diff --git a/.gitignore b/.gitignore index 754ce626..04cf357c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,6 @@ local.properties /gradledemo/gradletest/.settings/ /gradledemo/gradletest/.classpath /gradledemo/gradletest/.project -/release \ No newline at end of file +/release +.idea +cmake-build-debug/ diff --git a/.idea/checkstyle-idea.xml b/.idea/checkstyle-idea.xml deleted file mode 100644 index 418d9895..00000000 --- a/.idea/checkstyle-idea.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 7643783a..00000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123c..00000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 1aa5a278..00000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 8dbcc030..00000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index f49f8f92..00000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index 39fb9a67..00000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index d37f5bc9..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7f..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/FlutterHelper/common_utils/.gitignore b/FlutterHelper/common_utils/.gitignore new file mode 100644 index 00000000..e5e70b96 --- /dev/null +++ b/FlutterHelper/common_utils/.gitignore @@ -0,0 +1,18 @@ +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +.pub/ +build/ +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +*/.idea/ +.idea/ +/.idea/workspace.xml +/.idea/libraries \ No newline at end of file diff --git a/FlutterHelper/common_utils/CHANGELOG.md b/FlutterHelper/common_utils/CHANGELOG.md new file mode 100644 index 00000000..6265b8aa --- /dev/null +++ b/FlutterHelper/common_utils/CHANGELOG.md @@ -0,0 +1,74 @@ +## 2.0.2 + +* TODO: fix TimerUtil. + +## 2.0.1 + +* TODO: fix analysis. + +## 2.0.0 + +* TODO: Migrate to null-safety. + +## 1.2.4 + +* TODO: fix regex mobileExact. + +## 1.2.3 + +* TODO: fix analysis. + +## 1.2.2 + +* TODO: RegexUtil add regexPassport, fix TimelineInfo bugs and some updates. + +## 1.2.1 + +* TODO: fix DataFormats -> DateFormats, fix TimelineInfo bugs. + +## 1.2.0 + +* TODO: add JsonUtil, EncryptUtil, Some updates. + +## 1.1.3 + +* TODO: TextUtil, EnDecodeUtil, Some updates. +## 1.1.1 + +* TODO: Some updates. + +## 1.0.9 + +* TODO: NumUtil updates(add subtract multiply divide without loosing precision). MoneyUtil precise conversion. + +## 1.0.8 + +* TODO: Some updates. + +## 1.0.4 + +* TODO: Newly TimelineUtil.DateUtil update.No platform restriction found in primary library. + +## 1.0.3 + +* TODO: Newly added TimerUtil, MoneyUtil, LogUtil,Some updates. + +## 1.0.2 + +* TODO: fix bug. + +## 1.0.1 + +* TODO: Newly added NumUtil,Some updates. + +## 1.0.0 + +* TODO: Newly added DateUtil. + +## 0.0.2 + +* TODO: Contains ScreenUtil, WidgetUtil, ObjectUtil, RegexUtil. + +## 0.0.1 + +* TODO: CommonUtils initial release. \ No newline at end of file diff --git a/FlutterHelper/common_utils/CHANGE_LOG.md b/FlutterHelper/common_utils/CHANGE_LOG.md new file mode 100644 index 00000000..922c38c8 --- /dev/null +++ b/FlutterHelper/common_utils/CHANGE_LOG.md @@ -0,0 +1,175 @@ +## 更新说明 +#### v1.2.1 (2020.05.29) +1、fix DataFormats -> DateFormats。 +2、fix TimelineInfo bugs。 + +#### v1.2.0 (2020.05.23) +1、新增JsonUtil。 +2、新增EncryptUtil 简单加解密。 +3、LogUtil 更新。 +```yaml +String objStr = "{\"name\":\"成都市\"}"; +City hisCity = JsonUtil.getObj(objStr, (v) => City.fromJson(v)); +String listStr = "[{\"name\":\"成都市\"}, {\"name\":\"北京市\"}]"; +List cityList = JsonUtil.getObjList(listStr, (v) => City.fromJson(v)); + +const String key = '11, 22, 33, 44, 55, 66'; +String userName = 'Sky24n'; +String encode = EncryptUtil.xorBase64Encode(userName, key); // WH1YHgMs +String decode = EncryptUtil.xorBase64Decode(encode, key); // Sky24n + +//超长log查看 +common_utils e — — — — — — — — — — — — — — — — st — — — — — — — — — — — — — — — — +common_utils e | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45, +common_utils e | 7,988,989,990,991,992,993,994,995,996,997,998,999, +common_utils e — — — — — — — — — — — — — — — — ed — — — — — — — — — — — — — — — — +``` +#### v1.1.3 (2019.07.10) 1、新增TextUtil 银行卡号每隔4位加空格,每隔3三位加逗号,隐藏手机号等等. +2、新增EnDecodeUtil md5加密,Base64加/解密. +3、DateUtil 新增日期格式化,支持自定义格式输出。 +4、LogUtil 支持输出超长log。 +5、RegexUtil 支持199号段。 +```dart +/// DateUtil +DateUtil.formatDateMs(DateTime.now().millisecondsSinceEpoch, format: DataFormats.full); // 2019-07-09 16:51:14 +DateUtil.formatDateStr("2019-07-09 16:51:14", format: "yyyy/M/d HH:mm:ss"); // 2019/7/9 16:51:14 +DateUtil.formatDate(DateTime.now(), format: "yyyy/MM/dd HH:mm:ss"); // 2019/07/09 16:51:14 + +/// TextUtil +String phoneNo = TextUtil.formatSpace4("15845678910"); // 1584 5678 910 +String num = TextUtil.formatComma3("12345678"); // 12,345,678 +String phoneNo = TextUtil.hideNumber("15845678910"); // 158****8910 + +``` +```dart +/// DateUtil +DateUtil.formatDateMs(DateTime.now().millisecondsSinceEpoch, format: DataFormats.full); // 2019-07-09 16:51:14 +DateUtil.formatDateStr("2019-07-09 16:51:14", format: "yyyy/M/d HH:mm:ss"); // 2019/7/9 16:51:14 +DateUtil.formatDate(DateTime.now(), format: "yyyy/MM/dd HH:mm:ss"); // 2019/07/09 16:51:14 + +/// TextUtil +String phoneNo = TextUtil.formatSpace4("15845678910"); // 1584 5678 910 +String num = TextUtil.formatComma3("1234"); // 123,4 +String phoneNo = TextUtil.hidePhone("15845678910")// 158****8910 + +``` +(2018.10.31) +NumUtil更新, 精确加、减、乘、除, 防止精度丢失. +MoneyUtil更新, 精确转换, 防止精度丢失. + +common_utils库不再有平台限制. +WidgetUtil,ScreenUtil迁移至[flustars][flustars_github]库。 + + +## Flutter工具类库[flustars][flustars_github]更新说明 +#### v0.1.8(2018.12.29) +ScreenUtil 屏幕适配更新。 +方案一、不依赖context +``` +步骤 1 +//如果设计稿尺寸默认配置一致,无需该设置。 配置设计稿尺寸 默认 360.0 / 640.0 / 3.0 +setDesignWHD(_designW,_designH,_designD); + +步骤 2 +// 在MainPageState build 调用MediaQuery.of(context) +class MainPageState extends State { + @override + Widget build(BuildContext context) { + + // 在 MainPageState build 调用 MediaQuery.of(context) + MediaQuery.of(context); + + double width = ScreenUtil.getInstance().screenWidth; + double height = ScreenUtil.getInstance().screenHeight; + return new Scaffold( + appBar: new AppBar(), + ); + } +} + +步骤 3 +ScreenUtil.getInstance().screenWidth +ScreenUtil.getInstance().screenHeight +ScreenUtil.getInstance().screenDensity +ScreenUtil.getInstance().statusBarHeight +ScreenUtil.getInstance().bottomBarHeight +//屏幕适配相关 +ScreenUtil.getInstance().getWidth(size); //返回根据屏幕宽适配后尺寸(单位 dp or pt) +ScreenUtil.getInstance().getHeight(size); //返回根据屏幕高适配后尺寸 (单位 dp or pt) +ScreenUtil.getInstance().getWidthPx(sizePx); //sizePx 单位px +ScreenUtil.getInstance().getHeightPx(sizePx); //sizePx 单位px +ScreenUtil.getInstance().getSp(fontSize); //返回根据屏幕宽适配后字体尺寸 + +``` +方案二、依赖context +``` +//如果设计稿尺寸默认配置一致,无需该设置。 配置设计稿尺寸 默认 360.0 / 640.0 / 3.0 +setDesignWHD(_designW,_designH,_designD); + +ScreenUtil.getScreenW(context); //屏幕 宽 +ScreenUtil.getScreenH(context); //屏幕 高 +ScreenUtil.getScreenDensity(context); //屏幕 像素密度 +ScreenUtil.getStatusBarH(context); //状态栏高度 +ScreenUtil.getBottomBarH(context); //bottombar 高度 +//屏幕适配相关 +ScreenUtil.getScaleW(context, size); //返回根据屏幕宽适配后尺寸(单位 dp or pt) +ScreenUtil.getScaleH(context, size); //返回根据屏幕高适配后尺寸 (单位 dp or pt) +ScreenUtil.getScaleSp(context, size) ;//返回根据屏幕宽适配后字体尺寸 +``` +#### v0.1.6(2018.12.20) +新增网络请求工具DioUtil, 单例模式,可输出请求日志。详细请求+解析请参考[flutter_wanandroid][flutter_wanandroid_github]项目。 +``` +// 打开debug模式. +DioUtil.openDebug(); + +// 配置网络参数. +Options options = DioUtil.getDefOptions(); +options.baseUrl = "http://www.wanandroid.com/"; +HttpConfig config = new HttpConfig(options: options); +DioUtil().setConfig(config); + +// 两种单例请求方式. +DioUtil().request(Method.get, "banner/json"); +DioUtil.getInstance().request(Method.get, "banner/json"); + +//示例 +LoginReq req = new LoginReq('username', 'password'); +DioUtil().request(Method.post, "user/login",data: req.toJson()); + +//示例 +FormData formData = new FormData.from({ + "username": "username", + "password": "password", + }); +DioUtil().requestR(Method.post, "user/login",data: rformData); + +// 网络请求日志 +I/flutter ( 5922): ----------------Http Log---------------- +I/flutter ( 5922): [statusCode]: 200 +I/flutter ( 5922): [request ]: method: GET baseUrl: http://www.wanandroid.com/ path: lg/collect/list/0/json +I/flutter ( 5922): [reqdata ]: null +I/flutter ( 5922): [response ]: {data: {curPage: 1, datas: [], offset: 0, over: true, pageCount: 0, size: 20, total: 0}, errorCode: 0, errorMsg: } +``` + +#### v0.1.5(2018.12.14) +ScreenUtil 新增屏幕适配,不依赖context。 +``` +//如果设计稿尺寸默认配置一致,无需该设置。 配置设计稿尺寸 默认 360.0 / 640.0 / 3.0 +setDesignWHD(_designW,_designH,_designD); + +//返回根据屏幕宽适配后尺寸(单位 dp or pt) +ScreenUtil.getInstance().getWidth(100.0); + +//返回根据屏幕高适配后尺寸(单位 dp or pt) +ScreenUtil.getInstance().getHeight(100.0); + +//返回根据屏幕宽适配后字体尺寸 +ScreenUtil.getInstance().getSp(12.0); +``` + + + + +[flutter_wanandroid_github]: https://github.com/Sky24n/flutter_wanandroid +[common_utils_github]: https://github.com/Sky24n/common_utils +[flustars_github]: https://github.com/Sky24n/flustars \ No newline at end of file diff --git a/FlutterHelper/common_utils/LICENSE b/FlutterHelper/common_utils/LICENSE new file mode 100644 index 00000000..99a3972b --- /dev/null +++ b/FlutterHelper/common_utils/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2018, Sky24n +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/FlutterHelper/common_utils/README-EN.md b/FlutterHelper/common_utils/README-EN.md new file mode 100644 index 00000000..5fec7af1 --- /dev/null +++ b/FlutterHelper/common_utils/README-EN.md @@ -0,0 +1,308 @@ +Language: English | [中文简体](https://github.com/Sky24n/common_utils) + +[![Pub](https://img.shields.io/pub/v/common_utils.svg?style=flat-square&color=009688)](https://pub.dartlang.org/packages/common_utils)      [![Pub](https://img.shields.io/pub/v/common_utils.svg?style=flat-square&color=2196F3)](https://pub.flutter-io.cn/packages/common_utils) + +## common_utils is a Dart common utils library. + +1、Dart project dependencies. +```yaml +dependencies: + common_utils: ^2.0.2 +``` +2、Dart project dependencies, [flustars][flustars_github] is a Flutter common utils library. More SpUtil, ScreenUtil, DirectoryUtil. +```yaml +dependencies: + flustars: ^2.0.1 +``` + +Dart utils Library [common_utils][common_utils_github] +1. TimelineUtil : timeline util. +2. TimerUtil : countdown,timer. +3. MoneyUtil : fen to yuan, format output. +4. LogUtil : simply encapsulate print logs. +5. DateUtil : date conversion formatted output. +6. RegexUtil : regular verification of mobile phone numbers, ID cards, mailboxes and so on. +7. NumUtil : keep [x] decimal places, add subtract multiply divide without loosing precision. +8. ObjectUtil : object is empty, two List is equal. +9. EncryptUtil : xor, md5 ,Base64.. +10. TextUtil : hide phoneNo. +11. JsonUtil : json to object. + +Flutter utils Library [flustars][flustars_github] +1. SpUtil : SharedPreferences Util. +2. ScreenUtil : get screen width height density, appBarHeight, statusBarHeight, orientation. +3. WidgetUtil : get Widget width height,coordinates. +4. ImageUtil : get image size. +5. DirectoryUtil : Directory Util. +6. DioUtil : Dio Util(move to[DioUtil](https://github.com/Sky24n/FlutterRepos/blob/master/base_library/lib/src/data/net/dio_util.dart))。 + +### APIs +* SpUtil +SharedPreferences util. +```dart +/// await sp initialized。 +await SpUtil.getInstance(); + +/// support default value. +String name = SpUtil.putString("key_username", "Sky24n"); +bool isShow = SpUtil.getBool("key_show", defValue: true); + +/// save object example. +City city = new City(); +city.name = "成都市"; +SpUtil.putObject("loc_city", city); + +City hisCity = SpUtil.getObj("loc_city", (v) => City.fromJson(v)); +print("City: " + (hisCity == null ? "null" : hisCit.toString())); + + +/// save object list example. +List list = new List(); +list.add(new City(name: "成都市")); +list.add(new City(name: "北京市")); +SpUtil.putObjectList("loc_city_list", list); + +List _cityList = SpUtil.getObjList("loc_city_list", (v) => City.fromJson(v)); +print("City list: " + (_cityList == null ? "null" : _cityList.toString())); +``` + +* DateUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/date_page.dart) +``` +/// common format。example:"yyyy/MM/dd HH:mm:ss","yyyy/M/d HH:mm:ss"。 +/// year -> yyyy/yy month -> MM/M day -> dd/d +/// hour -> HH/H minute -> mm/m second -> ss/s +class DataFormats { + static String full = "yyyy-MM-dd HH:mm:ss"; + static String y_mo_d_h_m = "yyyy-MM-dd HH:mm"; + static String y_mo_d = "yyyy-MM-dd"; + static String y_mo = "yyyy-MM"; + static String mo_d = "MM-dd"; + static String mo_d_h_m = "MM-dd HH:mm"; + static String h_m_s = "HH:mm:ss"; + static String h_m = "HH:mm"; + + static String zh_full = "yyyy年MM月dd日 HH时mm分ss秒"; + static String zh_y_mo_d_h_m = "yyyy年MM月dd日 HH时mm分"; + static String zh_y_mo_d = "yyyy年MM月dd日"; + static String zh_y_mo = "yyyy年MM月"; + static String zh_mo_d = "MM月dd日"; + static String zh_mo_d_h_m = "MM月dd日 HH时mm分"; + static String zh_h_m_s = "HH时mm分ss秒"; + static String zh_h_m = "HH时mm分"; +} + +getDateTimeByMs : +getDateMsByTimeStr : +getNowDateMs : get Now Date milliseconds. +getNowDateStr : get Now DateStr.(yyyy-MM-dd HH:mm:ss) +formatDate : format Date by DateTime. +formatDateStr : format Date by DateStr. +formatDateMs : format Date by milliseconds. +getWeekday : get weekDay. +getDayOfYear : get day of year. +isToday : is today. +isYesterday : is yesterday. +isWeek : is week. +yearIsEqual : whether it is leap year. +isLeapYear : year is equal. + +// example +DateUtil.formatDateMs(dateMs, format: DateFormats.full); //2019-07-09 16:16:16 +DateUtil.formatDateStr('2019-07-09 16:16:16', format: "yyyy/M/d HH:mm:ss"); //2019/7/9 16:16:16 +DateUtil.formatDate(DateTime.now(), format: DateFormats.zh_full); //2019年07月09日 16时16分16秒 +``` + +* EncryptUtil +``` +encodeMd5 : md5. +encodeBase64 : Base64 encode. +decodeBase64() : Base64 decode. +xorCode() : xor. +xorBase64Encode() : xor Base64 encode. +xorBase64Decode() : xor Base64 decode. + +const String key = '11, 22, 33, 44, 55, 66'; +String userName = 'Sky24n'; +String encode = EncryptUtil.xorBase64Encode(userName, key); // WH1YHgMs +String decode = EncryptUtil.xorBase64Decode(encode, key); // Sky24n +``` + +* JsonUtil +``` +encodeObj : Obj to json string. +getObj : json string to object. +getObject : json string / map to object. +getObjList : json string list to object list. +getObjectList : json string / map list to object list. + +String objStr = "{\"name\":\"成都市\"}"; +City hisCity = JsonUtil.getObj(objStr, (v) => City.fromJson(v)); +String listStr = "[{\"name\":\"成都市\"}, {\"name\":\"北京市\"}]"; +List cityList = JsonUtil.getObjList(listStr, (v) => City.fromJson(v)); +``` + +* LogUtil +``` +init(tag, isDebug, maxLen) : tag, isDebug, maxLen. +e(object, tag) : Log e. +v(object, tag) : Log v,debug output. + +//超长log查看 +common_utils e — — — — — — — — — — — — — — — — st — — — — — — — — — — — — — — — — +common_utils e | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45, +common_utils e | 7,988,989,990,991,992,993,994,995,996,997,998,999, +common_utils e — — — — — — — — — — — — — — — — ed — — — — — — — — — — — — — — — — +``` + +* MoneyUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/money_page.dart) +``` +changeF2Y : fen to yuan, format output. +changeFStr2YWithUnit : fen str to yuan, format & unit output. +changeF2YWithUnit : fen to yuan, format & unit output. +changeYWithUnit : yuan, format & unit output.(yuan is int,double,str). +changeY2F : fen to yuan. +``` + +* NumUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/num_util_page.dart) +``` +getIntByValueStr : get int By value string. +getDoubleByValueStr : get double By value string. +getNumByValueStr : Keep [x] decimal places by value string. +getNumByValueDouble : Keep [x] decimal places by double. +isZero : is Zero. +add : add (without loosing precision). +subtract : subtract (without loosing precision). +multiply : multiply (without loosing precision). +divide : divide (without loosing precision). +remainder : 余. +lessThan : < . +thanOrEqual : <= . +greaterThan : > . +greaterOrEqual : >= . +``` + +* ObjectUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/object_util_page.dart) +``` +isEmptyString : String is empty. +isEmptyList : List is empty. +isEmptyMap : Map Map empty. +isEmpty : Object is empty.(String List Map). +isNotEmpty : Object is not empty.(String List Map). +twoListIsEqual : Two List Is Equal. +``` + +* RegexUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/regex_page.dart) +``` +isMobileSimple : +isMobileExact : +isTel : +isIDCard : +isIDCard15 : +isIDCard18 : +isIDCard18Exact : +isEmail : +isURL : +isZh : +isDate : +isIP : +isUserName : +isQQ : +``` + +* TextUtil +``` +isEmpty : isEmpty. +formatSpace4 : format Space 4. +formatComma3 : format Comma 3. +formatDoubleComma3 : format Double Comma3. +hideNumber : hide number. +replace : replace. +split : split. +reverse : reverse. + +/// example +String phoneNo = TextUtil.formatSpace4("15845678910"); // 1584 5678 910 +String num = TextUtil.formatComma3("1234"); // 123,4 +String phoneNo = TextUtil.hideNumber("15845678910")// 158****8910 +``` + +* TimelineUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/timeline_page.dart) +``` +///(xx)Configurable output. +enum DayFormat { + ///(less than 30s->just now)、x minutes、x hours、(Yesterday)、x days. + Simple, + ///(less than 30s->just now)、x minutes、x hours、[This year:(Yesterday/a day ago)、(two days age)、MM-dd ]、[past years: yyyy-MM-dd] + Common, + ///(less than 30s->just now)、x minutes、x hours、[This year:(Yesterday HH:mm/a day ago)、(two days age)、MM-dd HH:mm]、[past years: yyyy-MM-dd HH:mm] + Full, +} +///Timeline information configuration. +abstract class TimelineInfo { + String suffixAgo(); //suffix ago(后缀 后). + String suffixAfter(); //suffix after(后缀 前). + int maxJustNowSecond() => 30; // max just now second. + String lessThanOneMinute() => ''; //just now(刚刚). + String customYesterday() => ''; //Yesterday(昨天).优先级高于keepOneDay + bool keepOneDay(); //保持1天,example: true -> 1天前, false -> MM-dd. + bool keepTwoDays(); //保持2天,example: true -> 2天前, false -> MM-dd. + String oneMinute(int minutes); //a minute(1分钟). + String minutes(int minutes); //x minutes(x分钟). + String anHour(int hours); //an hour(1小时). + String hours(int hours); //x hours(x小时). + String oneDay(int days); //a day(1天). + String days(int days); //x days(x天). +} +setLocaleInfo : add custom configuration. +formatByDateTime : timeline format output by DateTime . +format : timeline format output. +formatA : timeline format output. like QQ. + +``` + +* TimerUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/timer_page.dart) +``` +setInterval : set Timer interval. +setTotalTime : set countdown totalTime. +startTimer() : start Timer. +startCountDown : start countdown Timer. +updateTotalTime : update countdown totalTime. +cancel : cancels the timer. +setOnTimerTickCallback : set timer callback. +isActive : timer is Active. +``` + +### [Flutter Demos](https://github.com/Sky24n/flutter_wanandroid/tree/master/lib/demos) + +>- |--demos +> - |-- city_select_page.dart +> - |-- date_page.dart +> - |-- image_size_page.dart +> - |-- money_page.dart +> - |-- pinyin_page.dart +> - |-- regex_page.dart +> - |-- round_portrait_page.dart +> - |-- timeline_page.dart +> - |-- timer_page.dart +> - |-- widget_page.dart + +### Demo Apk : [flutter_wanandroid](https://github.com/Sky24n/Doc) + +### Thanks +Blankj [AndroidUtilCode](https://github.com/Blankj/AndroidUtilCode)。 +Andres Araujo [timeago](https://github.com/andresaraujo/timeago.dart)。 +a14n [decimal](https://github.com/a14n/dart-decimal)。 + +### Apps +[flutter_wanandroid](https://github.com/Sky24n/flutter_wanandroid) +[Moss App](https://github.com/Sky24n/Moss) + +### [Change Log](CHANGELOG.md) +v1.2.1 (2020.05.29) +1、fix DataFormats -> DateFormats。 +2、fix TimelineInfo bugs。 + + + +[flustars_github]: https://github.com/Sky24n/flustars +[common_utils_github]: https://github.com/Sky24n/common_utils \ No newline at end of file diff --git a/FlutterHelper/common_utils/README.md b/FlutterHelper/common_utils/README.md new file mode 100644 index 00000000..c960dbc7 --- /dev/null +++ b/FlutterHelper/common_utils/README.md @@ -0,0 +1,319 @@ +Language: [English](README-EN.md) | 中文简体 + +[![Pub](https://img.shields.io/pub/v/common_utils.svg?style=flat-square&color=009688)](https://pub.dartlang.org/packages/common_utils)      [![Pub](https://img.shields.io/pub/v/common_utils.svg?style=flat-square&color=2196F3)](https://pub.flutter-io.cn/packages/common_utils) + +Dart常用工具类库。包含日期,正则,倒计时,时间轴等工具类。如果你有好的工具类欢迎PR. + +1、如果您是纯Dart项目,可以直接引用本库。 +```yaml +dependencies: + common_utils: ^2.0.2 +``` +2、如果您是Flutter项目,请使用Flutter常用工具类库 [flustars][flustars_github],该库依赖于本项目。[flustars][flustars_github]库为大家提供更多的工具类,例如SpUtil,ScreenUtil, DirectoryUtil等等。 +```yaml +dependencies: + flustars: ^2.0.1 +``` + +Dart常用工具类库 [common_utils][common_utils_github] +1. TimelineUtil : 时间轴. +2. TimerUtil : 倒计时,定时任务. +3. MoneyUtil : 精确转换,元转分,分转元,支持格式输出. +4. LogUtil : 简单封装打印日志. +5. DateUtil : 日期转换格式化输出. +6. RegexUtil : 正则验证手机号,身份证,邮箱等等. +7. NumUtil : 保留x位小数, 精确加、减、乘、除, 防止精度丢失. +8. ObjectUtil : 判断对象是否为空(String List Map),判断两个List是否相等. +9. EncryptUtil : 异或对称加/解密,md5加密,Base64加/解密. +10. TextUtil : 银行卡号每隔4位加空格,每隔3三位加逗号,隐藏手机号等等. +11. JsonUtil : 简单封装json字符串转对象. + +Flutter常用工具类库 [flustars][flustars_github] +1. SpUtil : 单例"同步"SharedPreferences工具类。支持get传入默认值,支持存储对象,支持存储对象数组。 +2. ScreenUtil : 屏幕适配,获取屏幕宽、高、密度,AppBar高,状态栏高度,屏幕方向. +3. WidgetUtil : 监听Widget渲染状态,获取Widget宽高,在屏幕上的坐标,获取网络/本地图片尺寸. +4. ImageUtil : 获取网络/本地图片尺寸. +5. DirectoryUtil : 文件目录工具类. +6. DioUtil : 单例Dio网络工具类(已迁移至此处[DioUtil](https://github.com/Sky24n/FlutterRepos/blob/master/base_library/lib/src/data/net/dio_util.dart))。 + + +### APIs +* SpUtil +强大易用的SharedPreferences工具类,详细使用请参考原仓库[flustars][flustars_github]。 +```dart +/// 等待Sp初始化完成。 +await SpUtil.getInstance(); + +/// 同步使用Sp。支付默认值。 +String name = SpUtil.putString("key_username", "Sky24n"); +bool isShow = SpUtil.getBool("key_show", defValue: true); + +/// 存储实体对象示例。 +City city = new City(); +city.name = "成都市"; +SpUtil.putObject("loc_city", city); + +City hisCity = SpUtil.getObj("loc_city", (v) => City.fromJson(v)); +print("City: " + (hisCity == null ? "null" : hisCit.toString())); + +/// 存储实体对象list示例。 +List list = new List(); +list.add(new City(name: "成都市")); +list.add(new City(name: "北京市")); +SpUtil.putObjectList("loc_city_list", list); + +List _cityList = SpUtil.getObjList("loc_city_list", (v) => City.fromJson(v)); +print("City list: " + (_cityList == null ? "null" : _cityList.toString())); +``` + +* DateUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/date_page.dart) +``` +/// 一些常用格式参照。可以自定义格式,例如:"yyyy/MM/dd HH:mm:ss","yyyy/M/d HH:mm:ss"。 +/// 格式要求 +/// year -> yyyy/yy month -> MM/M day -> dd/d +/// hour -> HH/H minute -> mm/m second -> ss/s +class DataFormats { + static String full = "yyyy-MM-dd HH:mm:ss"; + static String y_mo_d_h_m = "yyyy-MM-dd HH:mm"; + static String y_mo_d = "yyyy-MM-dd"; + static String y_mo = "yyyy-MM"; + static String mo_d = "MM-dd"; + static String mo_d_h_m = "MM-dd HH:mm"; + static String h_m_s = "HH:mm:ss"; + static String h_m = "HH:mm"; + + static String zh_full = "yyyy年MM月dd日 HH时mm分ss秒"; + static String zh_y_mo_d_h_m = "yyyy年MM月dd日 HH时mm分"; + static String zh_y_mo_d = "yyyy年MM月dd日"; + static String zh_y_mo = "yyyy年MM月"; + static String zh_mo_d = "MM月dd日"; + static String zh_mo_d_h_m = "MM月dd日 HH时mm分"; + static String zh_h_m_s = "HH时mm分ss秒"; + static String zh_h_m = "HH时mm分"; +} + +getDateTimeByMs : . +getDateMsByTimeStr : . +getNowDateMs : 获取现在 毫秒. +getNowDateStr : 获取现在 日期字符串.(yyyy-MM-dd HH:mm:ss) +formatDate : 格式化日期 DateTime. +formatDateStr : 格式化日期 字符串. +formatDateMs : 格式化日期 毫秒. +getWeekday : 获取星期几. +getDayOfYear : 在今年的第几天. +isToday : 是否是今天. +isYesterday : 是否是昨天. +isWeek : 是否是本周. +yearIsEqual : 是否同年. +isLeapYear : 是否是闰年. + +// example +DateUtil.formatDateMs(dateMs, format: DateFormats.full); //2019-07-09 16:16:16 +DateUtil.formatDateStr('2019-07-09 16:16:16', format: "yyyy/M/d HH:mm:ss"); //2019/7/9 16:16:16 +DateUtil.formatDate(DateTime.now(), format: DateFormats.zh_full); //2019年07月09日 16时16分16秒 +``` + +* EncryptUtil +``` +encodeMd5 : md5 加密. +encodeBase64 : Base64加密. +decodeBase64() : Base64解密. +xorCode() : 异或对称加密. +xorBase64Encode() : 异或对称 Base64 加密. +xorBase64Decode() : 异或对称 Base64 解密. + +const String key = '11, 22, 33, 44, 55, 66'; +String userName = 'Sky24n'; +String encode = EncryptUtil.xorBase64Encode(userName, key); // WH1YHgMs +String decode = EncryptUtil.xorBase64Decode(encode, key); // Sky24n +``` + +* JsonUtil +``` +encodeObj : object to json string. +getObj : json string to object. +getObject : json string / map to object. +getObjList : json string list to object list. +getObjectList : json string / map list to object list. + +String objStr = "{\"name\":\"成都市\"}"; +City hisCity = JsonUtil.getObj(objStr, (v) => City.fromJson(v)); +String listStr = "[{\"name\":\"成都市\"}, {\"name\":\"北京市\"}]"; +List cityList = JsonUtil.getObjList(listStr, (v) => City.fromJson(v)); +``` + +* LogUtil +``` +init(tag, isDebug, maxLen) : tag 标签, isDebug: 模式, maxLen 每行最大长度. +e(object, tag) : 日志e +v(object, tag) : 日志v,只在debug模式输出. + +//超长log查看 +common_utils e — — — — — — — — — — — — — — — — st — — — — — — — — — — — — — — — — +common_utils e | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45, +common_utils e | 7,988,989,990,991,992,993,994,995,996,997,998,999, +common_utils e — — — — — — — — — — — — — — — — ed — — — — — — — — — — — — — — — — +``` + +* MoneyUtil 精确转换,防止精度丢失 -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/money_page.dart) +``` +changeF2Y : 分 转 元, format格式输出. +changeFStr2YWithUnit : 分字符串 转 元, format 与 unit 格式 输出. +changeF2YWithUnit : 分 转 元, format 与 unit 格式 输出. +changeYWithUnit : 元, format 与 unit 格式 输出. +changeY2F : 元 转 分. +``` + +* NumUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/num_util_page.dart) +``` +getIntByValueStr : 数字字符串转int. +getDoubleByValueStr : 数字字符串转double. +getNumByValueStr : 保留x位小数 by 数字字符串. +getNumByValueDouble : 保留x位小数 by double. +isZero : 是否为0. +add : 加(精确相加,防止精度丢失). +subtract : 减(精确相减,防止精度丢失). +multiply : 乘(精确相乘,防止精度丢失). +divide : 除(精确相除,防止精度丢失). +remainder : 余. +lessThan : < . +thanOrEqual : <= . +greaterThan : > . +greaterOrEqual : >= . +``` + +* ObjectUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/object_util_page.dart) +``` +isEmptyString : 判断String是否为空. +isEmptyList : 判断List是否为空. +isEmptyMap : 判断Map是否为空. +isEmpty : 判断对象是否为空.(String List Map). +isNotEmpty : 判断对象是否非空.(String List Map). +twoListIsEqual : 判断两个List是否相等. +``` + +* RegexUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/regex_page.dart) +``` +isMobileSimple : 简单验证手机号 +isMobileExact : 精确验证手机号 +isTel : 验证电话号码 +isIDCard : 验证身份证号码 +isIDCard15 : 验证身份证号码 15 位 +isIDCard18 : 简单验证身份证号码 18 位 +isIDCard18Exact : 精确验证身份证号码 18 位 +isEmail : 验证邮箱 +isURL : 验证 URL +isZh : 验证汉字 +isDate : 验证 yyyy-MM-dd 格式的日期校验,已考虑平闰年 +isIP : 验证 IP 地址 +isUserName : 验证用户名 +isQQ : 验证 QQ +``` + +* TextUtil +``` +isEmpty : isEmpty. +formatSpace4 : 每隔4位加空格,格式化银行卡. +formatComma3 : 每隔3三位加逗号. +formatDoubleComma3 : 每隔3三位加逗号. +hideNumber : 隐藏号码. +replace : replace. +split : split. +reverse : reverse. + +/// example +String phoneNo = TextUtil.formatSpace4("15845678910"); // 1584 5678 910 +String num = TextUtil.formatComma3("1234"); // 123,4 +String phoneNo = TextUtil.hideNumber("15845678910")// 158****8910 +``` + +* TimelineUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/timeline_page.dart) +``` +///(xx)为可配置输出 +enum DayFormat { + ///(小于30s->刚刚)、x分钟、x小时、(昨天)、x天. + Simple, + ///(小于30s->刚刚)、x分钟、x小时、[今年: (昨天/1天前)、(2天前)、MM-dd],[往年: yyyy-MM-dd]. + Common, + ///小于30s->刚刚)、x分钟、x小时、[今年: (昨天 HH:mm/1天前)、(2天前)、MM-dd HH:mm],[往年: yyyy-MM-dd HH:mm]. + Full, +} +///Timeline信息配置. +abstract class TimelineInfo { + String suffixAgo(); //suffix ago(后缀 后). + String suffixAfter(); //suffix after(后缀 前). + int maxJustNowSecond() => 30; // max just now second. + String lessThanOneMinute() => ''; //just now(刚刚). + String customYesterday() => ''; //Yesterday(昨天).优先级高于keepOneDay + bool keepOneDay(); //保持1天,example: true -> 1天前, false -> MM-dd. + bool keepTwoDays(); //保持2天,example: true -> 2天前, false -> MM-dd. + String oneMinute(int minutes); //a minute(1分钟). + String minutes(int minutes); //x minutes(x分钟). + String anHour(int hours); //an hour(1小时). + String hours(int hours); //x hours(x小时). + String oneDay(int days); //a day(1天). + String days(int days); //x days(x天). +} +setLocaleInfo : 自定义设置配置信息. +formatByDateTime : 格式输出时间轴信息 by DateTime . +format : 格式输出时间轴信息. +formatA : 格式输出时间轴信息. like QQ. +``` + +* TimerUtil -> [Example](https://github.com/Sky24n/flutter_wanandroid/blob/master/lib/demos/timer_page.dart) +``` +setInterval : 设置Timer间隔. +setTotalTime : 设置倒计时总时间. +startTimer() : 启动定时Timer. +startCountDown : 启动倒计时Timer. +updateTotalTime : 重设倒计时总时间. +cancel : 取消计时器. +setOnTimerTickCallback : 计时器回调. +isActive : Timer是否启动. +``` + +### [Flutter Demos](https://github.com/Sky24n/flutter_wanandroid/tree/master/lib/demos) + +>- |--demos +> - |-- city_select_page.dart 城市列表(索引&悬停)示例 +> - |-- date_page.dart 日期格式化示例 +> - |-- image_size_page.dart 获取网络/本地图片尺寸示例 +> - |-- money_page.dart 金额(元转分/分转元)示例 +> - |-- pinyin_page.dart 汉字转拼音示例 +> - |-- regex_page.dart 正则工具类示例 +> - |-- round_portrait_page.dart 圆形圆角头像示例 +> - |-- timeline_page.dart 时间轴示例 +> - |-- timer_page.dart 倒计时/定时器示例 +> - |-- widget_page.dart 获取Widget尺寸/屏幕坐标示例 + +### Thanks +本库部分源码参考,正则,时间轴。 +Blankj [AndroidUtilCode](https://github.com/Blankj/AndroidUtilCode) 强大易用的安卓工具类库。 +Andres Araujo [timeago](https://github.com/andresaraujo/timeago.dart) Dart时间轴库。 +a14n [decimal](https://github.com/a14n/dart-decimal) 精确运算,避免精度丢失。 + +### 关于作者 +GitHub : [Sky24n](https://github.com/Sky24n) +掘金     : [Sky24n](https://juejin.im/user/5b9e8a92e51d453df0440422/posts) +简书     : [Sky24n](https://www.jianshu.com/u/cbf2ad25d33a) + +### Changelog +Please see the [Changelog](CHANGELOG.md) page to know what's recently changed. + +### Apps +[flutter_wanandroid](https://github.com/Sky24n/flutter_wanandroid) +[Moss](https://github.com/Sky24n/Moss). +A GitHub client app developed with Flutter, which supports Android iOS Web. +Web :[Flutter Web](https://sky24n.github.io/Sky24n/moss). + +|![](https://z3.ax1x.com/2021/04/26/gp1hm6.jpg)|![](https://z3.ax1x.com/2021/04/26/gp1Tte.jpg)|![](https://z3.ax1x.com/2021/04/26/gp17fH.jpg)| +|:---:|:---:|:---:| + + +[flutter_wanandroid_qr]: https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_wanandroid/qrcode.png + +[common_utils_github]: https://github.com/Sky24n/common_utils + +[flustars_github]: https://github.com/Sky24n/flustars + + diff --git a/FlutterHelper/common_utils/analysis_options.yaml b/FlutterHelper/common_utils/analysis_options.yaml new file mode 100644 index 00000000..fe29820c --- /dev/null +++ b/FlutterHelper/common_utils/analysis_options.yaml @@ -0,0 +1,21 @@ +# https://www.dartlang.org/guides/language/analysis-options +# Source of linter options: +# http://dart-lang.github.io/linter/lints/options/options.html +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false + errors: + todo: ignore + exclude: + - flutter/** + - lib/*.dart + +linter: + rules: + - camel_case_types + - hash_and_equals + - iterable_contains_unrelated_type + - list_remove_unrelated_type + - unrelated_type_equality_checks + - valid_regexps diff --git a/FlutterHelper/common_utils/example/lib/main.dart b/FlutterHelper/common_utils/example/lib/main.dart new file mode 100644 index 00000000..29ee0674 --- /dev/null +++ b/FlutterHelper/common_utils/example/lib/main.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:common_utils/common_utils.dart'; + +void main() { + LogUtil.e("---------------- DateUtil st ----------------"); + String dateStr = "2019-07-09 16:16:16"; + DateTime? dateTime = DateUtil.getDateTime(dateStr); + DateTime now = DateTime.now(); + int? dateMs = DateUtil.getDateMsByTimeStr(dateStr); + String nowStr1 = DateUtil.formatDateMs(dateMs!, format: DateFormats.full); + String nowStr2 = DateUtil.formatDateStr(dateStr, format: "yyyy/M/d HH:mm:ss"); + String nowStr3 = DateUtil.formatDate(dateTime, format: DateFormats.zh_full); + String nowStr4 = DateUtil.formatDate(dateTime, format: 'yyyy年M月d日 HH时mm分ss秒'); + LogUtil.e('nowStr1: $nowStr1'); //2020-05-15 16:58:47 + LogUtil.e('nowStr2: $nowStr2'); //2019/7/9 16:16:16 + LogUtil.e('nowStr3: $nowStr3'); //2019年07月09日 16时16分16秒 + LogUtil.e('nowStr4: $nowStr4'); //2019年7月9日 16时16分16秒 + DateTime week = DateTime(2020, 5, 6); + LogUtil.e('2020/5/6 : ${DateUtil.getWeekday(week, short: true)}'); + LogUtil.e('toady: ${DateUtil.getWeekdayByMs(now.millisecondsSinceEpoch)}'); + LogUtil.e("Today DayOfYear: " + DateUtil.getDayOfYear(now).toString()); + LogUtil.e("---------------- DateUtil en ----------------\n"); + + LogUtil.e("---------------- EncryptUtil st ----------------"); + const String key = '11, 22, 33, 44, 55, 66'; + String userName = 'Sky24n'; + String encode = EncryptUtil.xorBase64Encode(userName, key); // WH1YHgMs + String decode = EncryptUtil.xorBase64Decode(encode, key); // Sky24n + LogUtil.e('EncryptUtil -> encode: $encode, decode: $decode'); + LogUtil.e("---------------- EncryptUtil en ----------------\n"); + + LogUtil.e("---------------- JsonUtil st ----------------"); + String intListStr = "[1, 2, 3, 4, 5, 6]"; + List? intList = JsonUtil.getList(intListStr); + LogUtil.e("JsonUtil getList -> intList: $intList"); + String strListStr = "[\"tom\",\"tony\",\"jacky\"]"; + List? strList = JsonUtil.getList(strListStr); + LogUtil.e("JsonUtil getList -> strList: $strList"); + + String objStr = "{\"name\":\"成都市\"}"; + City? hisCity = + JsonUtil.getObj(objStr, (v) => City.fromJson(v as Map)); + String listStr = "[{\"name\":\"成都市\"}, {\"name\":\"北京市\"}]"; + List? cityList = JsonUtil.getObjList( + listStr, (v) => City.fromJson(v as Map)); + LogUtil.e( + 'JsonUtil -> hisCity: ${hisCity.toString()} ; cityList: ${cityList.toString()}'); + LogUtil.e("---------------- JsonUtil en ----------------\n"); + + LogUtil.e("---------------- LogUtil st ----------------"); + //LogUtil.init(isDebug: true, tag: "test", maxLen: 128); + LogUtil.init(isDebug: true); + StringBuffer sb = StringBuffer(); + for (int i = 1; i <= 160; i++) { + sb.write('$i,'); + } + LogUtil.e(sb.toString()); + + LogUtil.d(sb.toString()); + LogUtil.e("---------------- LogUtil en ----------------\n"); + + LogUtil.e("---------------- MoneyUtil st ----------------"); + String yuan = '1.66'; + LogUtil.e(MoneyUtil.changeFStr2YWithUnit("1160", + format: MoneyFormat.NORMAL, unit: MoneyUnit.YUAN_ZH) + + " " + + MoneyUtil.changeYWithUnit(yuan, MoneyUnit.YUAN_ZH)); + LogUtil.e("---------------- MoneyUtil en ----------------\n"); + + LogUtil.e("---------------- NumUtil st ----------------"); + //保留小数点后2位数 + String tempStr = "1.5561111"; + num? value = NumUtil.getNumByValueStr(tempStr, fractionDigits: 2); + LogUtil.e("getDoubleByStr: " + '$value'); //result=1.56 + double a = 59.89; + int b = 10000; + + double c = 70.59; + double d = 10.0; + + LogUtil.e("add a/b : " + + (a / b).toString() + + " add: " + + NumUtil.divide(a, b).toString()); // a+b : 0.30000000000000004 add: 0.3 + LogUtil.e("mul c*d : " + + (c * d).toString() + + " mul: " + + NumUtil.multiply(c, d).toString() + + " greaterThan: " + + NumUtil.greaterThan(a, b) + .toString()); //c*d : 705.9000000000001 mul: 705.9 greaterThan: false + LogUtil.e("---------------- NumUtil en ----------------\n"); + + LogUtil.e("---------------- ObjectUtil st ----------------"); + List listA = ["A", "B", "C"]; + List listB = ["A", "B", "C"]; + LogUtil.e("Two List Is Equal: " + + ObjectUtil.twoListIsEqual(listA, listB).toString()); + LogUtil.e("---------------- ObjectUtil en ----------------\n"); + + LogUtil.e("---------------- TextUtil st ----------------"); + String phoneNo = TextUtil.formatSpace4("15845678910"); + LogUtil.e(phoneNo); //1584 5678 910 + LogUtil.e("replace: " + TextUtil.replace(phoneNo, ' ', '')); + LogUtil.e("formatComma3: " + TextUtil.formatComma3(12345678)); //12,345,678 + LogUtil.e("reverse: " + TextUtil.reverse("12345678")); //87654321 + LogUtil.e("hideNumber: " + TextUtil.hideNumber("15845678910")); //158****8910 + LogUtil.e("---------------- TextUtil en ----------------\n"); + + LogUtil.e("---------------- TimelineUtil st ----------------"); + DateTime dateTime1 = DateTime(2020, 5, 20, 22, 30, 00); + DateTime locDateTime = DateTime(2020, 5, 20, 23, 30, 00); + LogUtil.e("Timeline: " + + TimelineUtil.formatByDateTime( + dateTime1, + locDateTime: locDateTime, + //locale: 'zh', + ).toString()); + LogUtil.e("Timeline: " + + TimelineUtil.formatByDateTime( + dateTime1, + //locDateTime: locDateTime, + ).toString()); + LogUtil.e("Timeline formatA: " + + TimelineUtil.formatA( + dateTime1.millisecondsSinceEpoch, + languageCode: 'zh', + short: true, + ).toString()); + LogUtil.e("---------------- TimelineUtil en ----------------\n"); + + LogUtil.e("---------------- TimerUtil st ----------------"); + TimerUtil? timerUtil; + //定时任务test + timerUtil = TimerUtil(mInterval: 1000, mTotalTime: 5 * 1000); + //timerUtil.setInterval(1000); + timerUtil.setOnTimerTickCallback((int value) { + LogUtil.e("TimerTick: " + value.toString()); + }); + timerUtil.startTimer(); + if (timerUtil != null) timerUtil.cancel(); //dispose() + + TimerUtil timerCountDown; + //倒计时test + timerCountDown = TimerUtil(mInterval: 1000, mTotalTime: 3 * 1000); +// timerCountDown.setInterval(1000); +// timerCountDown.setTotalTime(3 * 1000); + timerCountDown.setOnTimerTickCallback((int value) { + double tick = (value / 1000); + LogUtil.e("CountDown: " + tick.toInt().toString()); + }); + //timerCountDown.startCountDown(); + //if (timerCountDown != null) timerCountDown.cancel(); //dispose() + LogUtil.e("---------------- TimerUtil en ----------------\n"); + + LogUtil.e('Regex: ${RegexUtil.isPassport('EG6504900')}'); +} + +class City { + String name; + + City(this.name); + + City.fromJson(Map json) : name = json['name'] as String; + + Map toJson() { + Map map = Map(); + map['name'] = name; + return map; + } + + @override + String toString() { + return json.encode(this); + } +} diff --git a/FlutterHelper/common_utils/lib/common_utils.dart b/FlutterHelper/common_utils/lib/common_utils.dart new file mode 100644 index 00000000..6410ba50 --- /dev/null +++ b/FlutterHelper/common_utils/lib/common_utils.dart @@ -0,0 +1,13 @@ +library common_utils; + +export 'src/date_util.dart'; +export 'src/encrypt_util.dart'; +export 'src/json_util.dart'; +export 'src/log_util.dart'; +export 'src/money_util.dart'; +export 'src/num_util.dart'; +export 'src/object_util.dart'; +export 'src/regex_util.dart'; +export 'src/text_util.dart'; +export 'src/timeline_util.dart'; +export 'src/timer_util.dart'; diff --git a/FlutterHelper/common_utils/lib/src/date_util.dart b/FlutterHelper/common_utils/lib/src/date_util.dart new file mode 100644 index 00000000..c8ddb33a --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/date_util.dart @@ -0,0 +1,289 @@ +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Date Util. + * @Date: 2018/9/8 + */ + +/// 一些常用格式参照。可以自定义格式,例如:'yyyy/MM/dd HH:mm:ss','yyyy/M/d HH:mm:ss'。 +/// 格式要求 +/// year -> yyyy/yy month -> MM/M day -> dd/d +/// hour -> HH/H minute -> mm/m second -> ss/s +class DateFormats { + static String full = 'yyyy-MM-dd HH:mm:ss'; + static String y_mo_d_h_m = 'yyyy-MM-dd HH:mm'; + static String y_mo_d = 'yyyy-MM-dd'; + static String y_mo = 'yyyy-MM'; + static String mo_d = 'MM-dd'; + static String mo_d_h_m = 'MM-dd HH:mm'; + static String h_m_s = 'HH:mm:ss'; + static String h_m = 'HH:mm'; + + static String zh_full = 'yyyy年MM月dd日 HH时mm分ss秒'; + static String zh_y_mo_d_h_m = 'yyyy年MM月dd日 HH时mm分'; + static String zh_y_mo_d = 'yyyy年MM月dd日'; + static String zh_y_mo = 'yyyy年MM月'; + static String zh_mo_d = 'MM月dd日'; + static String zh_mo_d_h_m = 'MM月dd日 HH时mm分'; + static String zh_h_m_s = 'HH时mm分ss秒'; + static String zh_h_m = 'HH时mm分'; +} + +/// month->days. +Map MONTH_DAY = { + 1: 31, + 2: 28, + 3: 31, + 4: 30, + 5: 31, + 6: 30, + 7: 31, + 8: 31, + 9: 30, + 10: 31, + 11: 30, + 12: 31, +}; + +/// Date Util. +class DateUtil { + /// get DateTime By DateStr. + static DateTime? getDateTime(String dateStr, {bool? isUtc}) { + DateTime? dateTime = DateTime.tryParse(dateStr); + if (isUtc != null) { + if (isUtc) { + dateTime = dateTime?.toUtc(); + } else { + dateTime = dateTime?.toLocal(); + } + } + return dateTime; + } + + /// get DateTime By Milliseconds. + static DateTime getDateTimeByMs(int ms, {bool isUtc = false}) { + return DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc); + } + + /// get DateMilliseconds By DateStr. + static int? getDateMsByTimeStr(String dateStr, {bool? isUtc}) { + DateTime? dateTime = getDateTime(dateStr, isUtc: isUtc); + return dateTime?.millisecondsSinceEpoch; + } + + /// get Now Date Milliseconds. + static int getNowDateMs() { + return DateTime.now().millisecondsSinceEpoch; + } + + /// get Now Date Str.(yyyy-MM-dd HH:mm:ss) + static String getNowDateStr() { + return formatDate(DateTime.now()); + } + + /// format date by milliseconds. + /// milliseconds 日期毫秒 + static String formatDateMs(int ms, {bool isUtc = false, String? format}) { + return formatDate(getDateTimeByMs(ms, isUtc: isUtc), format: format); + } + + /// format date by date str. + /// dateStr 日期字符串 + static String formatDateStr(String dateStr, {bool? isUtc, String? format}) { + return formatDate(getDateTime(dateStr, isUtc: isUtc), format: format); + } + + /// format date by DateTime. + /// format 转换格式(已提供常用格式 DateFormats,可以自定义格式:'yyyy/MM/dd HH:mm:ss') + /// 格式要求 + /// year -> yyyy/yy month -> MM/M day -> dd/d + /// hour -> HH/H minute -> mm/m second -> ss/s + static String formatDate(DateTime? dateTime, {String? format}) { + if (dateTime == null) return ''; + format = format ?? DateFormats.full; + if (format.contains('yy')) { + String year = dateTime.year.toString(); + if (format.contains('yyyy')) { + format = format.replaceAll('yyyy', year); + } else { + format = format.replaceAll( + 'yy', year.substring(year.length - 2, year.length)); + } + } + + format = _comFormat(dateTime.month, format, 'M', 'MM'); + format = _comFormat(dateTime.day, format, 'd', 'dd'); + format = _comFormat(dateTime.hour, format, 'H', 'HH'); + format = _comFormat(dateTime.minute, format, 'm', 'mm'); + format = _comFormat(dateTime.second, format, 's', 'ss'); + format = _comFormat(dateTime.millisecond, format, 'S', 'SSS'); + + return format; + } + + /// com format. + static String _comFormat( + int value, String format, String single, String full) { + if (format.contains(single)) { + if (format.contains(full)) { + format = + format.replaceAll(full, value < 10 ? '0$value' : value.toString()); + } else { + format = format.replaceAll(single, value.toString()); + } + } + return format; + } + + /// get WeekDay. + /// dateTime + /// isUtc + /// languageCode zh or en + /// short + static String getWeekday(DateTime? dateTime, + {String languageCode = 'en', bool short = false}) { + if (dateTime == null) return ""; + String weekday = ""; + switch (dateTime.weekday) { + case 1: + weekday = languageCode == 'zh' ? '星期一' : 'Monday'; + break; + case 2: + weekday = languageCode == 'zh' ? '星期二' : 'Tuesday'; + break; + case 3: + weekday = languageCode == 'zh' ? '星期三' : 'Wednesday'; + break; + case 4: + weekday = languageCode == 'zh' ? '星期四' : 'Thursday'; + break; + case 5: + weekday = languageCode == 'zh' ? '星期五' : 'Friday'; + break; + case 6: + weekday = languageCode == 'zh' ? '星期六' : 'Saturday'; + break; + case 7: + weekday = languageCode == 'zh' ? '星期日' : 'Sunday'; + break; + default: + break; + } + return languageCode == 'zh' + ? (short ? weekday.replaceAll('星期', '周') : weekday) + : weekday.substring(0, short ? 3 : weekday.length); + } + + /// get WeekDay By Milliseconds. + static String getWeekdayByMs(int milliseconds, + {bool isUtc = false, String languageCode = 'en', bool short = false}) { + DateTime dateTime = getDateTimeByMs(milliseconds, isUtc: isUtc); + return getWeekday(dateTime, languageCode: languageCode, short: short); + } + + /// get day of year. + /// 在今年的第几天. + static int getDayOfYear(DateTime dateTime) { + int year = dateTime.year; + int month = dateTime.month; + int days = dateTime.day; + for (int i = 1; i < month; i++) { + days = days + MONTH_DAY[i]!; + } + if (isLeapYearByYear(year) && month > 2) { + days = days + 1; + } + return days; + } + + /// get day of year. + /// 在今年的第几天. + static int getDayOfYearByMs(int ms, {bool isUtc = false}) { + return getDayOfYear(DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc)); + } + + /// is today. + /// 是否是当天. + static bool isToday(int? milliseconds, {bool isUtc = false, int? locMs}) { + if (milliseconds == null || milliseconds == 0) return false; + DateTime old = + DateTime.fromMillisecondsSinceEpoch(milliseconds, isUtc: isUtc); + DateTime now; + if (locMs != null) { + now = DateUtil.getDateTimeByMs(locMs); + } else { + now = isUtc ? DateTime.now().toUtc() : DateTime.now().toLocal(); + } + return old.year == now.year && old.month == now.month && old.day == now.day; + } + + /// is yesterday by dateTime. + /// 是否是昨天. + static bool isYesterday(DateTime dateTime, DateTime locDateTime) { + if (yearIsEqual(dateTime, locDateTime)) { + int spDay = getDayOfYear(locDateTime) - getDayOfYear(dateTime); + return spDay == 1; + } else { + return ((locDateTime.year - dateTime.year == 1) && + dateTime.month == 12 && + locDateTime.month == 1 && + dateTime.day == 31 && + locDateTime.day == 1); + } + } + + /// is yesterday by millis. + /// 是否是昨天. + static bool isYesterdayByMs(int ms, int locMs) { + return isYesterday(DateTime.fromMillisecondsSinceEpoch(ms), + DateTime.fromMillisecondsSinceEpoch(locMs)); + } + + /// is Week. + /// 是否是本周. + static bool isWeek(int? ms, {bool isUtc = false, int? locMs}) { + if (ms == null || ms <= 0) { + return false; + } + DateTime _old = DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc); + DateTime _now; + if (locMs != null) { + _now = DateUtil.getDateTimeByMs(locMs, isUtc: isUtc); + } else { + _now = isUtc ? DateTime.now().toUtc() : DateTime.now().toLocal(); + } + + DateTime old = + _now.millisecondsSinceEpoch > _old.millisecondsSinceEpoch ? _old : _now; + DateTime now = + _now.millisecondsSinceEpoch > _old.millisecondsSinceEpoch ? _now : _old; + return (now.weekday >= old.weekday) && + (now.millisecondsSinceEpoch - old.millisecondsSinceEpoch <= + 7 * 24 * 60 * 60 * 1000); + } + + /// year is equal. + /// 是否同年. + static bool yearIsEqual(DateTime dateTime, DateTime locDateTime) { + return dateTime.year == locDateTime.year; + } + + /// year is equal. + /// 是否同年. + static bool yearIsEqualByMs(int ms, int locMs) { + return yearIsEqual(DateTime.fromMillisecondsSinceEpoch(ms), + DateTime.fromMillisecondsSinceEpoch(locMs)); + } + + /// Return whether it is leap year. + /// 是否是闰年 + static bool isLeapYear(DateTime dateTime) { + return isLeapYearByYear(dateTime.year); + } + + /// Return whether it is leap year. + /// 是否是闰年 + static bool isLeapYearByYear(int year) { + return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; + } +} diff --git a/FlutterHelper/common_utils/lib/src/encrypt_util.dart b/FlutterHelper/common_utils/lib/src/encrypt_util.dart new file mode 100644 index 00000000..759f0432 --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/encrypt_util.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; + +import 'package:crypto/crypto.dart'; +import 'package:convert/convert.dart'; + +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Encrypt Util. + * @Date: 2019/07/02 + */ + +/// Encrypt Util. +class EncryptUtil { + /// md5 加密 + static String encodeMd5(String data) { + var content = Utf8Encoder().convert(data); + var digest = md5.convert(content); + return hex.encode(digest.bytes); + } + + /// 异或对称加密 + static String xorCode(String res, String key) { + List keyList = key.split(','); + List codeUnits = res.codeUnits; + List codes = []; + for (int i = 0, length = codeUnits.length; i < length; i++) { + int code = codeUnits[i] ^ int.parse(keyList[i % keyList.length]); + codes.add(code); + } + return String.fromCharCodes(codes); + } + + /// 异或对称 Base64 加密 + static String xorBase64Encode(String res, String key) { + String encode = xorCode(res, key); + encode = encodeBase64(encode); + return encode; + } + + /// 异或对称 Base64 解密 + static String xorBase64Decode(String res, String key) { + String encode = decodeBase64(res); + encode = xorCode(encode, key); + return encode; + } + + /// Base64加密 + static String encodeBase64(String data) { + var content = utf8.encode(data); + var digest = base64Encode(content); + return digest; + } + + /// Base64解密 + static String decodeBase64(String data) { + List bytes = base64Decode(data); + String result = utf8.decode(bytes); + return result; + } +} diff --git a/FlutterHelper/common_utils/lib/src/json_util.dart b/FlutterHelper/common_utils/lib/src/json_util.dart new file mode 100644 index 00000000..b10b5a81 --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/json_util.dart @@ -0,0 +1,99 @@ +import 'dart:convert'; + +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Date Util. + * @Date: 2020/01/06 + */ + +/// Json Util. +class JsonUtil { + /// Converts object [value] to a JSON string. + static String? encodeObj(dynamic value) { + return value == null ? null : json.encode(value); + } + + /// Converts JSON string [source] to object. + static T? getObj(String? source, T f(Map v)) { + if (source == null || source.isEmpty) return null; + try { + Map map = json.decode(source); + return f(map); + } catch (e) { + print('JsonUtil convert error, Exception:${e.toString()}'); + } + return null; + } + + /// Converts JSON string or JSON map [source] to object. + static T? getObject(dynamic source, T f(Map v)) { + if (source == null || source.toString().isEmpty) return null; + try { + Map map; + if (source is String) { + map = json.decode(source); + } else { + map = source; + } + return f(map); + } catch (e) { + print('JsonUtil convert error, Exception:${e.toString()}'); + } + return null; + } + + /// Converts JSON string list [source] to object list. + static List? getObjList(String? source, T f(Map v)) { + if (source == null || source.isEmpty) return null; + try { + List list = json.decode(source); + return list.map((value) { + if (value is String) { + value = json.decode(value); + } + return f(value); + }).toList(); + } catch (e) { + print('JsonUtil convert error, Exception:${e.toString()}'); + } + return null; + } + + /// Converts JSON string or JSON map list [source] to object list. + static List? getObjectList(dynamic source, T f(Map v)) { + if (source == null || source.toString().isEmpty) return null; + try { + List list; + if (source is String) { + list = json.decode(source); + } else { + list = source; + } + return list.map((value) { + if (value is String) { + value = json.decode(value); + } + return f(value); + }).toList(); + } catch (e) { + print('JsonUtil convert error, Exception:${e.toString()}'); + } + return null; + } + + /// get List + /// [1, 2, 3, 4, 5, 6]; + /// "[\"tom\",\"tony\",\"jacky\"]"; + static List? getList(dynamic source) { + List? list; + if (source is String) { + list = json.decode(source); + } else { + list = source; + } + return list?.map((v) { + return v as T; + }).toList(); + } +} diff --git a/FlutterHelper/common_utils/lib/src/log_util.dart b/FlutterHelper/common_utils/lib/src/log_util.dart new file mode 100644 index 00000000..5c47ff9b --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/log_util.dart @@ -0,0 +1,64 @@ +import 'dart:developer'; + +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Log Util. + * @Date: 2018/9/29 + */ + +/// Log Util. +class LogUtil { + static const String _defTag = 'common_utils'; + static bool _debugMode = false; //是否是debug模式,true: log v 不输出. + static int _maxLen = 128; + static String _tagValue = _defTag; + + static void init({ + String tag = _defTag, + bool isDebug = false, + int maxLen = 128, + }) { + _tagValue = tag; + _debugMode = isDebug; + _maxLen = maxLen; + } + + static void d(Object? object, {String? tag}) { + if (_debugMode) { + log('$tag d | ${object?.toString()}'); + } + } + + static void e(Object? object, {String? tag}) { + _printLog(tag, ' e ', object); + } + + static void v(Object? object, {String? tag}) { + if (_debugMode) { + _printLog(tag, ' v ', object); + } + } + + static void _printLog(String? tag, String stag, Object? object) { + String da = object?.toString() ?? 'null'; + tag = tag ?? _tagValue; + if (da.length <= _maxLen) { + print('$tag$stag $da'); + return; + } + print( + '$tag$stag — — — — — — — — — — — — — — — — st — — — — — — — — — — — — — — — —'); + while (da.isNotEmpty) { + if (da.length > _maxLen) { + print('$tag$stag| ${da.substring(0, _maxLen)}'); + da = da.substring(_maxLen, da.length); + } else { + print('$tag$stag| $da'); + da = ''; + } + } + print( + '$tag$stag — — — — — — — — — — — — — — — — ed — — — — — — — — — — — — — — — —'); + } +} diff --git a/FlutterHelper/common_utils/lib/src/money_util.dart b/FlutterHelper/common_utils/lib/src/money_util.dart new file mode 100644 index 00000000..2f6b398a --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/money_util.dart @@ -0,0 +1,108 @@ +import 'package:common_utils/src/num_util.dart'; + +enum MoneyUnit { + NORMAL, // 6.00 + YUAN, // ¥6.00 + YUAN_ZH, // 6.00元 + DOLLAR, // $6.00 +} +enum MoneyFormat { + NORMAL, //保留两位小数(6.00元) + END_INTEGER, //去掉末尾'0'(6.00元 -> 6元, 6.60元 -> 6.6元) + YUAN_INTEGER, //整元(6.00元 -> 6元) +} +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Money Util. + * @Date: 2018/9/29 + */ + +/// Money Util. +class MoneyUtil { + static const String YUAN = '¥'; + static const String YUAN_ZH = '元'; + static const String DOLLAR = '\$'; + + /// fen to yuan, format output. + /// 分 转 元, format格式输出. + static String changeF2Y(int amount, + {MoneyFormat format = MoneyFormat.NORMAL}) { + String moneyTxt; + double yuan = NumUtil.divide(amount, 100); + switch (format) { + case MoneyFormat.NORMAL: + moneyTxt = yuan.toStringAsFixed(2); + break; + case MoneyFormat.END_INTEGER: + if (amount % 100 == 0) { + moneyTxt = yuan.toInt().toString(); + } else if (amount % 10 == 0) { + moneyTxt = yuan.toStringAsFixed(1); + } else { + moneyTxt = yuan.toStringAsFixed(2); + } + break; + case MoneyFormat.YUAN_INTEGER: + moneyTxt = (amount % 100 == 0) + ? yuan.toInt().toString() + : yuan.toStringAsFixed(2); + break; + } + return moneyTxt; + } + + /// fen str to yuan, format & unit output. + /// 分字符串 转 元, format 与 unit 格式 输出. + static String changeFStr2YWithUnit(String amountStr, + {MoneyFormat format = MoneyFormat.NORMAL, + MoneyUnit unit = MoneyUnit.NORMAL}) { + int amount = int.parse(amountStr); + return changeF2YWithUnit(amount, format: format, unit: unit); + } + + /// fen to yuan, format & unit output. + /// 分 转 元, format 与 unit 格式 输出. + static String changeF2YWithUnit(int amount, + {MoneyFormat format = MoneyFormat.NORMAL, + MoneyUnit unit = MoneyUnit.NORMAL}) { + return withUnit(changeF2Y(amount, format: format), unit); + } + + /// yuan, format & unit output.(yuan is int,double,str). + /// 元, format 与 unit 格式 输出. + static String changeYWithUnit(Object yuan, MoneyUnit unit, + {MoneyFormat? format}) { + String yuanTxt = yuan.toString(); + if (format != null) { + int amount = changeY2F(yuan); + yuanTxt = changeF2Y(amount.toInt(), format: format); + } + return withUnit(yuanTxt, unit); + } + + /// yuan to fen. + /// 元 转 分, + static int changeY2F(Object yuan) { + return NumUtil.multiplyDecStr(yuan.toString(), '100').toInt(); + } + + /// with unit. + /// 拼接单位. + static String withUnit(String moneyTxt, MoneyUnit unit) { + switch (unit) { + case MoneyUnit.YUAN: + moneyTxt = YUAN + moneyTxt; + break; + case MoneyUnit.YUAN_ZH: + moneyTxt = moneyTxt + YUAN_ZH; + break; + case MoneyUnit.DOLLAR: + moneyTxt = DOLLAR + moneyTxt; + break; + default: + break; + } + return moneyTxt; + } +} diff --git a/FlutterHelper/common_utils/lib/src/num_util.dart b/FlutterHelper/common_utils/lib/src/num_util.dart new file mode 100644 index 00000000..84ed4efd --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/num_util.dart @@ -0,0 +1,161 @@ +import 'package:decimal/decimal.dart'; + +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Num Util. + * @Date: 2018/9/18 + */ + +/// Num Util. +class NumUtil { + /// The parameter [fractionDigits] must be an integer satisfying: `0 <= fractionDigits <= 20`. + static num? getNumByValueStr(String valueStr, {int? fractionDigits}) { + double? value = double.tryParse(valueStr); + return fractionDigits == null + ? value + : getNumByValueDouble(value, fractionDigits); + } + + /// The parameter [fractionDigits] must be an integer satisfying: `0 <= fractionDigits <= 20`. + static num? getNumByValueDouble(double? value, int fractionDigits) { + if (value == null) return null; + String valueStr = value.toStringAsFixed(fractionDigits); + return fractionDigits == 0 + ? int.tryParse(valueStr) + : double.tryParse(valueStr); + } + + /// get int by value str. + static int? getIntByValueStr(String valueStr, {int? defValue = 0}) { + return int.tryParse(valueStr) ?? defValue; + } + + /// get double by value str. + static double? getDoubleByValueStr(String valueStr, {double? defValue = 0}) { + return double.tryParse(valueStr) ?? defValue; + } + + ///isZero + static bool isZero(num? value) { + return value == null || value == 0; + } + + /// 加 (精确相加,防止精度丢失). + /// add (without loosing precision). + static double add(num a, num b) { + return addDec(a, b).toDouble(); + } + + /// 减 (精确相减,防止精度丢失). + /// subtract (without loosing precision). + static double subtract(num a, num b) { + return subtractDec(a, b).toDouble(); + } + + /// 乘 (精确相乘,防止精度丢失). + /// multiply (without loosing precision). + static double multiply(num a, num b) { + return multiplyDec(a, b).toDouble(); + } + + /// 除 (精确相除,防止精度丢失). + /// divide (without loosing precision). + static double divide(num a, num b) { + return divideDec(a, b).toDouble(); + } + + /// 加 (精确相加,防止精度丢失). + /// add (without loosing precision). + static Decimal addDec(num a, num b) { + return addDecStr(a.toString(), b.toString()); + } + + /// 减 (精确相减,防止精度丢失). + /// subtract (without loosing precision). + static Decimal subtractDec(num a, num b) { + return subtractDecStr(a.toString(), b.toString()); + } + + /// 乘 (精确相乘,防止精度丢失). + /// multiply (without loosing precision). + static Decimal multiplyDec(num a, num b) { + return multiplyDecStr(a.toString(), b.toString()); + } + + /// 除 (精确相除,防止精度丢失). + /// divide (without loosing precision). + static Decimal divideDec(num a, num b) { + return divideDecStr(a.toString(), b.toString()); + } + + /// 余数 + static Decimal remainder(num a, num b) { + return remainderDecStr(a.toString(), b.toString()); + } + + /// Relational less than operator. + static bool lessThan(num a, num b) { + return lessThanDecStr(a.toString(), b.toString()); + } + + /// Relational less than or equal operator. + static bool thanOrEqual(num a, num b) { + return thanOrEqualDecStr(a.toString(), b.toString()); + } + + /// Relational greater than operator. + static bool greaterThan(num a, num b) { + return greaterThanDecStr(a.toString(), b.toString()); + } + + /// Relational greater than or equal operator. + static bool greaterOrEqual(num a, num b) { + return greaterOrEqualDecStr(a.toString(), b.toString()); + } + + /// 加 + static Decimal addDecStr(String a, String b) { + return Decimal.parse(a) + Decimal.parse(b); + } + + /// 减 + static Decimal subtractDecStr(String a, String b) { + return Decimal.parse(a) - Decimal.parse(b); + } + + /// 乘 + static Decimal multiplyDecStr(String a, String b) { + return Decimal.parse(a) * Decimal.parse(b); + } + + /// 除 + static Decimal divideDecStr(String a, String b) { + return Decimal.parse(a) / Decimal.parse(b); + } + + /// 余数 + static Decimal remainderDecStr(String a, String b) { + return Decimal.parse(a) % Decimal.parse(b); + } + + /// Relational less than operator. + static bool lessThanDecStr(String a, String b) { + return Decimal.parse(a) < Decimal.parse(b); + } + + /// Relational less than or equal operator. + static bool thanOrEqualDecStr(String a, String b) { + return Decimal.parse(a) <= Decimal.parse(b); + } + + /// Relational greater than operator. + static bool greaterThanDecStr(String a, String b) { + return Decimal.parse(a) > Decimal.parse(b); + } + + /// Relational greater than or equal operator. + static bool greaterOrEqualDecStr(String a, String b) { + return Decimal.parse(a) >= Decimal.parse(b); + } +} diff --git a/FlutterHelper/common_utils/lib/src/object_util.dart b/FlutterHelper/common_utils/lib/src/object_util.dart new file mode 100644 index 00000000..ea6bc719 --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/object_util.dart @@ -0,0 +1,70 @@ +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Object Util. + * @Date: 2018/9/8 + */ + +/// Object Util. +class ObjectUtil { + /// Returns true if the string is null or 0-length. + static bool isEmptyString(String? str) { + return str == null || str.isEmpty; + } + + /// Returns true if the list is null or 0-length. + static bool isEmptyList(Iterable? list) { + return list == null || list.isEmpty; + } + + /// Returns true if there is no key/value pair in the map. + static bool isEmptyMap(Map? map) { + return map == null || map.isEmpty; + } + + /// Returns true String or List or Map is empty. + static bool isEmpty(Object? object) { + if (object == null) return true; + if (object is String && object.isEmpty) { + return true; + } else if (object is Iterable && object.isEmpty) { + return true; + } else if (object is Map && object.isEmpty) { + return true; + } + return false; + } + + /// Returns true String or List or Map is not empty. + static bool isNotEmpty(Object? object) { + return !isEmpty(object); + } + + /// Returns true Two List Is Equal. + static bool twoListIsEqual(List? listA, List? listB) { + if (listA == listB) return true; + if (listA == null || listB == null) return false; + int length = listA.length; + if (length != listB.length) return false; + for (int i = 0; i < length; i++) { + if (!listA.contains(listB[i])) { + return false; + } + } + return true; + } + + /// get length. + static int getLength(Object? value) { + if (value == null) return 0; + if (value is String) { + return value.length; + } else if (value is Iterable) { + return value.length; + } else if (value is Map) { + return value.length; + } else { + return 0; + } + } +} diff --git a/FlutterHelper/common_utils/lib/src/regex_util.dart b/FlutterHelper/common_utils/lib/src/regex_util.dart new file mode 100644 index 00000000..0b04817a --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/regex_util.dart @@ -0,0 +1,238 @@ +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Regex Util. + * @Date: 2018/9/8 + */ + +/// id card province dict. +List ID_CARD_PROVINCE_DICT = [ + '11=北京', + '12=天津', + '13=河北', + '14=山西', + '15=内蒙古', + '21=辽宁', + '22=吉林', + '23=黑龙江', + '31=上海', + '32=江苏', + '33=浙江', + '34=安徽', + '35=福建', + '36=江西', + '37=山东', + '41=河南', + '42=湖北', + '43=湖南', + '44=广东', + '45=广西', + '46=海南', + '50=重庆', + '51=四川', + '52=贵州', + '53=云南', + '54=西藏', + '61=陕西', + '62=甘肃', + '63=青海', + '64=宁夏', + '65=新疆', + '71=台湾老', + '81=香港', + '82=澳门', + '83=台湾新', + '91=国外', +]; + +/// Regex Util. +class RegexUtil { + /// Regex of simple mobile. + static final String regexMobileSimple = '^[1]\\d{10}\$'; + + /// Regex of exact mobile. + ///

china mobile: 134(0-8), 135, 136, 137, 138, 139, 147, 150, 151, 152, 157, 158, 159, 165, 172, 178, 182, 183, 184, 187, 188, 195, 198

+ ///

china unicom: 130, 131, 132, 145, 155, 156, 166, 167, 171, 175, 176, 185, 186

+ ///

china telecom: 133, 153, 162, 173, 177, 180, 181, 189, 199, 191

+ ///

global star: 1349

+ ///

virtual operator: 170

+ static final String regexMobileExact = + '^((13[0-9])|(14[57])|(15[0-35-9])|(16[2567])|(17[01235-8])|(18[0-9])|(19[1589]))\\d{8}\$'; + + /// Regex of telephone number. + static final String regexTel = '^0\\d{2,3}[- ]?\\d{7,8}'; + + /// Regex of id card number which length is 15. + static final String regexIdCard15 = + '^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}\$'; + + /// Regex of id card number which length is 18. + static final String regexIdCard18 = + '^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9Xx])\$'; + + /// Regex of email. + static final String regexEmail = + '^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*\$'; + + /// Regex of url. + static final String regexUrl = '[a-zA-Z]+://[^\\s]*'; + + /// Regex of Chinese character. + static final String regexZh = '[\\u4e00-\\u9fa5]'; + + /// Regex of date which pattern is 'yyyy-MM-dd'. + static final String regexDate = + '^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)\$'; + + /// Regex of ip address. + static final String regexIp = + '((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)'; + + /// must contain letters and numbers, 6 ~ 18. + /// 必须包含字母和数字, 6~18. + static const String regexUsername = + '^(?![0-9]+\$)(?![a-zA-Z]+\$)[0-9A-Za-z]{6,18}\$'; + + /// must contain letters and numbers, can contain special characters 6 ~ 18. + /// 必须包含字母和数字,可包含特殊字符 6~18. + static const String regexUsername2 = + '^(?![0-9]+\$)(?![a-zA-Z]+\$)[0-9A-Za-z\\W]{6,18}\$'; + + /// must contain letters and numbers and special characters, 6 ~ 18. + /// 必须包含字母和数字和殊字符, 6~18. + static const String regexUsername3 = + '^(?![0-9]+\$)(?![a-zA-Z]+\$)(?![0-9a-zA-Z]+\$)(?![0-9\\W]+\$)(?![a-zA-Z\\W]+\$)[0-9A-Za-z\\W]{6,18}\$'; + + /// Regex of QQ number. + static final String regexQQ = '[1-9][0-9]{4,}'; + + /// Regex of postal code in China. + static final String regexChinaPostalCode = "[1-9]\\d{5}(?!\\d)"; + + /// Regex of Passport. + static final String regexPassport = + r'(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)'; + + static final Map cityMap = Map(); + + ///Return whether input matches regex of simple mobile. + static bool isMobileSimple(String input) { + return matches(regexMobileSimple, input); + } + + ///Return whether input matches regex of exact mobile. + static bool isMobileExact(String input) { + return matches(regexMobileExact, input); + } + + /// Return whether input matches regex of telephone number. + static bool isTel(String input) { + return matches(regexTel, input); + } + + /// Return whether input matches regex of id card number. + static bool isIDCard(String input) { + if (input.length == 15) { + return isIDCard15(input); + } + if (input.length == 18) { + return isIDCard18Exact(input); + } + return false; + } + + /// Return whether input matches regex of id card number which length is 15. + static bool isIDCard15(String input) { + return matches(regexIdCard15, input); + } + + /// Return whether input matches regex of id card number which length is 18. + static bool isIDCard18(String input) { + return matches(regexIdCard18, input); + } + + ///Return whether input matches regex of exact id card number which length is 18. + static bool isIDCard18Exact(String input) { + if (isIDCard18(input)) { + List factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; + List suffix = [ + '1', + '0', + 'X', + '9', + '8', + '7', + '6', + '5', + '4', + '3', + '2' + ]; + if (cityMap.isEmpty) { + List list = ID_CARD_PROVINCE_DICT; + List> mapEntryList = []; + for (int i = 0, length = list.length; i < length; i++) { + List tokens = list[i].trim().split('='); + MapEntry mapEntry = MapEntry(tokens[0], tokens[1]); + mapEntryList.add(mapEntry); + } + cityMap.addEntries(mapEntryList); + } + if (cityMap[input.substring(0, 2)] != null) { + int weightSum = 0; + for (int i = 0; i < 17; ++i) { + weightSum += (input.codeUnitAt(i) - '0'.codeUnitAt(0)) * factor[i]; + } + int idCardMod = weightSum % 11; + String idCardLast = String.fromCharCode(input.codeUnitAt(17)); + return idCardLast == suffix[idCardMod]; + } + } + return false; + } + + /// Return whether input matches regex of email. + static bool isEmail(String input) { + return matches(regexEmail, input); + } + + /// Return whether input matches regex of url. + static bool isURL(String input) { + return matches(regexUrl, input); + } + + /// Return whether input matches regex of Chinese character. + static bool isZh(String input) { + return '〇' == input || matches(regexZh, input); + } + + /// Return whether input matches regex of date which pattern is 'yyyy-MM-dd'. + static bool isDate(String input) { + return matches(regexDate, input); + } + + /// Return whether input matches regex of ip address. + static bool isIP(String input) { + return matches(regexIp, input); + } + + /// Return whether input matches regex of username. + static bool isUserName(String input, {String regex = regexUsername}) { + return matches(regex, input); + } + + /// Return whether input matches regex of QQ. + static bool isQQ(String input) { + return matches(regexQQ, input); + } + + ///Return whether input matches regex of Passport. + static bool isPassport(String input) { + return matches(regexPassport, input); + } + + static bool matches(String regex, String input) { + if (input.isEmpty) return false; + return RegExp(regex).hasMatch(input); + } +} diff --git a/FlutterHelper/common_utils/lib/src/text_util.dart b/FlutterHelper/common_utils/lib/src/text_util.dart new file mode 100644 index 00000000..3931767f --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/text_util.dart @@ -0,0 +1,83 @@ +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Text Util. + * @Date: 2019/7/9 + */ + +/// Text Util. +class TextUtil { + /// isEmpty + static bool isEmpty(String? text) { + return text == null || text.isEmpty; + } + + /// 每隔 x位 加 pattern + static String formatDigitPattern(String text, + {int digit = 4, String pattern = ' '}) { + text = text.replaceAllMapped(RegExp('(.{$digit})'), (Match match) { + return '${match.group(0)}$pattern'; + }); + if (text.endsWith(pattern)) { + text = text.substring(0, text.length - 1); + } + return text; + } + + /// 每隔 x位 加 pattern, 从末尾开始 + static String formatDigitPatternEnd(String text, + {int digit = 4, String pattern = ' '}) { + String temp = reverse(text); + temp = formatDigitPattern(temp, digit: digit, pattern: pattern); + temp = reverse(temp); + return temp; + } + + /// 每隔4位加空格 + static String formatSpace4(String text) { + return formatDigitPattern(text); + } + + /// 每隔3三位加逗号 + /// num 数字或数字字符串。int型。 + static String formatComma3(Object num) { + return formatDigitPatternEnd(num.toString(), digit: 3, pattern: ','); + } + + /// 每隔3三位加逗号 + /// num 数字或数字字符串。double型。 + static String formatDoubleComma3(Object num, + {int digit = 3, String pattern = ','}) { + List list = num.toString().split('.'); + String left = + formatDigitPatternEnd(list[0], digit: digit, pattern: pattern); + String right = list[1]; + return '$left.$right'; + } + + /// hideNumber + static String hideNumber(String phoneNo, + {int start = 3, int end = 7, String replacement = '****'}) { + return phoneNo.replaceRange(start, end, replacement); + } + + /// replace + static String replace(String text, Pattern from, String replace) { + return text.replaceAll(from, replace); + } + + /// split + static List split(String text, Pattern pattern) { + return text.split(pattern); + } + + /// reverse + static String reverse(String text) { + if (isEmpty(text)) return ''; + StringBuffer sb = StringBuffer(); + for (int i = text.length - 1; i >= 0; i--) { + sb.writeCharCode(text.codeUnitAt(i)); + } + return sb.toString(); + } +} diff --git a/FlutterHelper/common_utils/lib/src/timeline_util.dart b/FlutterHelper/common_utils/lib/src/timeline_util.dart new file mode 100644 index 00000000..85c07c7f --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/timeline_util.dart @@ -0,0 +1,374 @@ +import 'package:common_utils/src/date_util.dart'; + +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Timeline Util. + * @Date: 2018/10/3 + */ + +/// (xx)Configurable output. +/// (xx)为可配置输出. +enum DayFormat { + /// (less than 10s->just now)、x minutes、x hours、(Yesterday)、x days. + /// (小于10s->刚刚)、x分钟、x小时、(昨天)、x天. + Simple, + + /// (less than 10s->just now)、x minutes、x hours、[This year:(Yesterday/a day ago)、(two days age)、MM-dd ]、[past years: yyyy-MM-dd] + /// (小于10s->刚刚)、x分钟、x小时、[今年: (昨天/1天前)、(2天前)、MM-dd],[往年: yyyy-MM-dd]. + Common, + + /// 日期 + HH:mm + /// (less than 10s->just now)、x minutes、x hours、[This year:(Yesterday HH:mm/a day ago)、(two days age)、MM-dd HH:mm]、[past years: yyyy-MM-dd HH:mm] + /// 小于10s->刚刚)、x分钟、x小时、[今年: (昨天 HH:mm/1天前)、(2天前)、MM-dd HH:mm],[往年: yyyy-MM-dd HH:mm]. + Full, +} + +/// Timeline information configuration. +/// Timeline信息配置. +abstract class TimelineInfo { + String suffixAgo(); //suffix ago(后缀 后). + + String suffixAfter(); //suffix after(后缀 前). + + int maxJustNowSecond() => 30; // max just now second. + + String lessThanOneMinute() => ''; //just now(刚刚). + + String customYesterday() => ''; //Yesterday(昨天).优先级高于keepOneDay + + bool keepOneDay(); //保持1天,example: true -> 1天前, false -> MM-dd. + + bool keepTwoDays(); //保持2天,example: true -> 2天前, false -> MM-dd. + + String oneMinute(int minutes); //a minute(1分钟). + + String minutes(int minutes); //x minutes(x分钟). + + String anHour(int hours); //an hour(1小时). + + String hours(int hours); //x hours(x小时). + + String oneDay(int days); //a day(1天). + + String weeks(int week) => ''; //x week(星期x). + + String days(int days); //x days(x天). + +} + +class ZhInfo implements TimelineInfo { + String suffixAgo() => '前'; + + String suffixAfter() => '后'; + + int maxJustNowSecond() => 30; + + String lessThanOneMinute() => '刚刚'; + + String customYesterday() => '昨天'; + + bool keepOneDay() => true; + + bool keepTwoDays() => true; + + String oneMinute(int minutes) => '$minutes分钟'; + + String minutes(int minutes) => '$minutes分钟'; + + String anHour(int hours) => '$hours小时'; + + String hours(int hours) => '$hours小时'; + + String oneDay(int days) => '$days天'; + + String weeks(int week) => ''; //x week(星期x). + + String days(int days) => '$days天'; +} + +class EnInfo implements TimelineInfo { + String suffixAgo() => ' ago'; + + String suffixAfter() => ' after'; + + int maxJustNowSecond() => 30; + + String lessThanOneMinute() => 'just now'; + + String customYesterday() => 'Yesterday'; + + bool keepOneDay() => true; + + bool keepTwoDays() => true; + + String oneMinute(int minutes) => 'a minute'; + + String minutes(int minutes) => '$minutes minutes'; + + String anHour(int hours) => 'an hour'; + + String hours(int hours) => '$hours hours'; + + String oneDay(int days) => 'a day'; + + String weeks(int week) => ''; //x week(星期x). + + String days(int days) => '$days days'; +} + +class ZhNormalInfo implements TimelineInfo { + String suffixAgo() => '前'; + + String suffixAfter() => '后'; + + int maxJustNowSecond() => 30; + + String lessThanOneMinute() => '刚刚'; + + String customYesterday() => '昨天'; + + bool keepOneDay() => true; + + bool keepTwoDays() => false; + + String oneMinute(int minutes) => '$minutes分钟'; + + String minutes(int minutes) => '$minutes分钟'; + + String anHour(int hours) => '$hours小时'; + + String hours(int hours) => '$hours小时'; + + String oneDay(int days) => '$days天'; + + String weeks(int week) => ''; //x week(星期x). + + String days(int days) => '$days天'; +} + +class EnNormalInfo implements TimelineInfo { + String suffixAgo() => ' ago'; + + String suffixAfter() => ' after'; + + int maxJustNowSecond() => 30; + + String lessThanOneMinute() => 'just now'; + + String customYesterday() => 'Yesterday'; + + bool keepOneDay() => true; + + bool keepTwoDays() => false; + + String oneMinute(int minutes) => 'a minute'; + + String minutes(int minutes) => '$minutes minutes'; + + String anHour(int hours) => 'an hour'; + + String hours(int hours) => '$hours hours'; + + String oneDay(int days) => 'a day'; + + String weeks(int week) => ''; //x week(星期x). + + String days(int days) => '$days days'; +} + +Map _timelineInfoMap = { + 'zh': ZhInfo(), + 'en': EnInfo(), + 'zh_normal': ZhNormalInfo(), //keepTwoDays() => false + 'en_normal': EnNormalInfo(), //keepTwoDays() => false +}; + +/// add custom configuration. +void setLocaleInfo(String locale, TimelineInfo timelineInfo) { + ArgumentError.checkNotNull(locale, '[locale] must not be null'); + ArgumentError.checkNotNull(timelineInfo, '[timelineInfo] must not be null'); + _timelineInfoMap[locale] = timelineInfo; +} + +/// TimelineUtil +class TimelineUtil { + /// format time by DateTime. + /// dateTime + /// locDateTime: current time or schedule time. + /// locale: output key. + static String formatByDateTime( + DateTime dateTime, { + DateTime? locDateTime, + String? locale, + DayFormat? dayFormat, + }) { + return format( + dateTime.millisecondsSinceEpoch, + locTimeMs: locDateTime?.millisecondsSinceEpoch, + locale: locale, + dayFormat: dayFormat, + ); + } + + /// format time by millis. + /// dateTime : millis. + /// locDateTime: current time or schedule time. millis. + /// locale: output key. + static String format( + int ms, { + int? locTimeMs, + String? locale, + DayFormat? dayFormat, + }) { + int _locTimeMs = locTimeMs ?? DateTime.now().millisecondsSinceEpoch; + String _locale = locale ?? 'en'; + TimelineInfo _info = _timelineInfoMap[_locale] ?? EnInfo(); + DayFormat _dayFormat = dayFormat ?? DayFormat.Common; + + int elapsed = _locTimeMs - ms; + String suffix; + if (elapsed < 0) { + suffix = _info.suffixAfter(); + // suffix after is empty. user just now. + if (suffix.isNotEmpty) { + elapsed = elapsed.abs(); + _dayFormat = DayFormat.Simple; + } else { + return _info.lessThanOneMinute(); + } + } else { + suffix = _info.suffixAgo(); + } + + String timeline; + if (_info.customYesterday().isNotEmpty && + DateUtil.isYesterdayByMs(ms, _locTimeMs)) { + return _getYesterday(ms, _info, _dayFormat); + } + + if (!DateUtil.yearIsEqualByMs(ms, _locTimeMs)) { + timeline = _getYear(ms, _dayFormat); + if (timeline.isNotEmpty) return timeline; + } + + final num seconds = elapsed / 1000; + final num minutes = seconds / 60; + final num hours = minutes / 60; + final num days = hours / 24; + + if (seconds < 90) { + timeline = _info.oneMinute(1); + if (suffix != _info.suffixAfter() && + _info.lessThanOneMinute().isNotEmpty && + seconds < _info.maxJustNowSecond()) { + timeline = _info.lessThanOneMinute(); + suffix = ''; + } + } else if (minutes < 60) { + timeline = _info.minutes(minutes.round()); + } else if (minutes < 90) { + timeline = _info.anHour(1); + } else if (hours < 24) { + timeline = _info.hours(hours.round()); + } else { + if ((days.round() == 1 && _info.keepOneDay() == true) || + (days.round() == 2 && _info.keepTwoDays() == true)) { + _dayFormat = DayFormat.Simple; + } + timeline = _formatDays(ms, days.round(), _info, _dayFormat); + suffix = (_dayFormat == DayFormat.Simple ? suffix : ''); + } + return timeline + suffix; + } + + /// Timeline like QQ. + /// + /// today (HH:mm) + /// yesterday (昨天;Yesterday) + /// this week (星期一,周一;Monday,Mon) + /// others (yyyy-MM-dd) + static String formatA( + int ms, { + int? locMs, + String formatToday = 'HH:mm', + String format = 'yyyy-MM-dd', + String languageCode = 'en', + bool short = false, + }) { + int _locTimeMs = locMs ?? DateTime.now().millisecondsSinceEpoch; + int elapsed = _locTimeMs - ms; + if (elapsed < 0) { + return DateUtil.formatDateMs(ms, format: formatToday); + } + + if (DateUtil.isToday(ms, locMs: _locTimeMs)) { + return DateUtil.formatDateMs(ms, format: formatToday); + } + + if (DateUtil.isYesterdayByMs(ms, _locTimeMs)) { + return languageCode == 'zh' ? '昨天' : 'Yesterday'; + } + + if (DateUtil.isWeek(ms, locMs: _locTimeMs)) { + return DateUtil.getWeekdayByMs(ms, + languageCode: languageCode, short: short); + } + + return DateUtil.formatDateMs(ms, format: format); + } + + /// get Yesterday. + /// 获取昨天. + static String _getYesterday( + int ms, + TimelineInfo info, + DayFormat dayFormat, + ) { + return info.customYesterday() + + (dayFormat == DayFormat.Full + ? (' ' + DateUtil.formatDateMs(ms, format: 'HH:mm')) + : ''); + } + + /// get is not year info. + /// 获取非今年信息. + static String _getYear( + int ms, + DayFormat dayFormat, + ) { + if (dayFormat != DayFormat.Simple) { + return DateUtil.formatDateMs(ms, + format: (dayFormat == DayFormat.Common + ? 'yyyy-MM-dd' + : 'yyyy-MM-dd HH:mm')); + } + return ''; + } + + /// format Days. + static String _formatDays( + int ms, + num days, + TimelineInfo info, + DayFormat dayFormat, + ) { + String timeline; + switch (dayFormat) { + case DayFormat.Simple: + timeline = (days == 1 + ? info.customYesterday().isEmpty + ? info.oneDay(days.round()) + : info.days(2) + : info.days(days.round())); + break; + case DayFormat.Common: + timeline = DateUtil.formatDateMs(ms, format: 'MM-dd'); + break; + case DayFormat.Full: + timeline = DateUtil.formatDateMs(ms, format: 'MM-dd HH:mm'); + break; + } + return timeline; + } +} diff --git a/FlutterHelper/common_utils/lib/src/timer_util.dart b/FlutterHelper/common_utils/lib/src/timer_util.dart new file mode 100644 index 00000000..a5b17b24 --- /dev/null +++ b/FlutterHelper/common_utils/lib/src/timer_util.dart @@ -0,0 +1,119 @@ +import 'dart:async'; + +///timer callback.(millisUntilFinished 毫秒). +typedef void OnTimerTickCallback(int millisUntilFinished); + +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Timer Util. + * @Date: 2018/9/28 + */ + +/// TimerUtil. +class TimerUtil { + TimerUtil( + {this.mInterval = Duration.millisecondsPerSecond, this.mTotalTime = 0}); + + /// Timer. + Timer? _mTimer; + + /// Is Timer active. + /// Timer是否启动. + bool _isActive = false; + + /// Timer interval (unit millisecond,def: 1000 millisecond). + /// Timer间隔 单位毫秒,默认1000毫秒(1秒). + int mInterval; + + /// countdown totalTime. + /// 倒计时总时间 + int mTotalTime; //单位毫秒 + + OnTimerTickCallback? _onTimerTickCallback; + + /// set Timer interval. (unit millisecond). + /// 设置Timer间隔. + void setInterval(int interval) { + if (interval <= 0) interval = Duration.millisecondsPerSecond; + mInterval = interval; + } + + /// set countdown totalTime. (unit millisecond). + /// 设置倒计时总时间. + void setTotalTime(int totalTime) { + if (totalTime <= 0) return; + mTotalTime = totalTime; + } + + /// start Timer. + /// 启动定时Timer. + void startTimer() { + if (_isActive || mInterval <= 0) return; + _isActive = true; + Duration duration = Duration(milliseconds: mInterval); + _doCallback(0); + _mTimer = Timer.periodic(duration, (Timer timer) { + _doCallback(timer.tick); + }); + } + + /// start countdown Timer. + /// 启动倒计时Timer. + void startCountDown() { + if (_isActive || mInterval <= 0 || mTotalTime <= 0) return; + _isActive = true; + Duration duration = Duration(milliseconds: mInterval); + _doCallback(mTotalTime); + _mTimer = Timer.periodic(duration, (Timer timer) { + int time = mTotalTime - mInterval; + mTotalTime = time; + if (time >= mInterval) { + _doCallback(time); + } else if (time == 0) { + _doCallback(time); + cancel(); + } else { + timer.cancel(); + Future.delayed(Duration(milliseconds: time), () { + mTotalTime = 0; + _doCallback(0); + cancel(); + }); + } + }); + } + + void _doCallback(int time) { + if (_onTimerTickCallback != null) { + _onTimerTickCallback!(time); + } + } + + /// update countdown totalTime. + /// 重设倒计时总时间. + void updateTotalTime(int totalTime) { + cancel(); + mTotalTime = totalTime; + startCountDown(); + } + + /// timer is Active. + /// Timer是否启动. + bool isActive() { + return _isActive; + } + + /// Cancels the timer. + /// 取消计时器. + void cancel() { + _mTimer?.cancel(); + _mTimer = null; + _isActive = false; + } + + /// set timer callback. + void setOnTimerTickCallback(OnTimerTickCallback callback) { + _onTimerTickCallback = callback; + } +} diff --git a/FlutterHelper/common_utils/pkgget b/FlutterHelper/common_utils/pkgget new file mode 100644 index 00000000..15cf7712 --- /dev/null +++ b/FlutterHelper/common_utils/pkgget @@ -0,0 +1,3 @@ +export PUB_HOSTED_URL=https://pub.flutter-io.cn +export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn +flutter packages get \ No newline at end of file diff --git a/FlutterHelper/common_utils/pubspec.yaml b/FlutterHelper/common_utils/pubspec.yaml new file mode 100644 index 00000000..290869aa --- /dev/null +++ b/FlutterHelper/common_utils/pubspec.yaml @@ -0,0 +1,15 @@ +name: common_utils +description: Dart common utils library.Contain DateUtil, EncryptUtil, JsonUtil, LogUtil, MoneyUtil, NumUtil, ObjectUtil, RegexUtil, TextUtil, TimelineUtil, TimerUtil. +version: 2.0.2 +homepage: https://github.com/Sky24n/common_utils + +environment: + sdk: ">=2.12.0-259.9.beta <3.0.0" + +dependencies: + # https://github.com/a14n/dart-decimal + decimal: ">=1.0.0 <3.0.0" + # https://github.com/dart-lang/crypto + crypto: ">=3.0.0 <5.0.0" + # https://github.com/dart-lang/convert + convert: ">=3.0.0 <5.0.0" \ No newline at end of file diff --git a/FlutterHelper/common_utils/uploadMaster b/FlutterHelper/common_utils/uploadMaster new file mode 100644 index 00000000..6f74d207 --- /dev/null +++ b/FlutterHelper/common_utils/uploadMaster @@ -0,0 +1 @@ +git push origin master diff --git a/FlutterHelper/flutter.rp b/FlutterHelper/flutter.rp new file mode 100644 index 00000000..40df1275 Binary files /dev/null and b/FlutterHelper/flutter.rp differ diff --git a/FlutterHelper/flutter_helper/.gitignore b/FlutterHelper/flutter_helper/.gitignore new file mode 100644 index 00000000..9d532b18 --- /dev/null +++ b/FlutterHelper/flutter_helper/.gitignore @@ -0,0 +1,41 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json diff --git a/FlutterHelper/flutter_helper/.metadata b/FlutterHelper/flutter_helper/.metadata new file mode 100644 index 00000000..9432b087 --- /dev/null +++ b/FlutterHelper/flutter_helper/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: f30b7f4db93ee747cd727df747941a28ead25ff5 + channel: stable + +project_type: app diff --git a/FlutterHelper/flutter_helper/README.md b/FlutterHelper/flutter_helper/README.md new file mode 100644 index 00000000..784d34d3 --- /dev/null +++ b/FlutterHelper/flutter_helper/README.md @@ -0,0 +1,16 @@ +# flutter_helper + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/FlutterHelper/flutter_helper/android/.gitignore b/FlutterHelper/flutter_helper/android/.gitignore new file mode 100644 index 00000000..a484c7bd --- /dev/null +++ b/FlutterHelper/flutter_helper/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +build.gradle +.idea +.gradle + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/FlutterHelper/flutter_helper/android/app/.gitignore b/FlutterHelper/flutter_helper/android/app/.gitignore new file mode 100644 index 00000000..a484c7bd --- /dev/null +++ b/FlutterHelper/flutter_helper/android/app/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +build.gradle +.idea +.gradle + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/FlutterHelper/flutter_helper/android/app/build.gradle b/FlutterHelper/flutter_helper/android/app/build.gradle new file mode 100644 index 00000000..481156af --- /dev/null +++ b/FlutterHelper/flutter_helper/android/app/build.gradle @@ -0,0 +1,61 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 29 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId "com.example.flutter_helper" + minSdkVersion 16 + targetSdkVersion 29 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/FlutterHelper/flutter_helper/android/app/src/debug/AndroidManifest.xml b/FlutterHelper/flutter_helper/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..6e9515b9 --- /dev/null +++ b/FlutterHelper/flutter_helper/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/FlutterHelper/flutter_helper/android/app/src/main/AndroidManifest.xml b/FlutterHelper/flutter_helper/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..cafa5191 --- /dev/null +++ b/FlutterHelper/flutter_helper/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_helper/android/app/src/main/kotlin/com/example/flutter_helper/MainActivity.kt b/FlutterHelper/flutter_helper/android/app/src/main/kotlin/com/example/flutter_helper/MainActivity.kt new file mode 100644 index 00000000..4cd8d47b --- /dev/null +++ b/FlutterHelper/flutter_helper/android/app/src/main/kotlin/com/example/flutter_helper/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.flutter_helper + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/FlutterHelper/flutter_helper/android/app/src/main/res/drawable/launch_background.xml b/FlutterHelper/flutter_helper/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/FlutterHelper/flutter_helper/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..db77bb4b Binary files /dev/null and b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..17987b79 Binary files /dev/null and b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..09d43914 Binary files /dev/null and b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..d5f1c8d3 Binary files /dev/null and b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..4d6372ee Binary files /dev/null and b/FlutterHelper/flutter_helper/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_helper/android/app/src/main/res/values/styles.xml b/FlutterHelper/flutter_helper/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..1f83a33f --- /dev/null +++ b/FlutterHelper/flutter_helper/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/FlutterHelper/flutter_helper/android/app/src/profile/AndroidManifest.xml b/FlutterHelper/flutter_helper/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..6e9515b9 --- /dev/null +++ b/FlutterHelper/flutter_helper/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/FlutterHelper/flutter_helper/android/build.gradle b/FlutterHelper/flutter_helper/android/build.gradle new file mode 100644 index 00000000..ec823b7b --- /dev/null +++ b/FlutterHelper/flutter_helper/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.5.0' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.2.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/FlutterHelper/flutter_helper/android/gradle.properties b/FlutterHelper/flutter_helper/android/gradle.properties new file mode 100644 index 00000000..a6738207 --- /dev/null +++ b/FlutterHelper/flutter_helper/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true +android.enableR8=true diff --git a/FlutterHelper/flutter_helper/android/gradle/wrapper/gradle-wrapper.properties b/FlutterHelper/flutter_helper/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..3df6b338 --- /dev/null +++ b/FlutterHelper/flutter_helper/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip diff --git a/FlutterHelper/flutter_helper/android/settings.gradle b/FlutterHelper/flutter_helper/android/settings.gradle new file mode 100644 index 00000000..44e62bcf --- /dev/null +++ b/FlutterHelper/flutter_helper/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/FlutterHelper/flutter_helper/android/settings_aar.gradle b/FlutterHelper/flutter_helper/android/settings_aar.gradle new file mode 100644 index 00000000..e7b4def4 --- /dev/null +++ b/FlutterHelper/flutter_helper/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/FlutterHelper/flutter_helper/assets/CustomFont.ttf b/FlutterHelper/flutter_helper/assets/CustomFont.ttf new file mode 100755 index 00000000..6d165949 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/CustomFont.ttf differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00000.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00000.png new file mode 100644 index 00000000..75036112 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00000.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00001.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00001.png new file mode 100644 index 00000000..75036112 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00001.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00002.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00002.png new file mode 100644 index 00000000..509dfdcb Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00002.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00003.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00003.png new file mode 100644 index 00000000..9da9a330 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00003.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00004.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00004.png new file mode 100644 index 00000000..f1be25af Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00004.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00005.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00005.png new file mode 100644 index 00000000..f1be25af Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00005.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00006.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00006.png new file mode 100644 index 00000000..1b099712 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00006.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00007.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00007.png new file mode 100644 index 00000000..415078e5 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00007.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00008.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00008.png new file mode 100644 index 00000000..5555456c Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00008.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00009.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00009.png new file mode 100644 index 00000000..8d513c04 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00009.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00010.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00010.png new file mode 100644 index 00000000..9bd8b564 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00010.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00011.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00011.png new file mode 100644 index 00000000..27534a78 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00011.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00012.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00012.png new file mode 100644 index 00000000..55807449 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00012.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00013.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00013.png new file mode 100644 index 00000000..21bf739a Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00013.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00014.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00014.png new file mode 100644 index 00000000..6b79eea9 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00014.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00015.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00015.png new file mode 100644 index 00000000..3014b30e Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00015.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00016.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00016.png new file mode 100644 index 00000000..5946b0fc Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00016.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00017.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00017.png new file mode 100644 index 00000000..9170315f Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00017.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00018.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00018.png new file mode 100644 index 00000000..6f14bcbe Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00018.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00019.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00019.png new file mode 100644 index 00000000..ffeafc20 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00019.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00020.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00020.png new file mode 100644 index 00000000..d085869f Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00020.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00021.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00021.png new file mode 100644 index 00000000..0a6c447f Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00021.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00022.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00022.png new file mode 100644 index 00000000..78870ab0 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00022.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00023.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00023.png new file mode 100644 index 00000000..2fc75a5d Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00023.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00024.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00024.png new file mode 100644 index 00000000..eba6c531 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00024.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00025.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00025.png new file mode 100644 index 00000000..231252cc Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00025.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00026.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00026.png new file mode 100644 index 00000000..0a4c8279 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00026.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00027.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00027.png new file mode 100644 index 00000000..035e3365 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00027.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00028.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00028.png new file mode 100644 index 00000000..bb3d4882 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00028.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00029.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00029.png new file mode 100644 index 00000000..d644b1da Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00029.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00030.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00030.png new file mode 100644 index 00000000..00cfdf26 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00030.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00031.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00031.png new file mode 100644 index 00000000..8c420fe5 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00031.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00032.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00032.png new file mode 100644 index 00000000..ecf581b3 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00032.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00033.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00033.png new file mode 100644 index 00000000..97076703 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00033.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00034.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00034.png new file mode 100644 index 00000000..2cb339d3 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00034.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00035.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00035.png new file mode 100644 index 00000000..0490e5e3 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00035.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00036.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00036.png new file mode 100644 index 00000000..e79b41a2 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00036.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00037.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00037.png new file mode 100644 index 00000000..bad7bfdd Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00037.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00038.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00038.png new file mode 100644 index 00000000..5adb2ee6 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00038.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00039.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00039.png new file mode 100644 index 00000000..d5468bdc Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00039.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00040.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00040.png new file mode 100644 index 00000000..85360559 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00040.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00041.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00041.png new file mode 100644 index 00000000..8687e2fe Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00041.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00042.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00042.png new file mode 100644 index 00000000..31bcd68f Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00042.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00043.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00043.png new file mode 100644 index 00000000..a3ab6ac6 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00043.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00044.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00044.png new file mode 100644 index 00000000..9156a869 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00044.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00045.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00045.png new file mode 100644 index 00000000..5ea9e60d Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00045.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00046.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00046.png new file mode 100644 index 00000000..e53bd45f Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00046.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00047.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00047.png new file mode 100644 index 00000000..91ee0147 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00047.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00048.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00048.png new file mode 100644 index 00000000..e5bae5c7 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00048.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00049.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00049.png new file mode 100644 index 00000000..78438155 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00049.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00050.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00050.png new file mode 100644 index 00000000..58b9f817 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00050.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00051.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00051.png new file mode 100644 index 00000000..3a6466ce Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00051.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00052.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00052.png new file mode 100644 index 00000000..6a8633dd Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00052.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00053.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00053.png new file mode 100644 index 00000000..38a2e4c8 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00053.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00054.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00054.png new file mode 100644 index 00000000..a15acb34 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00054.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00055.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00055.png new file mode 100644 index 00000000..aac2dd94 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00055.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00056.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00056.png new file mode 100644 index 00000000..ffae201a Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00056.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00057.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00057.png new file mode 100644 index 00000000..81ec9c58 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00057.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00058.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00058.png new file mode 100644 index 00000000..09751165 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00058.png differ diff --git a/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00059.png b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00059.png new file mode 100644 index 00000000..266aaf38 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/ImageSequence/Frame_00059.png differ diff --git a/FlutterHelper/flutter_helper/assets/after.jpg b/FlutterHelper/flutter_helper/assets/after.jpg new file mode 100644 index 00000000..0de82982 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/after.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/after.png b/FlutterHelper/flutter_helper/assets/after.png new file mode 100644 index 00000000..e0f22bf6 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/after.png differ diff --git a/FlutterHelper/flutter_helper/assets/awsome.png b/FlutterHelper/flutter_helper/assets/awsome.png new file mode 100644 index 00000000..7a9712b3 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/awsome.png differ diff --git a/FlutterHelper/flutter_helper/assets/background.jpg b/FlutterHelper/flutter_helper/assets/background.jpg new file mode 100644 index 00000000..d25bab71 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/background.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/before.jpg b/FlutterHelper/flutter_helper/assets/before.jpg new file mode 100644 index 00000000..493280c8 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/before.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/before.png b/FlutterHelper/flutter_helper/assets/before.png new file mode 100644 index 00000000..afcb9f7b Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/before.png differ diff --git a/FlutterHelper/flutter_helper/assets/dart.png b/FlutterHelper/flutter_helper/assets/dart.png new file mode 100644 index 00000000..f0252b3f Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/dart.png differ diff --git a/FlutterHelper/flutter_helper/assets/data.json b/FlutterHelper/flutter_helper/assets/data.json new file mode 100644 index 00000000..82da15a8 --- /dev/null +++ b/FlutterHelper/flutter_helper/assets/data.json @@ -0,0 +1,100 @@ +[ + { + "id" : "1", + "avatar": "assets/images/hum_1.jpg", + "name": "Denny Hess", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "08:30am" + }, + { + "id" : "2", + "avatar": "assets/images/hum_2.jpg", + "name": "Adam Wyman", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "09:30pm" + }, + { + "id" : "3", + "avatar": "assets/images/hum_3.jpg", + "name": "Justin Smiths", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "06:40am" + }, + { + "id" : "4", + "avatar": "assets/images/hum_4.jpg", + "name": "Sendi Madafaka", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "05:340pm" + }, + { + "id" : "5", + "avatar": "assets/images/hum_5.jpg", + "name": "Justin Madafaka", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "05:340pm" + }, + { + "id" : "6", + "avatar": "assets/images/hum_6.jpg", + "name": "Dolares Sancos", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "05:340pm" + }, + { + "id" : "7", + "avatar": "assets/images/hum_7.jpg", + "name": "Durdi Sura", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "05:340pm" + }, + { + "id" : "8", + "avatar": "assets/images/hum_8.jpg", + "name": "Sonkara Dorsa", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "05:340pm" + }, + { + "id" : "9", + "avatar": "assets/images/hum_1.jpg", + "name": "Denny Hess", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "08:30am" + }, + { + "id" : "10", + "avatar": "assets/images/hum_2.jpg", + "name": "Adam Wyman", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "09:30pm" + }, + { + "id" : "11", + "avatar": "assets/images/hum_3.jpg", + "name": "Justin Smiths", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "06:40am" + }, + { + "id" : "12", + "avatar": "assets/images/hum_4.jpg", + "name": "Sendi Madafaka", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "05:340pm" + }, + { + "id" : "13", + "avatar": "assets/images/hum_5.jpg", + "name": "Justin Madafaka", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "05:340pm" + }, + { + "id" : "14", + "avatar": "assets/images/hum_6.jpg", + "name": "Dolares Sancos", + "message": "Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Felanlar filanlar intermilanlar.", + "time": "05:340pm" + } +] \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/assets/flutter.png b/FlutterHelper/flutter_helper/assets/flutter.png new file mode 100644 index 00000000..00357cb9 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/flutter.png differ diff --git a/FlutterHelper/flutter_helper/assets/fonts.png b/FlutterHelper/flutter_helper/assets/fonts.png new file mode 100644 index 00000000..9aa05207 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts.png differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/Quicksand-Medium.ttf b/FlutterHelper/flutter_helper/assets/fonts/Quicksand-Medium.ttf new file mode 100644 index 00000000..c0cc3b58 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/Quicksand-Medium.ttf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Bold.otf b/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Bold.otf new file mode 100755 index 00000000..4f371fa9 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Bold.otf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Book.otf b/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Book.otf new file mode 100755 index 00000000..ee8b12d7 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Book.otf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Light.otf b/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Light.otf new file mode 100755 index 00000000..798c1a74 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/Quicksand_Light.otf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/Raleway-Medium.ttf b/FlutterHelper/flutter_helper/assets/fonts/Raleway-Medium.ttf new file mode 100755 index 00000000..7a71a6ff Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/Raleway-Medium.ttf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/Raleway-Regular.ttf b/FlutterHelper/flutter_helper/assets/fonts/Raleway-Regular.ttf new file mode 100755 index 00000000..e570a2d5 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/Raleway-Regular.ttf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/line-awesome.ttf b/FlutterHelper/flutter_helper/assets/fonts/line-awesome.ttf new file mode 100644 index 00000000..8f99967b Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/line-awesome.ttf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/themify.ttf b/FlutterHelper/flutter_helper/assets/fonts/themify.ttf new file mode 100644 index 00000000..5d627e70 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/themify.ttf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/timeburnerbold.ttf b/FlutterHelper/flutter_helper/assets/fonts/timeburnerbold.ttf new file mode 100644 index 00000000..f0680418 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/timeburnerbold.ttf differ diff --git a/FlutterHelper/flutter_helper/assets/fonts/timeburnernormal.ttf b/FlutterHelper/flutter_helper/assets/fonts/timeburnernormal.ttf new file mode 100644 index 00000000..28cee22e Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/fonts/timeburnernormal.ttf differ diff --git a/FlutterHelper/flutter_helper/assets/google.png b/FlutterHelper/flutter_helper/assets/google.png new file mode 100644 index 00000000..66e07c1f Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/google.png differ diff --git a/FlutterHelper/flutter_helper/assets/hitchhiker.png b/FlutterHelper/flutter_helper/assets/hitchhiker.png new file mode 100644 index 00000000..5789131e Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/hitchhiker.png differ diff --git a/FlutterHelper/flutter_helper/assets/hitchhiker_2.png b/FlutterHelper/flutter_helper/assets/hitchhiker_2.png new file mode 100644 index 00000000..5f4887bb Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/hitchhiker_2.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/blank.jpg b/FlutterHelper/flutter_helper/assets/images/blank.jpg new file mode 100644 index 00000000..f0edff3e Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/blank.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/calendarbanner.jpg b/FlutterHelper/flutter_helper/assets/images/calendarbanner.jpg new file mode 100644 index 00000000..fec1f432 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/calendarbanner.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/calendarheader.png b/FlutterHelper/flutter_helper/assets/images/calendarheader.png new file mode 100644 index 00000000..00efad34 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/calendarheader.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/concave.png b/FlutterHelper/flutter_helper/assets/images/concave.png new file mode 100644 index 00000000..33263602 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/concave.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/convex.png b/FlutterHelper/flutter_helper/assets/images/convex.png new file mode 100644 index 00000000..1ec8fe15 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/convex.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/credit_card_chip.png b/FlutterHelper/flutter_helper/assets/images/credit_card_chip.png new file mode 100644 index 00000000..59dc0278 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/credit_card_chip.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/dashboard.jpg b/FlutterHelper/flutter_helper/assets/images/dashboard.jpg new file mode 100644 index 00000000..b8023a07 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/dashboard.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/emma-watson.jpg b/FlutterHelper/flutter_helper/assets/images/emma-watson.jpg new file mode 100644 index 00000000..73557156 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/emma-watson.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/flat.png b/FlutterHelper/flutter_helper/assets/images/flat.png new file mode 100644 index 00000000..82157416 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/flat.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_0.jpg b/FlutterHelper/flutter_helper/assets/images/hum_0.jpg new file mode 100644 index 00000000..697f9608 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_0.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_1.jpg b/FlutterHelper/flutter_helper/assets/images/hum_1.jpg new file mode 100644 index 00000000..51bdd295 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_1.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_10.jpg b/FlutterHelper/flutter_helper/assets/images/hum_10.jpg new file mode 100644 index 00000000..7a80cd6e Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_10.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_2.jpg b/FlutterHelper/flutter_helper/assets/images/hum_2.jpg new file mode 100644 index 00000000..7c3becc9 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_2.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_3.jpg b/FlutterHelper/flutter_helper/assets/images/hum_3.jpg new file mode 100644 index 00000000..b8c82adb Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_3.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_4.jpg b/FlutterHelper/flutter_helper/assets/images/hum_4.jpg new file mode 100644 index 00000000..5add8366 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_4.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_5.jpg b/FlutterHelper/flutter_helper/assets/images/hum_5.jpg new file mode 100644 index 00000000..05c2913c Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_5.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_6.jpg b/FlutterHelper/flutter_helper/assets/images/hum_6.jpg new file mode 100644 index 00000000..d65ff50d Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_6.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_7.jpg b/FlutterHelper/flutter_helper/assets/images/hum_7.jpg new file mode 100644 index 00000000..08797d27 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_7.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_8.jpg b/FlutterHelper/flutter_helper/assets/images/hum_8.jpg new file mode 100644 index 00000000..a6d7506e Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_8.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/hum_9.jpg b/FlutterHelper/flutter_helper/assets/images/hum_9.jpg new file mode 100644 index 00000000..4abc14a5 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/hum_9.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/img_dribbble.gif b/FlutterHelper/flutter_helper/assets/images/img_dribbble.gif new file mode 100644 index 00000000..4a425532 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/img_dribbble.gif differ diff --git a/FlutterHelper/flutter_helper/assets/images/img_flutter.gif b/FlutterHelper/flutter_helper/assets/images/img_flutter.gif new file mode 100644 index 00000000..b0847630 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/img_flutter.gif differ diff --git a/FlutterHelper/flutter_helper/assets/images/joystick.png b/FlutterHelper/flutter_helper/assets/images/joystick.png new file mode 100644 index 00000000..76032ab7 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/joystick.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/login.jpg b/FlutterHelper/flutter_helper/assets/images/login.jpg new file mode 100644 index 00000000..9f3af9f0 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/login.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/map.jpg b/FlutterHelper/flutter_helper/assets/images/map.jpg new file mode 100644 index 00000000..439b9a46 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/map.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/map.png b/FlutterHelper/flutter_helper/assets/images/map.png new file mode 100644 index 00000000..83f8f170 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/map.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/microphone.png b/FlutterHelper/flutter_helper/assets/images/microphone.png new file mode 100644 index 00000000..781e7d03 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/microphone.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/package_delivery_tracking.png b/FlutterHelper/flutter_helper/assets/images/package_delivery_tracking.png new file mode 100644 index 00000000..4e4896a2 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/package_delivery_tracking.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/payment.jpg b/FlutterHelper/flutter_helper/assets/images/payment.jpg new file mode 100644 index 00000000..c991a4bd Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/payment.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/pk.jpg b/FlutterHelper/flutter_helper/assets/images/pk.jpg new file mode 100644 index 00000000..16d3449f Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/pk.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/process_timeline.png b/FlutterHelper/flutter_helper/assets/images/process_timeline.png new file mode 100644 index 00000000..1f7e9247 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/process_timeline.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/process_timeline/status1.png b/FlutterHelper/flutter_helper/assets/images/process_timeline/status1.png new file mode 100644 index 00000000..66872c60 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/process_timeline/status1.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/process_timeline/status2.png b/FlutterHelper/flutter_helper/assets/images/process_timeline/status2.png new file mode 100644 index 00000000..8e5f6be9 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/process_timeline/status2.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/process_timeline/status3.png b/FlutterHelper/flutter_helper/assets/images/process_timeline/status3.png new file mode 100644 index 00000000..607d9d8a Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/process_timeline/status3.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/process_timeline/status4.png b/FlutterHelper/flutter_helper/assets/images/process_timeline/status4.png new file mode 100644 index 00000000..d2d8b258 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/process_timeline/status4.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/process_timeline/status5.png b/FlutterHelper/flutter_helper/assets/images/process_timeline/status5.png new file mode 100644 index 00000000..bfaaed8d Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/process_timeline/status5.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/profile.jpg b/FlutterHelper/flutter_helper/assets/images/profile.jpg new file mode 100644 index 00000000..13851eca Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/profile.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/setting.jpeg b/FlutterHelper/flutter_helper/assets/images/setting.jpeg new file mode 100644 index 00000000..269c1094 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/setting.jpeg differ diff --git a/FlutterHelper/flutter_helper/assets/images/shopping.jpeg b/FlutterHelper/flutter_helper/assets/images/shopping.jpeg new file mode 100644 index 00000000..1d7fe7f0 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/shopping.jpeg differ diff --git a/FlutterHelper/flutter_helper/assets/images/tesla.png b/FlutterHelper/flutter_helper/assets/images/tesla.png new file mode 100644 index 00000000..bd73cd6c Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/tesla.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/tesla_cropped.png b/FlutterHelper/flutter_helper/assets/images/tesla_cropped.png new file mode 100644 index 00000000..4383733d Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/tesla_cropped.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/timeline.jpeg b/FlutterHelper/flutter_helper/assets/images/timeline.jpeg new file mode 100644 index 00000000..0836e7f6 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/timeline.jpeg differ diff --git a/FlutterHelper/flutter_helper/assets/images/timeline_status.png b/FlutterHelper/flutter_helper/assets/images/timeline_status.png new file mode 100644 index 00000000..93855441 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/timeline_status.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/verification.jpg b/FlutterHelper/flutter_helper/assets/images/verification.jpg new file mode 100644 index 00000000..311e3871 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/verification.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/images/wallet.png b/FlutterHelper/flutter_helper/assets/images/wallet.png new file mode 100644 index 00000000..160e25e9 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/wallet.png differ diff --git a/FlutterHelper/flutter_helper/assets/images/weeknd.jpg b/FlutterHelper/flutter_helper/assets/images/weeknd.jpg new file mode 100644 index 00000000..80c3f182 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/images/weeknd.jpg differ diff --git a/FlutterHelper/flutter_helper/assets/navigation_route.png b/FlutterHelper/flutter_helper/assets/navigation_route.png new file mode 100644 index 00000000..a36d41a7 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/navigation_route.png differ diff --git a/FlutterHelper/flutter_helper/assets/scratch.png b/FlutterHelper/flutter_helper/assets/scratch.png new file mode 100644 index 00000000..e5785cf1 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/scratch.png differ diff --git a/FlutterHelper/flutter_helper/assets/simform.png b/FlutterHelper/flutter_helper/assets/simform.png new file mode 100644 index 00000000..95efa540 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/simform.png differ diff --git a/FlutterHelper/flutter_helper/assets/timezone/2018c.tzf b/FlutterHelper/flutter_helper/assets/timezone/2018c.tzf new file mode 100644 index 00000000..2ccd0d9e Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/timezone/2018c.tzf differ diff --git a/FlutterHelper/flutter_helper/assets/todo.png b/FlutterHelper/flutter_helper/assets/todo.png new file mode 100644 index 00000000..78c9364e Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/todo.png differ diff --git a/FlutterHelper/flutter_helper/assets/twilight_sparkle.png b/FlutterHelper/flutter_helper/assets/twilight_sparkle.png new file mode 100644 index 00000000..9482ca19 Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/twilight_sparkle.png differ diff --git a/FlutterHelper/flutter_helper/assets/unseen.ttf b/FlutterHelper/flutter_helper/assets/unseen.ttf new file mode 100755 index 00000000..e6ffa26d Binary files /dev/null and b/FlutterHelper/flutter_helper/assets/unseen.ttf differ diff --git a/FlutterHelper/flutter_helper/fonts/NeumorphicIcons.ttf b/FlutterHelper/flutter_helper/fonts/NeumorphicIcons.ttf new file mode 100755 index 00000000..75dccf31 Binary files /dev/null and b/FlutterHelper/flutter_helper/fonts/NeumorphicIcons.ttf differ diff --git a/FlutterHelper/flutter_helper/fonts/OpenSans-ExtraBold.ttf b/FlutterHelper/flutter_helper/fonts/OpenSans-ExtraBold.ttf new file mode 100644 index 00000000..3660681d Binary files /dev/null and b/FlutterHelper/flutter_helper/fonts/OpenSans-ExtraBold.ttf differ diff --git a/FlutterHelper/flutter_helper/fonts/SamsungSans-Bold.ttf b/FlutterHelper/flutter_helper/fonts/SamsungSans-Bold.ttf new file mode 100644 index 00000000..bf84b52d Binary files /dev/null and b/FlutterHelper/flutter_helper/fonts/SamsungSans-Bold.ttf differ diff --git a/FlutterHelper/flutter_helper/fonts/Satisfy-Regular.ttf b/FlutterHelper/flutter_helper/fonts/Satisfy-Regular.ttf new file mode 100644 index 00000000..d4287888 Binary files /dev/null and b/FlutterHelper/flutter_helper/fonts/Satisfy-Regular.ttf differ diff --git a/FlutterHelper/flutter_helper/fonts/fontYouandiModernTR.ttf b/FlutterHelper/flutter_helper/fonts/fontYouandiModernTR.ttf new file mode 100644 index 00000000..51b811da Binary files /dev/null and b/FlutterHelper/flutter_helper/fonts/fontYouandiModernTR.ttf differ diff --git a/FlutterHelper/flutter_helper/fonts/neumorphic_icons_config.json b/FlutterHelper/flutter_helper/fonts/neumorphic_icons_config.json new file mode 100755 index 00000000..be21936b --- /dev/null +++ b/FlutterHelper/flutter_helper/fonts/neumorphic_icons_config.json @@ -0,0 +1,16 @@ +{ + "name": "NeumorphicIcons", + "css_prefix_text": "", + "css_use_suffix": false, + "hinting": true, + "units_per_em": 1000, + "ascent": 850, + "glyphs": [ + { + "uid": "83b1dd96a1760c9d049edbba9b96f2b2", + "css": "check", + "code": 59392, + "src": "material" + } + ] +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/google_fonts/Lato-Bold.ttf b/FlutterHelper/flutter_helper/google_fonts/Lato-Bold.ttf new file mode 100755 index 00000000..b63a14d6 Binary files /dev/null and b/FlutterHelper/flutter_helper/google_fonts/Lato-Bold.ttf differ diff --git a/FlutterHelper/flutter_helper/google_fonts/Lato-BoldItalic.ttf b/FlutterHelper/flutter_helper/google_fonts/Lato-BoldItalic.ttf new file mode 100755 index 00000000..8f9a50d1 Binary files /dev/null and b/FlutterHelper/flutter_helper/google_fonts/Lato-BoldItalic.ttf differ diff --git a/FlutterHelper/flutter_helper/google_fonts/Lato-Italic.ttf b/FlutterHelper/flutter_helper/google_fonts/Lato-Italic.ttf new file mode 100755 index 00000000..49e9f2c3 Binary files /dev/null and b/FlutterHelper/flutter_helper/google_fonts/Lato-Italic.ttf differ diff --git a/FlutterHelper/flutter_helper/google_fonts/Lato-Regular.ttf b/FlutterHelper/flutter_helper/google_fonts/Lato-Regular.ttf new file mode 100755 index 00000000..33eba8b1 Binary files /dev/null and b/FlutterHelper/flutter_helper/google_fonts/Lato-Regular.ttf differ diff --git a/FlutterHelper/flutter_helper/images/1.png b/FlutterHelper/flutter_helper/images/1.png new file mode 100644 index 00000000..aef6ae69 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/1.png differ diff --git a/FlutterHelper/flutter_helper/images/2.png b/FlutterHelper/flutter_helper/images/2.png new file mode 100644 index 00000000..601f39f9 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/2.png differ diff --git a/FlutterHelper/flutter_helper/images/3.png b/FlutterHelper/flutter_helper/images/3.png new file mode 100644 index 00000000..02ea8bde Binary files /dev/null and b/FlutterHelper/flutter_helper/images/3.png differ diff --git a/FlutterHelper/flutter_helper/images/4.png b/FlutterHelper/flutter_helper/images/4.png new file mode 100644 index 00000000..8e160c30 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/4.png differ diff --git a/FlutterHelper/flutter_helper/images/amex.png b/FlutterHelper/flutter_helper/images/amex.png new file mode 100644 index 00000000..50dfd2ad Binary files /dev/null and b/FlutterHelper/flutter_helper/images/amex.png differ diff --git a/FlutterHelper/flutter_helper/images/angry.gif b/FlutterHelper/flutter_helper/images/angry.gif new file mode 100644 index 00000000..4565ef3a Binary files /dev/null and b/FlutterHelper/flutter_helper/images/angry.gif differ diff --git a/FlutterHelper/flutter_helper/images/angry2.png b/FlutterHelper/flutter_helper/images/angry2.png new file mode 100644 index 00000000..3d5ca48d Binary files /dev/null and b/FlutterHelper/flutter_helper/images/angry2.png differ diff --git a/FlutterHelper/flutter_helper/images/banner.png b/FlutterHelper/flutter_helper/images/banner.png new file mode 100644 index 00000000..9c55dad4 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/banner.png differ diff --git a/FlutterHelper/flutter_helper/images/beatiful_lady.jpeg b/FlutterHelper/flutter_helper/images/beatiful_lady.jpeg new file mode 100644 index 00000000..5a3a3b77 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/beatiful_lady.jpeg differ diff --git a/FlutterHelper/flutter_helper/images/bird.png b/FlutterHelper/flutter_helper/images/bird.png new file mode 100644 index 00000000..53f9d556 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/bird.png differ diff --git a/FlutterHelper/flutter_helper/images/bossapp2x.png b/FlutterHelper/flutter_helper/images/bossapp2x.png new file mode 100644 index 00000000..d316f538 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/bossapp2x.png differ diff --git a/FlutterHelper/flutter_helper/images/checkmark.png b/FlutterHelper/flutter_helper/images/checkmark.png new file mode 100644 index 00000000..9c1e96ac Binary files /dev/null and b/FlutterHelper/flutter_helper/images/checkmark.png differ diff --git a/FlutterHelper/flutter_helper/images/discover.png b/FlutterHelper/flutter_helper/images/discover.png new file mode 100644 index 00000000..dc22664e Binary files /dev/null and b/FlutterHelper/flutter_helper/images/discover.png differ diff --git a/FlutterHelper/flutter_helper/images/ellie.png b/FlutterHelper/flutter_helper/images/ellie.png new file mode 100644 index 00000000..f49e341f Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ellie.png differ diff --git a/FlutterHelper/flutter_helper/images/eric.png b/FlutterHelper/flutter_helper/images/eric.png new file mode 100644 index 00000000..8eb931ce Binary files /dev/null and b/FlutterHelper/flutter_helper/images/eric.png differ diff --git a/FlutterHelper/flutter_helper/images/flutter_cover.png b/FlutterHelper/flutter_helper/images/flutter_cover.png new file mode 100644 index 00000000..47666b39 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/flutter_cover.png differ diff --git a/FlutterHelper/flutter_helper/images/github.png b/FlutterHelper/flutter_helper/images/github.png new file mode 100644 index 00000000..b0507749 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/github.png differ diff --git a/FlutterHelper/flutter_helper/images/haha.gif b/FlutterHelper/flutter_helper/images/haha.gif new file mode 100644 index 00000000..883ee322 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/haha.gif differ diff --git a/FlutterHelper/flutter_helper/images/haha2.png b/FlutterHelper/flutter_helper/images/haha2.png new file mode 100644 index 00000000..38df2822 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/haha2.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_like.png b/FlutterHelper/flutter_helper/images/ic_like.png new file mode 100644 index 00000000..3e7e5106 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_like.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_like_fill.png b/FlutterHelper/flutter_helper/images/ic_like_fill.png new file mode 100644 index 00000000..e24ea84d Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_like_fill.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_main_tab_company_nor.png b/FlutterHelper/flutter_helper/images/ic_main_tab_company_nor.png new file mode 100755 index 00000000..371d5ac1 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_main_tab_company_nor.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_main_tab_company_pre.png b/FlutterHelper/flutter_helper/images/ic_main_tab_company_pre.png new file mode 100755 index 00000000..83c709f9 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_main_tab_company_pre.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_main_tab_contacts_nor.png b/FlutterHelper/flutter_helper/images/ic_main_tab_contacts_nor.png new file mode 100755 index 00000000..fbcc9d58 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_main_tab_contacts_nor.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_main_tab_contacts_pre.png b/FlutterHelper/flutter_helper/images/ic_main_tab_contacts_pre.png new file mode 100755 index 00000000..17ad70f0 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_main_tab_contacts_pre.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_main_tab_find_nor.png b/FlutterHelper/flutter_helper/images/ic_main_tab_find_nor.png new file mode 100755 index 00000000..89c6433d Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_main_tab_find_nor.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_main_tab_find_pre.png b/FlutterHelper/flutter_helper/images/ic_main_tab_find_pre.png new file mode 100755 index 00000000..7bc21fd7 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_main_tab_find_pre.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_main_tab_my_nor.png b/FlutterHelper/flutter_helper/images/ic_main_tab_my_nor.png new file mode 100755 index 00000000..0766c144 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_main_tab_my_nor.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_main_tab_my_pre.png b/FlutterHelper/flutter_helper/images/ic_main_tab_my_pre.png new file mode 100755 index 00000000..94e689cd Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_main_tab_my_pre.png differ diff --git a/FlutterHelper/flutter_helper/images/ic_purchase_history_blank.jpeg b/FlutterHelper/flutter_helper/images/ic_purchase_history_blank.jpeg new file mode 100644 index 00000000..7720479c Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_purchase_history_blank.jpeg differ diff --git a/FlutterHelper/flutter_helper/images/ic_purchase_history_blank.png b/FlutterHelper/flutter_helper/images/ic_purchase_history_blank.png new file mode 100644 index 00000000..b1284412 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_purchase_history_blank.png differ diff --git a/multilanguage/src/main/res/drawable/ic_purchase_history_blank.webp b/FlutterHelper/flutter_helper/images/ic_purchase_history_blank.webp similarity index 100% rename from multilanguage/src/main/res/drawable/ic_purchase_history_blank.webp rename to FlutterHelper/flutter_helper/images/ic_purchase_history_blank.webp diff --git a/FlutterHelper/flutter_helper/images/ic_trip.png b/FlutterHelper/flutter_helper/images/ic_trip.png new file mode 100644 index 00000000..9c938e1a Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ic_trip.png differ diff --git a/FlutterHelper/flutter_helper/images/image_-pet-wild.png b/FlutterHelper/flutter_helper/images/image_-pet-wild.png new file mode 100644 index 00000000..a1c79ca8 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_-pet-wild.png differ diff --git a/FlutterHelper/flutter_helper/images/image_1111.png b/FlutterHelper/flutter_helper/images/image_1111.png new file mode 100644 index 00000000..4046de2a Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_1111.png differ diff --git a/FlutterHelper/flutter_helper/images/image_2222.png b/FlutterHelper/flutter_helper/images/image_2222.png new file mode 100644 index 00000000..897018c4 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_2222.png differ diff --git a/FlutterHelper/flutter_helper/images/image_3333.png b/FlutterHelper/flutter_helper/images/image_3333.png new file mode 100644 index 00000000..0c8f2c9c Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_3333.png differ diff --git a/FlutterHelper/flutter_helper/images/image_and_nature.png b/FlutterHelper/flutter_helper/images/image_and_nature.png new file mode 100644 index 00000000..d99e7bdf Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_and_nature.png differ diff --git a/FlutterHelper/flutter_helper/images/image_animaltest.png b/FlutterHelper/flutter_helper/images/image_animaltest.png new file mode 100644 index 00000000..11beacd1 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_animaltest.png differ diff --git a/FlutterHelper/flutter_helper/images/image_domestic_3204653.png b/FlutterHelper/flutter_helper/images/image_domestic_3204653.png new file mode 100644 index 00000000..03e4039d Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_domestic_3204653.png differ diff --git a/FlutterHelper/flutter_helper/images/image_eye_care.png b/FlutterHelper/flutter_helper/images/image_eye_care.png new file mode 100644 index 00000000..062aa2ac Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_eye_care.png differ diff --git a/FlutterHelper/flutter_helper/images/image_hospital.png b/FlutterHelper/flutter_helper/images/image_hospital.png new file mode 100644 index 00000000..0a230858 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/image_hospital.png differ diff --git a/FlutterHelper/flutter_helper/images/ipad.gif b/FlutterHelper/flutter_helper/images/ipad.gif new file mode 100644 index 00000000..3e63fc59 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/ipad.gif differ diff --git a/FlutterHelper/flutter_helper/images/jenny.png b/FlutterHelper/flutter_helper/images/jenny.png new file mode 100644 index 00000000..184f6ebd Binary files /dev/null and b/FlutterHelper/flutter_helper/images/jenny.png differ diff --git a/FlutterHelper/flutter_helper/images/kevin.png b/FlutterHelper/flutter_helper/images/kevin.png new file mode 100644 index 00000000..ad8f7f7e Binary files /dev/null and b/FlutterHelper/flutter_helper/images/kevin.png differ diff --git a/FlutterHelper/flutter_helper/images/like.gif b/FlutterHelper/flutter_helper/images/like.gif new file mode 100644 index 00000000..a3a4db8c Binary files /dev/null and b/FlutterHelper/flutter_helper/images/like.gif differ diff --git a/FlutterHelper/flutter_helper/images/louis.png b/FlutterHelper/flutter_helper/images/louis.png new file mode 100644 index 00000000..6cedde0b Binary files /dev/null and b/FlutterHelper/flutter_helper/images/louis.png differ diff --git a/FlutterHelper/flutter_helper/images/love.gif b/FlutterHelper/flutter_helper/images/love.gif new file mode 100644 index 00000000..7cca3812 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/love.gif differ diff --git a/FlutterHelper/flutter_helper/images/love2.png b/FlutterHelper/flutter_helper/images/love2.png new file mode 100644 index 00000000..427bacb4 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/love2.png differ diff --git a/FlutterHelper/flutter_helper/images/mastercard.png b/FlutterHelper/flutter_helper/images/mastercard.png new file mode 100644 index 00000000..0188fb44 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/mastercard.png differ diff --git a/FlutterHelper/flutter_helper/images/mytemplate.png b/FlutterHelper/flutter_helper/images/mytemplate.png new file mode 100644 index 00000000..426aa4d9 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/mytemplate.png differ diff --git a/FlutterHelper/flutter_helper/images/others.png b/FlutterHelper/flutter_helper/images/others.png new file mode 100644 index 00000000..272c19c1 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/others.png differ diff --git a/FlutterHelper/flutter_helper/images/phoneusage.gif b/FlutterHelper/flutter_helper/images/phoneusage.gif new file mode 100644 index 00000000..02334dd7 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/phoneusage.gif differ diff --git a/FlutterHelper/flutter_helper/images/poster.png b/FlutterHelper/flutter_helper/images/poster.png new file mode 100644 index 00000000..35092d29 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/poster.png differ diff --git a/FlutterHelper/flutter_helper/images/sad.gif b/FlutterHelper/flutter_helper/images/sad.gif new file mode 100644 index 00000000..25230e1a Binary files /dev/null and b/FlutterHelper/flutter_helper/images/sad.gif differ diff --git a/FlutterHelper/flutter_helper/images/sad2.png b/FlutterHelper/flutter_helper/images/sad2.png new file mode 100644 index 00000000..7d241ac3 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/sad2.png differ diff --git a/FlutterHelper/flutter_helper/images/show.gif b/FlutterHelper/flutter_helper/images/show.gif new file mode 100644 index 00000000..b724e6f5 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/show.gif differ diff --git a/FlutterHelper/flutter_helper/images/type_channelgroup.png b/FlutterHelper/flutter_helper/images/type_channelgroup.png new file mode 100644 index 00000000..40fd73a1 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_channelgroup.png differ diff --git a/FlutterHelper/flutter_helper/images/type_channelgs.png b/FlutterHelper/flutter_helper/images/type_channelgs.png new file mode 100644 index 00000000..4bb4377f Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_channelgs.png differ diff --git a/FlutterHelper/flutter_helper/images/type_channelplane.png b/FlutterHelper/flutter_helper/images/type_channelplane.png new file mode 100644 index 00000000..a168ad32 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_channelplane.png differ diff --git a/FlutterHelper/flutter_helper/images/type_channeltrain.png b/FlutterHelper/flutter_helper/images/type_channeltrain.png new file mode 100644 index 00000000..1b77530a Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_channeltrain.png differ diff --git a/FlutterHelper/flutter_helper/images/type_cruise.png b/FlutterHelper/flutter_helper/images/type_cruise.png new file mode 100644 index 00000000..98e74d6e Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_cruise.png differ diff --git a/FlutterHelper/flutter_helper/images/type_district.png b/FlutterHelper/flutter_helper/images/type_district.png new file mode 100644 index 00000000..3a5db15c Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_district.png differ diff --git a/FlutterHelper/flutter_helper/images/type_food.png b/FlutterHelper/flutter_helper/images/type_food.png new file mode 100644 index 00000000..ec7217e9 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_food.png differ diff --git a/FlutterHelper/flutter_helper/images/type_hotel.png b/FlutterHelper/flutter_helper/images/type_hotel.png new file mode 100644 index 00000000..d9a08a7f Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_hotel.png differ diff --git a/FlutterHelper/flutter_helper/images/type_huodong.png b/FlutterHelper/flutter_helper/images/type_huodong.png new file mode 100644 index 00000000..87d497c3 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_huodong.png differ diff --git a/FlutterHelper/flutter_helper/images/type_shop.png b/FlutterHelper/flutter_helper/images/type_shop.png new file mode 100644 index 00000000..51fd82b1 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_shop.png differ diff --git a/FlutterHelper/flutter_helper/images/type_sight.png b/FlutterHelper/flutter_helper/images/type_sight.png new file mode 100644 index 00000000..3d24cd39 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_sight.png differ diff --git a/FlutterHelper/flutter_helper/images/type_ticket.png b/FlutterHelper/flutter_helper/images/type_ticket.png new file mode 100644 index 00000000..c780ce75 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_ticket.png differ diff --git a/FlutterHelper/flutter_helper/images/type_travelgroup.png b/FlutterHelper/flutter_helper/images/type_travelgroup.png new file mode 100644 index 00000000..f96a1ba3 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/type_travelgroup.png differ diff --git a/FlutterHelper/flutter_helper/images/visacard.png b/FlutterHelper/flutter_helper/images/visacard.png new file mode 100644 index 00000000..f83fcab9 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/visacard.png differ diff --git a/FlutterHelper/flutter_helper/images/wow.gif b/FlutterHelper/flutter_helper/images/wow.gif new file mode 100644 index 00000000..36f7cb79 Binary files /dev/null and b/FlutterHelper/flutter_helper/images/wow.gif differ diff --git a/FlutterHelper/flutter_helper/images/wow2.png b/FlutterHelper/flutter_helper/images/wow2.png new file mode 100644 index 00000000..7568e7ed Binary files /dev/null and b/FlutterHelper/flutter_helper/images/wow2.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/authentication.png b/FlutterHelper/flutter_helper/img/bg/authentication.png new file mode 100644 index 00000000..fe3cec09 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/authentication.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/camera.png b/FlutterHelper/flutter_helper/img/bg/camera.png new file mode 100644 index 00000000..bcee7865 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/camera.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/coin.png b/FlutterHelper/flutter_helper/img/bg/coin.png new file mode 100644 index 00000000..93748bd9 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/coin.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/fail.png b/FlutterHelper/flutter_helper/img/bg/fail.png new file mode 100644 index 00000000..fec1ac52 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/fail.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/geolocation.png b/FlutterHelper/flutter_helper/img/bg/geolocation.png new file mode 100644 index 00000000..697f57c0 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/geolocation.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/gift.png b/FlutterHelper/flutter_helper/img/bg/gift.png new file mode 100644 index 00000000..80996a46 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/gift.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/notification.png b/FlutterHelper/flutter_helper/img/bg/notification.png new file mode 100644 index 00000000..077c54b0 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/notification.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/red_packet.png b/FlutterHelper/flutter_helper/img/bg/red_packet.png new file mode 100644 index 00000000..b8c245f3 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/red_packet.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/rocket_blue.png b/FlutterHelper/flutter_helper/img/bg/rocket_blue.png new file mode 100644 index 00000000..9e0ed889 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/rocket_blue.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/rocket_green.png b/FlutterHelper/flutter_helper/img/bg/rocket_green.png new file mode 100644 index 00000000..4e4b08d2 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/rocket_green.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/rocket_orange.png b/FlutterHelper/flutter_helper/img/bg/rocket_orange.png new file mode 100644 index 00000000..6c3bf884 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/rocket_orange.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/rocket_orange_2.png b/FlutterHelper/flutter_helper/img/bg/rocket_orange_2.png new file mode 100644 index 00000000..5f54dbdb Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/rocket_orange_2.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/success.png b/FlutterHelper/flutter_helper/img/bg/success.png new file mode 100644 index 00000000..7c22515f Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/success.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/term.png b/FlutterHelper/flutter_helper/img/bg/term.png new file mode 100644 index 00000000..aff324dc Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/term.png differ diff --git a/FlutterHelper/flutter_helper/img/bg/thumb.png b/FlutterHelper/flutter_helper/img/bg/thumb.png new file mode 100644 index 00000000..a70a0ce6 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/bg/thumb.png differ diff --git a/FlutterHelper/flutter_helper/img/p1.jpg b/FlutterHelper/flutter_helper/img/p1.jpg new file mode 100644 index 00000000..0e34ed44 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/p1.jpg differ diff --git a/FlutterHelper/flutter_helper/img/p2.jpg b/FlutterHelper/flutter_helper/img/p2.jpg new file mode 100644 index 00000000..7e595f8e Binary files /dev/null and b/FlutterHelper/flutter_helper/img/p2.jpg differ diff --git a/FlutterHelper/flutter_helper/img/p3.jpg b/FlutterHelper/flutter_helper/img/p3.jpg new file mode 100644 index 00000000..f1e609b1 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/p3.jpg differ diff --git a/FlutterHelper/flutter_helper/img/p4.jpg b/FlutterHelper/flutter_helper/img/p4.jpg new file mode 100644 index 00000000..35cd5e67 Binary files /dev/null and b/FlutterHelper/flutter_helper/img/p4.jpg differ diff --git a/FlutterHelper/flutter_helper/img/source/gift.ai b/FlutterHelper/flutter_helper/img/source/gift.ai new file mode 100644 index 00000000..fda7d624 --- /dev/null +++ b/FlutterHelper/flutter_helper/img/source/gift.ai @@ -0,0 +1,4455 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[7 0 R 8 0 R 9 0 R 165 0 R 166 0 R 233 0 R 234 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + Promotion Popup + + + + + 2019-12-03T22:40:50+08:00 + 2019-12-03T22:40:50+08:00 + 2018-07-30T22:21:53-04:00 + Adobe Illustrator CC 2015 (Windows) + + + + 188 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAC8AwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYqtkkSJC7nio6k5TqNRDDAzmeGI/Hz7h1TGJJoKA+tT71NvEeg29Q/OtQuayP5rU72cGI+7xD7 7sQ91GX9Utnpj/SP2ftXCxterJ6h8ZCXP/DVyyPYul5yh4h75kz/AN1a+NLoa92zjY2Z/wB0ovuo Cn7xTJS7F0Z/yUB/VHCfnGijxp95aME8W8EhYf76lJYfQ32h+OVnRZ8O+CZI/mZCZD4S+uPxMh5J 4wfqHyXwXCy1UgpIv2426j+o98ydHro5riQYZI/VA8x+sd0hsWM4V7lXM5g7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FUm1HW9Nsil1fSUjqRaxAVJpsZKfqzlp6/DPINRlN4wT4Uau62OT 48odw35yc/BpMmT0wG/X9SK0zXdK1Mf6HOrsNzGdmH0H+GbvSdo4dRtCW/cdj8mnUaPLh+sUj8zn GdiqB1PXNL01a3k6xseidWP0DMLV9o4dP9ct+7mfk5On0mTL9AtD2Or6drCGXT5P9Ig3AYUND2Pi pzWSzY9aOPAeHUY/pvb/ADZd8Zcj3c+Ybc2myYDUx6SmcEoliWQCleqnqCNiD8jm30eqGfEMgFX0 6gjYg+YOzhzjwml+ZLF2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KqN4zC3ZVNGkIjU+Bcha/ RXNb2vOQ05jE1KZjAf58hG/hdtmIer3b/JgfnK0uf0m5mjP1XiiW5oeHFVGwPzrnFdvYMmLPyrGA BDuoDk9L2Xkj4Yo+rqxlba5tphPZylJFNVoaEEe+azHqqIPIjqHbnJGYqY2ZXD+Yt1DpbLcW3PUk IVSdkZe7mnh7Z1eD2jIxVIcWToeh9/n97pJ9hxlk9Mv3f2+5dN+Ys0ulKLe346nISrAboo7OK+PY HDn9oz4VRHDk69w93n9yIdhgZfUf3Y+fuYk9vdXUzT3speRzViTUk/POUyaqyTzJ6l3gnGA4YDZk vk22ul1aF7aMiBAwmah48SDsT882fs9DNLVCcQeHfiPSqdR2pkicREjv0Z3F8F3NH+y4EoHufhb9 QzsNKPC1eXH/AAzEcg959Mv9zE++ReblvEH4IjNs1OxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxViv5nXN5a+S7+4s5XguIuDJLEzI6/EN1ZaEZq+0wf3f/DP97Kvtp3Xs/jhPVwjMAxN7Hk+f284 +bmBVtb1Ag9QbqYj/iWRM5EUS+nDsvSj/JY/9JH9SFbXdbc8m1C5Zj1JmkJ/XmLLSYZGzCJ+Abho 8I5Qj8g0dZ1g9b64P/PV/wCuR/JYP5kP9KE/lcX8yPyDhrOsAUF9cAf8ZX/rj+SwfzIf6UL+Vxfz I/INrrmtqarqFyp8RNID+vDHSYQbEIj4BB0eE/wR+QRS+cPNygKut6gFHQC6mA/4lmWJkCgWk9l6 U/5LH/pI/qeofkdq+s6ld6s2o3txeiKOERG4leXjUvy48yaVoK0yrCSdZEn/AFOf+6xvHe12lxYo 4/DjGFmV8IA7u561m7eIdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqWeZ9KGreX9Q079q5gd EPg1Ph/HMDtPEZ4Dw7yjUgO8xIlX+dVfFzOz9T4GeGT+bIPkS61extbiW2uGaOeF2jljKNVXQ0YH bsRmND1xEo7g7h9fGuwkXxfYf1KX+IdJ/wB/H/gG/pkuA9yfz2H+d9h/Ui9MvItUna3sA9xMqmRk RGqFBAJ3HiwynPljiFzPCEHX4R/F9h/Ur6mk+lwLcX8MlvCzCNXdGoWIJA29lOV4NVjymoSEigdo YD/F9h/Ulv8AiHSf9/H/AIBv6ZlcB7mX57D/ADvsP6nf4h0n/fx/4Bv6Y8B7l/PYf532H9T6J/Ij S/R8qPqhBH6Tk5wkgqfST4VND4mpwdnxMss59BUB7xvKvmB74l889q9bHNnEYmxAfaXpWbd5Z2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV86/85AflXcw3svm7R4TJazfFqsCDeNx/u4Afsn9 rw6+OaWvy2TgP93M+k9xP8B+P0f6Xao31vYvaIlHwpH1Dl5vCioPUZmPQUzr8nYQ3me6oaf6FJ/y dizn/aQ/4PH+uPuk0Z9gyT844nXyzbdx9dTp/wAYpc1Xs2f8Il/UP3xa8JsvHM7ZvZp+V35bal52 12OFUaPSLdg2o3fQBevpqe7t+HXMTUZzYx498suX9EfzpeQ/2R2HeMLW6yOCFnn0D7JsbK2sbOCy tYxFbWyLFDGuwVEFABmy0+COKAhHkPt7yfMnc+bw2SZnIyPMq+XMHYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FWpI0kRkkUOjCjKwqCD2IyGTHGcTGQuJ6FIJBsPGPPn/OOOk6pNJf+Wpl026c lms3BNuxP8tN4/oqPbNWdNmw/QfEh3E+oe6X8X+dR75l6HR9vGI4covz6sR8i/lb538r+ZLibU9O Y2rWrxJc25EyM5kjYCifGNlPVc0fbs5ZcIiITEhK94nuP8W8flIu3l2jgyR9Mh8dk2/MXyd5o8wa LbWWk6bPPcLdpIylTGAgjkUsWk4L1Yd81vYQlizGUoyoxraMpb2P5oKMesxQNykPmg/KH/OMupTy pceabtLe3FCbO1PORvZpCOK/RX551wGfLtGPhj+dLc/CIP8AuiK/mlxNV29ACsY4j9j3zQvL+j6D psWnaTapa2kQ+GNB1Pix6knxOZ2m0sMINbyPOR5y9/6hQHQAPMZ888suKRsphmS0uxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV 2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV 2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kpfea3aWtwYJFcsKElQKb79yM0et7fwabL4cxKx3AVv8 XKxaSU42KVLbV7G4IVJKOf2W2P45kaTtnTag1CXq7jsfx7mGTTThzCMBB6ZtGh2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KsU17/jqS/Jf+IjPM/aX/HJe6P3O70f92EuzQuU nmj6vJUQTNy/kY9flndeznbMsh8DKbl/Ce/ydXrNMB6o/FP1YMKjOwdc3irsVdirsVdirsVdirsV dirsVdirsVWzTRQxPNM6xxRqXkkcgKqgVJJPQDFlGJkQALJeOebvzxuTNJaeWolSJSV/SEy8mane OM7AeBavyGYWTU/zXvOzPZGNCWoO/wDNH6T+r5sKb8zvPjS+odYm5daARhf+BC8fwynxp970A9n9 EBXhj7f1sl0D889dtWWPWbdNQi/amjAhm+dAPTPyoMshqiOe7qNb7H4Z74SYHuO4/X9pe65nvnDs VdirsVYnr3/HUl+S/wDERnmftL/jkvdH7nd6P+7CX5oXKbVmVgymhG4OTx5JQkJRNSHJBAIop9Ye YIlQLcAqf5gKjO60XtVilEDMDGXeNx+sOry6A36eSrceZbZRSBGkbxPwr/XJ6r2rwxH7oGZ+Q/Wi GgkfqNINfM13yq0UZXwFQfvqc1UPa3PxeqEDH4j7bP3N57PjWxKcWOpwXaVSoYfaQ9RnX9ndpY9X DihzHMdQ6/NhljNFGZsGl2KuxV2KuxV2KuxV2KuxV5T+evmeW2s7XQLaTi12DPeUND6Smkan2ZgT /scxNVOhT2vsf2eJzlnkPp2j7+vyH3vFMwn0F2KuxV9g5uHwl2KuxV2KsI8z6nbW+sTRuGLgJUKP FAe5Geae0cb1kvdH7g9F2fp5SxAjz+9Kl1u0JoQ49yB/A5o/DLmHST8kVDeW03924J8Oh+45ExIa Z4pR5hWwMHYq7FUTp87Q3SsDQHY5u/Z7U+Fq47+mfpPx5fbTjauHFjPky62l9SMHPT3RquKuxV2K uxV2KuxV2KqF/f2en2U17eSiG1t1Lyyt0CjASALLbhwzyzEIC5S5Pl/zj5jl8xeYrvVHBWOVuNvG eqRJsg+dNz75q8k+KVvsXZehGlwRxDmOfmeqS5Bz3Yq7FX2Dm4fCXYq7FXYq8y86f8pHdfKP/k2u ebe0H+OT/wA3/ch6/sr/ABePx+8pJmmdi4Eg1BoR0OKppYaqwIjnNQdlf+uQlBw82mHOKbqwIqMq cAhvFXYg0qcadrqwqEnUkD9tf4jO07P9qgIiOcGx/EP0j8e51ubQ2bij38yWC/ZWRj7AAfic2GT2 r0o5CcvgP0lpGgn5L7fzBYTMEblET0L0p94rl2k9pdNllwm4H+ly+f62OTRTiL5ou7v7OztJby6l WG2gUvLKxoFUdTm/JAFtGLFLJIQiLkeQeMea/wA8dTnne38uxra2ymi3kqh5Xp3VGqij5gn5ZhZN Sf4Xv+zvZHHECWoPFL+aNgPjzP2MS/5WX5658/0xPWtafBT7uNMp8afe7z+QNFVeHH7WT6J+euvW qiPVbWPUB/v1D6En00DIfoUZbHVEc93T6v2PwTN4pGHl9Q/X9pTm5/5yAsxEfqukSPL29WVVUf8A AqxOWHVjudfj9i536sgryH7Xnfmzz75h8zyKL+UR2iHlFZwgrEp6ciCSWb3Y/KmY2TKZc3quzexs GjHoFyP8R5/s+DHcrdq7FXYq7FX2Dm4fCXYq7FXYq8y86f8AKR3Xyj/5Nrnm3tB/jk/83/ch6/sr /F4/H7ykmaZ2LsVdiqb6VeFl9Nz8S9Pllc4uv1OKjaajK3EdirsVdirsVYB+aXm+4njh8uwyH0YC Jbwg/aalY0Pso3+7wz0DsbUZJ6WIn05eY6PS+zvZcYE6gjeW0f0n4/r73nObJ6x2KuxV2KuxV2Ku xV2KuxV9g5uHwl2KuxV2KvMvOn/KR3Xyj/5Nrnm3tB/jk/8AN/3Iev7K/wAXj8fvKSZpnYuxV2Kt o7IwZTRh0OKCARRTKHW3VaSR8j4g0yBg4ktIDyK2bW7htolEY8ftH8dsRAJhpIjnuoLqd8DX1SfY gU/Vh4Q2nTw7kysdUE59OQBZO1OhyEoU4mbT8O45O17WIdJ0qe+koTGtIkP7Uh2Vfv8Awy/RaU58 ogOvP3Lo9Kc+UQHX7nh1xcTXNxJcTMXmlYvIx7sxqTnosICMREcg+iwgIRERyCnk2TsVdirsVdir sVdirsVdir7BzcPhLsVdirsVeZedP+UjuvlH/wAm1zzb2g/xyf8Am/7kPX9lf4vH4/eUkzTOxdir sVdirsVdirsVbRirBh1BqMUEWKYj+YGvyXt9Hp61EFoAzA7cpHFa/QpoPpzrOwtIIY/E6y+53nYm i8PGZn6pfcGJ5vnduxVGQaPqlwoeK1kZDuG4kA/InMXJrcMDUpAH3tE9VjiaMgoXFpdWzBbiF4mP QOpWvyrluPNCYuJB9zZDLGe8SCpZazdirsVdirsVdir7BzcPhLsVdirsVYd5y8s3dzc/pGyQyllC zxD7VVFAyjvttTOQ7f7HyZJ+NjHFf1Drt1d92X2hCEfDma7ixX9Ca1/ywXP/ACJf+mcz/J2p/wBT n/pT+p3X5vD/AD4/MO/Qmtf8sFz/AMiZP6YP5O1P+pz/ANKf1L+bw/z4/MO/Qmtf8sFz/wAiZP6Y /wAnan/U5/6U/qX83h/nx+Yd+hNa/wCWC5/5Eyf0x/k7U/6nP/Sn9S/m8P8APj8w79Ca1/ywXP8A yJk/pj/J2p/1Of8ApT+pfzeH+fH5h36E1r/lguf+RMn9Mf5O1P8Aqc/9Kf1L+bw/z4/MO/Qmtf8A LBc/8iZP6Y/ydqf9Tn/pT+pfzeH+fH5h36E1r/lguf8AkTJ/TH+TtT/qc/8ASn9S/m8P8+PzCW6v 5GvNTUGXT7lJlFEmSF+QHgdtxmfoxrcB9OOZj3cMv1OXpu14YeU413WEhP5UeYOdBHPw/m+rSV+7 +3Nz+fz1/cZL9x/U7L/RHgrnG/6wTjTPy8nsaOdNubicf7skhcgH/JWlBmr1WXXZdhjnGPcIy++n A1Hbccm3HGI8pBOP0JrX/LBc/wDImT+mav8Ak7U/6nP/AEp/U4P5vD/Pj8wpXXlrUbqFobjTJ5I2 6qYZPw22y3FpNXjlxRhkB/qn9TPHr8cDcZxB/rBgGqeQvNNrfSRQaRfTwdY5EtpWHE9iQvUZ2ekl kyYwZRlGXUEF6bT9s6acAZZIA/1h+tC/4N83/wDVj1D/AKRZ/wDmjMnw5dxb/wCVdL/quP8A08f1 u/wb5v8A+rHqH/SLP/zRj4cu4r/Kul/1XH/p4/rd/g3zf/1Y9Q/6RZ/+aMfDl3Ff5V0v+q4/9PH9 bv8ABvm//qx6h/0iz/8ANGPhy7iv8q6X/Vcf+nj+tkXk38qvMWq6nC+p2Uthpkbhrl7hTG7qDXgi NRqt0rSgyzHgkTvydV2r7R6fDjIxyE8h5VuPeTy2fQ+bF8sdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd ir//2Q== + + + + + + uuid:72974516-2800-460a-b1f2-a8f39fe5df0b + xmp.did:bb426c5e-7df3-ad4a-87c4-199bed7ffdd0 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:85886100-6372-8545-be80-39f410c7d0a4 + xmp.did:85886100-6372-8545-be80-39f410c7d0a4 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:1029d5db-88e6-c84a-9e59-b4f3a1e62138 + 2018-07-30T21:17:22-05:00 + Adobe Illustrator CC 2015 (Windows) + / + + + saved + xmp.iid:bb426c5e-7df3-ad4a-87c4-199bed7ffdd0 + 2018-07-30T22:21:48-05:00 + Adobe Illustrator CC 2015 (Windows) + / + + + + + + Document + Print + + + False + True + 1 + + 399.999512 + 581.146484 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + 默认色板组 + 0 + + + + Blanco + RGB + PROCESS + 255 + 255 + 255 + + + Negro + RGB + PROCESS + 33 + 25 + 21 + + + Rojo CMYK + RGB + PROCESS + 191 + 4 + 17 + + + Amarillo CMYK + RGB + PROCESS + 254 + 238 + 0 + + + Verde CMYK + RGB + PROCESS + 0 + 144 + 69 + + + Cian CMYK + RGB + PROCESS + 0 + 155 + 219 + + + Azul CMYK + RGB + PROCESS + 0 + 29 + 126 + + + Magenta CMYK + RGB + PROCESS + 186 + 0 + 124 + + + C=15 M=100 Y=90 K=10 + RGB + PROCESS + 160 + 17 + 39 + + + C=0 M=90 Y=85 K=0 + RGB + PROCESS + 198 + 72 + 50 + + + C=0 M=80 Y=95 K=0 + RGB + PROCESS + 203 + 97 + 32 + + + C=0 M=50 Y=100 K=0 + RGB + PROCESS + 219 + 150 + 0 + + + C=0 M=35 Y=85 K=0 + RGB + PROCESS + 230 + 181 + 74 + + + C=5 M=0 Y=90 K=0 + RGB + PROCESS + 247 + 236 + 69 + + + C=20 M=0 Y=100 K=0 + RGB + PROCESS + 222 + 220 + 28 + + + C=50 M=0 Y=100 K=0 + RGB + PROCESS + 163 + 189 + 49 + + + C=75 M=0 Y=100 K=0 + RGB + PROCESS + 112 + 168 + 59 + + + C=85 M=10 Y=100 K=10 + RGB + PROCESS + 79 + 142 + 58 + + + C=90 M=30 Y=95 K=30 + RGB + PROCESS + 51 + 101 + 53 + + + C=75 M=0 Y=75 K=0 + RGB + PROCESS + 110 + 170 + 111 + + + C=80 M=10 Y=45 K=0 + RGB + PROCESS + 95 + 161 + 153 + + + C=70 M=15 Y=0 K=0 + RGB + PROCESS + 118 + 170 + 219 + + + C=85 M=50 Y=0 K=0 + RGB + PROCESS + 74 + 114 + 178 + + + C=100 M=95 Y=5 K=0 + RGB + PROCESS + 0 + 46 + 130 + + + C=100 M=100 Y=25 K=25 + RGB + PROCESS + 0 + 26 + 90 + + + C=75 M=100 Y=0 K=0 + RGB + PROCESS + 88 + 22 + 125 + + + C=50 M=100 Y=0 K=0 + RGB + PROCESS + 123 + 5 + 126 + + + C=35 M=100 Y=35 K=10 + RGB + PROCESS + 133 + 14 + 91 + + + C=10 M=100 Y=50 K=0 + RGB + PROCESS + 178 + 0 + 83 + + + C=0 M=95 Y=20 K=0 + RGB + PROCESS + 191 + 51 + 118 + + + C=25 M=25 Y=40 K=0 + RGB + PROCESS + 197 + 186 + 159 + + + C=40 M=45 Y=50 K=5 + RGB + PROCESS + 155 + 137 + 123 + + + C=50 M=50 Y=60 K=25 + RGB + PROCESS + 114 + 105 + 88 + + + C=55 M=60 Y=65 K=40 + RGB + PROCESS + 89 + 78 + 65 + + + C=25 M=40 Y=65 K=0 + RGB + PROCESS + 188 + 158 + 108 + + + C=30 M=50 Y=75 K=10 + RGB + PROCESS + 163 + 128 + 81 + + + C=35 M=60 Y=80 K=25 + RGB + PROCESS + 130 + 98 + 60 + + + C=40 M=65 Y=90 K=35 + RGB + PROCESS + 110 + 81 + 40 + + + C=40 M=70 Y=100 K=50 + RGB + PROCESS + 91 + 64 + 10 + + + C=50 M=70 Y=80 K=70 + RGB + PROCESS + 60 + 44 + 23 + + + + + + Grises + 0 + + + + C=0 M=0 Y=0 K=100 + RGB + PROCESS + 33 + 25 + 21 + + + C=0 M=0 Y=0 K=90 + RGB + PROCESS + 68 + 66 + 66 + + + C=0 M=0 Y=0 K=80 + RGB + PROCESS + 91 + 91 + 95 + + + C=0 M=0 Y=0 K=70 + RGB + PROCESS + 114 + 113 + 118 + + + C=0 M=0 Y=0 K=60 + RGB + PROCESS + 135 + 134 + 138 + + + C=0 M=0 Y=0 K=50 + RGB + PROCESS + 154 + 153 + 158 + + + C=0 M=0 Y=0 K=40 + RGB + PROCESS + 174 + 173 + 179 + + + C=0 M=0 Y=0 K=30 + RGB + PROCESS + 194 + 195 + 201 + + + C=0 M=0 Y=0 K=20 + RGB + PROCESS + 216 + 217 + 221 + + + C=0 M=0 Y=0 K=10 + RGB + PROCESS + 237 + 238 + 240 + + + C=0 M=0 Y=0 K=5 + RGB + PROCESS + 247 + 247 + 248 + + + + + + Brillantes + 0 + + + + C=0 M=100 Y=100 K=0 + RGB + PROCESS + 191 + 4 + 17 + + + C=0 M=75 Y=100 K=0 + RGB + PROCESS + 206 + 107 + 0 + + + C=0 M=10 Y=95 K=0 + RGB + PROCESS + 248 + 225 + 46 + + + C=85 M=10 Y=100 K=0 + RGB + PROCESS + 85 + 151 + 61 + + + C=100 M=90 Y=0 K=0 + RGB + PROCESS + 0 + 56 + 138 + + + C=60 M=90 Y=0 K=0 + RGB + PROCESS + 114 + 64 + 141 + + + + + + + + + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 3 0 obj <> endobj 11 0 obj <>/Resources<>/ExtGState<>/Properties<>/XObject<>>>/Thumb 247 0 R/TrimBox[0.0 0.0 400.0 581.146]/Type/Page>> endobj 236 0 obj <>stream +HɎ$5~tJpgTa$ޞ/lR5Ģ2"8Gљ/<˷|< OxےIZ<-^+"2Յ)).b1Omf쏗$pTbZZio3bU\w)L;}/˽|\7?/9sy1 o?_?\OǗ~Z#E_<-kH*!'J@XC%1 :)];aK.6Ņ(̞!OWM.T̯&x%.ˇ#JWbzr/!V9+ 2l'y+6 f6׆XfPMIV|I(Y-N dVdJU78@8 5F8* a\4`Z=&%V+eY4]E3{'}sV'ۓ^K7di;uʮAeH1n@5ITn0F.wi<.0X&#y[5aX75c3Vpfz$`oPzzwʼnwbz6uP SകMM13CJ^oƳ^H);ϝ+bf/u1kd<ߛ%94;i(J.X{OapNX|Χ]ˍ%%gQL !OᜮrD Rue9@LaX,C&Sanhfܷ> endobj 247 0 obj <>stream +8;Z]!0p[J8%#1spLOk?#bU'^R$4EoeO@BV\ZO%b+_?SoPP2p1bhB_pp7uQ:%7dMR- +^U;eOm`MT_Ir0?R&DDJZ).DmAD%MbMOqA2UD%..Df+ji5YljCT!<,4p&InheG:5M! +Bje4?'F'"%C[:h@!q!'^(tdkTef.EEK@%ahXls*n^)A +0;HPDn<<>ZfcNQd_JoC2))GmKR.33K*PNFOORjLOTGm#fmNW>S\c;:C%Trtp[kr'8 +O$q(BmE^G1WAslXPPrt$cr"l[-eLa4-!]j9ffu`3#h`%:*EhXR&qLZG25/nk*MCZ1 +Je@V=rb_k[.RG^_pD9hP5XfATY6Z(Ai2NSnpT[=Wam/6-&TW%0/0+fcp@eh(ml6j7 +cf*/_dlN.3.i#f$!/Y/J7K~> +endstream endobj 249 0 obj [/Indexed/DeviceRGB 255 250 0 R] endobj 250 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> +endstream endobj 243 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +293.2800117 0 0 234.0000093 -41.6259766 -58.2177827 cm +/Im0 Do +Q + +endstream endobj 244 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +273.8400109 0 0 211.9200084 146.2255859 -47.2530162 cm +/Im0 Do +Q + +endstream endobj 245 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC/ImageI]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +344.8800137 0 0 167.2800066 -22.8964844 -50.9606707 cm +/Im0 Do +Q + +endstream endobj 246 0 obj <>/ExtGState<>>>/Subtype/Form>>stream +/CS0 cs 0.929 0.929 0.929 scn +/Perceptual ri +/GS0 gs +q 1 0 0 1 140.3291 485.1382 cm +0 0 m +118.255 -35.836 l +118.255 0 l +h +f +Q + +endstream endobj 261 0 obj <> endobj 240 0 obj <> endobj 239 0 obj [/ICCBased 262 0 R] endobj 262 0 obj <>stream +Hb``2ptqre``+) +rwRR`?> v^~^*vD_)p%?@lZhdg"I`($>dCW@$ ]>faˀ% { *23J ---SR+KRs< +KRSj!ABPi5Zho@p2A!@riQdL0cR?1^: Sbj  O +endstream endobj 258 0 obj <> endobj 260 0 obj <>stream +H 6EA7='qP U+ Tnsw,$4H|(k4N̲FO!=J} ztP!ئxd>w@NK8G7շ\[w\U]\Q]9Է\KݼW\Gݻ\A])՗ܴVVnj6a[C}j-H`%uіR_&f˩/XBw +Lت{V7l]3 rYZ^}t]A}|n]C}lj]F}Td]I}<^]K},Z]N}T]Q}N]S}L]U}F]X}@]Z}<]]}8Q/Q]&S%VM]%~wn.[Q/9c7 1-zz@ԫruЪ=2T @= S燇y>;N!^%n){~-;Ž1{ž5{k¾=;cA[ESI{KI{KM;CQ;U3!Y+1]#AaQeQeai qmquoyy}ooo /))9/IY/Y/iy/սD؀^pzmfu.8U=7`U] U ب'lSՋ6Sԩt-Rpzsu(8_9`:՝PxzuSu&HԳ+AD 'HPUR>:uUzun@ p[j4'R\=A 7aWoG#W#WCg|WW!3Q` o(0zWuED: ^"EQO]]QO]]QoMRRkS瀡sU׀sU׀{Qǀԃ~[`A?-`4")`8$%`<&̟M?ęQ-*qz@]T. WW7Q˄iµ`\60z[Mpϝ|`{zլ ܳ+fM>/}; Ui߂v_=Yx#N5,>SԖ_f؉OY]a#<<sITUxsc`? +[/i\g)lS&rUʕ&xĿv `2W +/t.5~^T ]jy,>SxgzLZVֵ󻃧3KmԋgvٱO +2%;Y|X[b\eSOө-P&T?[^9̨~\@=rSrY^=qUvY\=pVxY[oX|YYnY~YX=nZYWm\YUl]YT=l_YR=kX@YQjXAYP=jXBYOiXDYMS/HP +t*IcK$dHe&>hF33=<ҿfL$}0f[4H2L&Ea6?$҇ Ij搾cP[3Ì ،/}0fxI6K_0*\aV JnƖ_Ww3ߛf ,}0g\ۅ8J.L.Urar/Ψҗ Kq>\^3ҿ!(}7gD髅9J-,!Ofa p' kHt>YXD3*%}gg,{u;CI+,$IZa!H ++Iw>VXJ3Rqo֒ #}gKŤ +J}ʥVK(,+閾OXV-}ZNXZ:J&,-zo֖.ҧ kKZӄ @i U2aq*}t(>LX]J&,/:w KGNR,t>K@y }8@*qUęG I/q '] gw`syfw`syfwXś`Wsvg޽ٜVzfwX`ovgE>ٞfw`og&ٝ&f{d`ogٝ>Zf{`ٚ୵kgٟ֟uf pș /q:@!tNOxD-.< +endstream endobj 252 0 obj [/Indexed 239 0 R 1 264 0 R] endobj 263 0 obj <>/Filter/FlateDecode/Height 697/Intent/Perceptual/Length 80679/Name/X/Subtype/Image/Type/XObject/Width 1437>>stream +Hwg%@($BCE@EpA,hђ +({yyy [fr9s7@!B!B!B!B!rlmW![ܹoZ͗d0BB B%[La4Bu]W F#˷,m!ZDtۿB߫C;]B^J {BU=M5!"k՝!2yjܥͅnCũL^۰fJ7_!F0׫X#ke].ך\ָZDgвH^UuL\70Y.yJRw"m!4:œs9r +H1{Bs +K]#4|F-:M˱Cq7vQVnGNXom*dn4|F>u s N͍`#]%::>#^er>_$tHt t'3Bhil20],(G ;}4*:P:@] tg!dj6a]NTHn  b=Zs@gɜrUPd#kJFW綿 +Bhed.er'9x5R_Z{CsB !4Ź egrk6FD'Bns!dNaNqٳ@6n3mބZ[-ѱu||F|&s˞e ;. +^*mNݕm*ʩ̕ɼ\9cYQ&; Ӯb{m6JnF'Bg%ZW2Gse˲W٘lAfwwK{|Q tVi5:$::!J%WG2NeCeCxJO +#gZvFEA#t^7>?Bh9\d,.:e. Veg)_:tP +38F ѱ ɀ<#^eyWe'¬2Wafe-,*; ȎCᠷ8 Nicḧ́v@ogV;32'sfvyԺC]fe+ʊl8fHG]3d+Ԫ -F;>gЫ+GsGc73v/̲Qٛ [cڻ+9b+^i6ZvNNtU!Hi\Y.+e%Y=f{F:aO/(mDg]|nc"Kh+2Gy\9r2lLVc6$wJ:Iȑ[Ei5:! ]:/9! +9/s4d\eUfd}:ý1'rFkZfhZ6ztF9;3Bhx4eO,̓gZ\Oa; <潬.[Ce&YAp"-w[kZfh"ZVM z]f@>oq>3=|2#{bSy'D ̡˴eQ٣$wK.}~_Zi2Z#6^ 等̳!egs@:Nf3d.̃yz:tֲlTVd |CMg. jUZ6Fд@OMf|Ũ8~44G2'yΉ]v|ǽ33eʢ&1{J8 EjfhD4h'fBs>D@G@O=1>o<4480xn+#^r6WiUs2d"0`>uw2L[YT6(3X|ڵԏ>ܟXiM;ڬh }&y@ON>~^sxF-\ټVl4ќ9̓4d>xa>`>0w`Vy.ZL*P&Ȣ1|ƍr?>$lVeJѴeE>uJ>&@<l3Qy<#9ٍd>pa~;>l2,kY* J2߼ysvv3sS^ 2HLh+&瑑ᡡ|. B-9=f6G4hMC< 晳3|Q\kY* L2,n9 _С-RӤ Fӎ!MZ?@[̀}޹c1s?xF-RUlNiyp0's0L0sfra.Zv:oeYʌ Ʒok7ڗA+:je%;Zv@K}4><(3xF-x%e64<2ȼe޻7\Y\&eˎe$"oQw;SVic+ ]3>)>|f-f> |#ͽ29+299/e2lQfdgϞL/Pfib)mVc=3:狱gЂls8OsEp2+<Ŝ,.Z&A3糑Kj#+i]\0q6 h^,Hfa.P`v2 .3˨2 333py7ԉGpJ\#Ĵ40DZWJ@231Qa'C)|Kϳ5̳g99ϙ7nf=$s0ˌ 2s2q2#̅E`V]'˓SPʈ2 ij7a`_ lZ( HCIOMN*D ]]UY!}NW}|Vy|F)Yϋx^ܗ5C8;yVY4S4R3fنɌ0 Uf]0. QeBLF۷ܹs{W|38&j`FhhQ:FZtIqQA~^Nvl$M q1Q||<+y,''>f%f7A ,d6VYMf a1lpy,ʀ2 sss󰇸oľCS~)iP3ӈ4 TxZtyYiqQ9-5jI4')<>ijgrrrNoWh)fwO/oD@ GsTt 73ʜ2C2a2B2̵uslf`ZUd$=f=z@{bw8cQjfhh&'4 @47A@TUV϶dkR6NE,YNN[86S6lvs4+`JLY9̅"SsfM0.S-VF e4EFAߧO~=~@S~)qP#Ӡ4!!D_Dkftur@7eHOMZ&簓A'E=vD`P0Asٖ_2W֟dd0]Z&Ae ea}Oap?s8z8% j44MD?YXxBx<`ꪊR\%є<y'xN<.YƳ[k17lܨؼl޷!w/ÔAaL595=ennimd'40kY*#h2_8= 4+ HH4V4D#4} |"ƆSu5Օe"33R-x9T˳_y75񹣽tC}m9ٶdkn<^<_CNNn%(ׯؼ]l=6c6G͉9 hhSeUyW &eeedTVPFc~Oa&Qi4-Ɗ)B W._p^LWG[ksi5 sm)֤DS|\LTby,x^ϫe;>9uNIٛn#s .Q\, e2D?=КJ#l4V ;Z' 9޹yb|ldxG"9<'ky  3ƳfWO*ɳV8/gyټl`xfsfVN^AB3Gso0|¥Wgq2 zwP +˨2L&3H`G/wjrFhhhZ$Z s>_pnjs/ssC}mMU򜟋<: y&grrrKktm;wwࠛsgsAQIYB3G|uWTU(Ɔ`GޤX( 6F+^) >;N2Qc2IL{}:׺/w}ַ$3܂`Ђ\e2BL@f?F{k5U! F3iBF}.).,?{p) qρ,ijx:LY+fq'Nbdas@Pq ˓VNa4h>p(7/d.-dnd!`fe\˘e26(~?i41 ̈́ B#^F\UY^VRTx$0^۷B>oaVDhhhP hYs[ksScC]Mu%Ç dg_;꿊܏A8p +g#cSs+;gWw/oY%qV$NlޔmNBs~AQIiyeum]C#D0epYa2FH t)^S189ѢПZ h܋|n?|^\];wl۲Y7Ago/OwW'{[+KSuijYNN<*'B8O35uprqlN\:u}]?h.oؗCygx{y:;:Z[YLC3fΙmް13kCq4wt'b20 0?| +f첚e2YB'\39ҔhAqBcgJ>ŅGr׮%"3|<]h}sCsy)y5+a/?78(`L?Zg3f[86aE`󡼂Ҋ&LsO) ._5`3Yf2gLhMJ1ѸyCQA?{k 4|qڕ/|n?ւx(+QsxN[:/dN8]xyAgrrt89c ǩwfK'N%6{ 7hKL3+Wy33Q2?zX f 9 edf?gjhF"4*w7]r"ghCHyxN\d"9(ƳgSϓx5dzYNn`pFp=FpDY#-\$nYҪ’Jc'1.hy ,$GtìLXf*+&3xZ.UPsјh.4Mh +˗B@s?MP>Z 0ϻY2֯MY,>v⨅ 쮊g#g3Q<#rrsZ8!nj57~d#csKk;~P8GD&$LY}g6|ڍ[͌SH/4`&2UYAYSwV&D+B#~ϟ}r/]; թs}k֦iS׬JZ,~iLtTDX輐94=x6j43y3!g g==ΣF57y aKW$YfsCS 擧ϞwT%/_Yq2SY4_}֑ +ҔhAhиi@~žϝ9u$xh͙7K]2iyBŋ"# Tleinfy"Q#q<3Jq83UqfM *h:D$( +"A@AAD@$$" (*ꔮ:S{yNshT }o_I5A8pՍf3Z÷h%HWfwYe2" 1 i$da>O+/?׋uxNN'$8\8xg.gg\gR0):Sy3fljYv +J*l5OG g]!aѱ Yy-]zNlwV3D3Yf,߼ Y22 eIi$44|ycվ/@O<\xJOMN8w@?^۶8!lIij.Ϫl2g3Ҹ1km&p^p^,ନRU uWp^o΀=Q2s Kʪj'N"<0 *3 3e i,7b'qEF Mgh>߽s._c<6z@+3(Ue%Eٙi)Iq1#B}wlGƳφ0|GM$y33fsr8!8q^"t +[h2Zv/}cӳU76]|wlf\f y8TRx06:*bA~>^nX<[lYK(q9l3gοgtflgYrObF{-ۼv s0)53y`pd(Td02H,i BCрF|D)&oxs(sC]MeԤёBwƳϫVjl +ijRa:ctflw"/@p]"t2KU^ozv,R2r*k[:tEm60hɳiPW]Y^Z\?"|OHP(7񬧫%48j,eDgyFgf$p^p^,#+' h2Zv'iYy5퇏6;'j4#220,3$XF4h*ԀL3Ϸ%yhki(+-*HKN<Eg;[k4 @9=; Σ=z/\?84xf@O?AɌg \6Mڷ1MZd%|gϓT/_<)֦ꊲҢܬdϑh{ʵޛ@l~+mFYD3f0ӳߨ&;#W\p]M e%9Y)IQB}ݶ8;lXgf%s5,1O3p"iwuii/":#CF;O8>=35 w0q +H(hZ9yG'gaùh515f-]L4CLfb|"h&#<>CC=7g,|BbRrJj6aQyUuOvt<53|`އ4|L4&'<yϓc/_tPW]Y^ZT83@?Ow'{K3C=mM5e9iI1A~.vVݾu:3-XxFtF2v4oݹ_X\Z^Y]/(<:!%#Ys['#cӳ˫ol}>Kh0|y `o7sG[KϵeŅp<`kenj(/#)."|2OΟCtFp23+pDLbjfnaieƖ׽p8Vެo߄m'sȟ 5&3&A y~YC]M^<@WK]UI^VJ\TH UDgd(rDq]řG@DBFAES; $26)-+֎}#cp8{s`3TX?擢|H>y=7;=51sS(KxNJ + twu436PUVdgab Pg@x Ox_RQu0jbj =j&-D_wցxyrbltdh๫0 rScC8Y[j(Hp2?L x83qA8+iG'dT>ildžΐlƑ80\>Bhr>3qyyqa=;359y s[~!1)9%5m} [G7OR/F'g Kkopml>,rЇ|&Ϥy^Z\@NOMFȰ_/W'[+sC=m@gY)qQ!^n6P; 7:_x2J<󵛷12cpV60urIL-*{5>5^\^][x _~!#d5]&4|&K蹙ɉё!l<7C\Y^RH_GSMYAVZBTX2 +qOę37HDlRZv^QYuzQs+o޾ywOۃ4$xބyyyia=;359ƍڪǙi qA>.v*rbuEtFvNv&FDgd(p'YC; 42.9q~qEMCcK{Ww zayum}cskgw·lʌQ>wK㹥I}MUyiQ~nvF٭\D@Kb76I4EM5il{Ċ"J"]zWB!w.[aYqg{k;n\lv[筛~]U+ϝӻ HepJ# Ljpp1{:jz•>rr}peUYM-8K 3*Y{nn 3L<''R#B}<]?} Gg{'HYHXgn$}g1#GI⼁,HM"pf8&aKqVfV +Ymm-3:\6I:Ԥ _/W'v߽ma~gO0!u޼a=y岥@@XgnP%󰏤pp3h֬۰eLLϚ]ay/L8?/*)8s!΍g,G%y"ygZrb|ltDhp37'G{{7_t>rpvn:Y u^L26k^Rs<EO>B:_8wX_~:/G::pnͽ|9-sxt|-=\Z^ds5u -g`NIhͨ>!P3<ϥ^ΏwnݸvOmYބ:=t6 tu{:)yH<~dE88߼cmGCIN!pfqxյ8-Ymk3qۀE繢꜕FKN + pu~|% 󎭛TY q:p^y!Tsqęgm?DYy.y~nvFZ +5K-s@#lH p&tPJ86wK\X\V)¹Y +p5 [;ϝ$gbҫ*JyLO&Q# t>_Γ$tF׹5=1NtGp pT3<8kq&g!}|dTUBrSiI q1a!"޿ t t6:A1@g}ñ8o8o۵|I3U%p42#˳ye򲒗s2hɉ1Q!>Oηf@cPu +u G@Xgn>D8&(ĹՅY;rZrXLzUsvfZ +5Dlot0lv*:Lu6Upj"Iq~@ 7 yVxIk<ɨ(/-.zQJMF|<ϐ:y:qcFt8pV³ynG\W[- t,:egCcD:?:[Y޼X lt&gNS +q.*)8Fyn +5>bE:s?AΫW:5{4BqPg} !!XgNS[jiGQn t8lsEYBsVz*9"4SN:fe@@" u%tiy~IUG;:P:RgFy~NVF*5Mtl*y/H%|pg&G#3 Mge~[BRgfu:Ӓ(qu6޽cXE@Y3}O: uJꌯ3a+e<:wuF\[-#+KD:'(y;y +ysfMJ{sO)ҙ t~tn: +Jy1::_6;wac.0,컌>0wB D46F4ݞg@4 spϹ]-L t9r2Hg:ҙH@:#΢3 q_ݢ癫3~/#!o:1sOʲc"B]pu8ꪓ:Өdt ap_sgL_1#y.O<ձ(/;cER|tDHK(/+-)ΠQDtNMu5WgJ&tKW/]8Չݵc˦ukZjʊ3V$Gz9 t9L%yYiIqB&vg hgGtMy;o\_[YZhgmajRUVLRHDtqE1E&u A_z[Pws|+Ο9t޿gͣC;V7Tf%'Fy8ZikTd$t*D@:#q:C8 OW?b:?t{+Ǐܿg|摡֦U9b"B}ܜl,͌ t9jL%9iI B&vAgg:?C:?o\|iľ[dž7]XWUV2cER|txHG(/+-)NRHDtqyYCAgR¹'طkM:Zj+K S‚=\M t,e9) J&gLg$<tH'wnݸzٯN=t`[F7vw5Tf%'Fy8Zik1%%4 +HXƻ3u A_t[\pu~;_yGwnZU]^\<>&"$PWe*JKө]g\gQQ$,oa߾??wHׯ\:#662׳(eƊW';k S#}-6KEYQNFJAI3o3 IGt7WWH秸wo߼v9L}Ƿ lX׹0/;=%16*,PO[TR`(d"a:sutt/2y)W?zpo\|O۵c˦m5%9Yi 1^n6f uU8J!u?uLe`|wLӔ] +Y}ϒ{֬,EQBH$ +*ʒ-k}}w88<3-;{ȓm{:SQ:CpH[u^Ft#:O!:vw57Vdy$,$m?oWg'SVF:j +%Eyql,iI8BySgXgn3e%~soWGkI¼/b"?kW\r9ifb$DZBLDye>F:ZXgf:y0jom,+.~">&2<48M_/wϝ8al('#uHTX f&Fz:dFu :CvpTyeSqD羞ƺS?{aIq!~^';L 4꼃?8g?":B\Bt!<4PW]^RUB\߽zPO[CUI ]}:RoLE A rΤuFu^@thmn*/.H}2>&*Qp^./;cmq!Q!^n.6:S% ]Ma!://d{[k*ˊ rަ$x,2&2n.L.t7u t 8c:Ig"a~@owGkS}MeYqAnVzJRb\Ӱ{_z҅sglN06RWAYTζ4-_鼾 +qiqa~nfjbld(?'3ͫبGwnz\<q#}M5%#b"|<8:3!g7N0~]u:33~vfr|tx0/;#5E|Ldx?oˎ6f&zZ*r2RDxH@OKCM^gT$t 8cpQgdiD硁֦ʲY)IqO?kW\pqc:GՕdK8YYcdEՙ +76u&./f&F{[+Js2^Jxx福)KsSC}mMU%#b|\Yl^g;ՙdWWK ٙζڪ¼ϟ= wZ*r: +"̶4[y :CFuFy? 뼲DNO vw6T/x&)1.rwxi+F:j:HO߯gR3fkku{Hjoi(-L{2>&2I1W#Bφzy;171PUdgű`1MgƯ3BEgz::S(0CәHZt~rfj|thygG{Kc]ueYq~NVzrBlԕ gNxtsgmif('-!*L`㘱L; 33Z32)鼲H\{;`ϳۚj+-̻s+.;p~۽&4ՔeE|<;錇3m:#:3| '3i:/HDh:Byblxɣ֦%)qёφ!`62%ńJT3Ψj5ΰtt3y03C;;6UUd''F]tǎ>hHOGSMYAVJBTϻ Œtpuކ +3;)鼲H\{;`_ϳ[jT޽s5"ܩ _/wg=&J2"B|<;9Yq,X m:A tpFYtuHyD"#yjbtx8?';#%16J؅3'|<923RWQ悦3 MgΌ T J8qCәHZuꇧsÆڪ{EywnݼqKO>n.M5eY)qQ!?<,HggXgz mpgz::S(鼲H\{;`_wדG5K +r~lHnm U%yI1A>.NvV D@gQjә2yD@Ύƺʲب+aO8~v֖Fz:Zt&rsqqXh:Sufuf:@ +LCәHMgO57<(-{;35)>jDStvqcab R"B>lxf 33UA tpF_q Og +m:Sc}]O4UWfg$EG]8s2>k+3cZ*rҒb"|\8,:!}yf@љΟ(i:#yݛ/g&G{w>n{X[u(έ7_|އ805TSV&rsqqXh:#:oͣ3]W},81::Sh:/Cyӓc#tnm_QR{;35)>&2ِ _/wg{=&J2R"B>lxfo:3Yg4]*A73*[gx:ShyD"R4;[*ˊsғb]8}#:43RWQ@tfű`1L;`:8Z282:#Ue"iayzr|dm *J LՈsz`Po0 љ6Ѯr DKą^LM uw=yT_} 7;#%1.:2♓~>ݜm̍ vkk*H1ch:oθ : A;3JteD"yfj|tygGڪ{eEywnݼqKO8~v֖fF:Z*rҒb"|xf u+$7(tLt&ӓc#\_sԤB}<]lXTSV`gű`1uf鼕GN7AڟtLЦ +m:Bybtx-uՕe9Y QW.9y`љ32QfyDA586ә32㶇 ޽s+._::8v֖F:Z*r2"B|<;998f,f󿾡O;\޺v!|Z33jkKą^LM uw=yT_} 7;#%1.:2ِ _/wg=&z4Ք%ĄY,Xtf(:L^h8U8teD"yfj|tygGڪʲب+aΜ :0㍀;M +c  +ADADPHGzw"mE'N.3=mϞ,LPwΝ2CI^Yy8fx 3 ,1NgTgx::ZVWC9=%1]DH}]m-3T۵}˦kV-_pY*eJKILŬ>aft +(Ph3H8 s}NvwWgƺҢ̴䄘WnvM n^rcGݹmu\d93Q%!':<՗ 0 $Y By+4BOg範fuuӹ0/;#5).:"4药 WZ5uC򅳧O=ώ7]rfC:+tK֙xD3.Ob04$;tLtps}mUEiqAnVzJB>.Ol-LjkiQ?zhaK-;{ %i2ҒSB<:"<px:#8%LO=6 u5%9iI1ao=ܜlܿmZgԏڿ{B:/^8y,$\gQ΄ŢWfdL`S<)@3 x eg> _ttX_[]QV\륫M n^z)5Ճvo kW@uVfY љxO0eMfy*c%&..NzKt'3|W"puŦGҹ(?7+=9!6*<$3{[kKn\xNڑ{wa:/]`ޜD':C"~ʳ\b&c+C3\i@}t)A 88Q0/'3-)>&2,8wuu._8wıڶe5%% 'TLy|e$3f8ʨ㈍?<4h _ӹΝt(-.HM z{<~{v":",<b<@#yEf f\M`;őƈ64hπgppQpJΟz8lV4[\SU^Z.<$sZ]zIC:o|"LgiSI:3se&3f\'"Mb +=;Z _u,y8Dΐ:Cәlokmt,+)LK + x噽]C׮\:qUH[7o\GY YJbI̟=b@i4q&OFz; M3$C:bcCKSc}mUEiqA^vFjR\td?o7g'6Ɔn\x^㔚}I:R, , bL G0̢ܷ\).c(K I2qF&M3q>ACyX81{8lVWG[k 4kKsScE~`g=;7t._vQgyi2ҒS&#:c3M&h^F\FT,5i9%|,1lhh~>3 3pQp +O^l:䰻:?45VWeg&D~㇖&Ft`t^tBDrR΄ &*<8녫̓Ɔn^zد訫3=nRdS @$!$L !d' I`BH &(bRb Xڪ(ժkaɾ{$=}ym&/ ߫b>8K9<4t:{2s~̬'YR>Z+t{THd$3/fY2L$^^^l3x1i$ZZZs}wl7XafuPw֍kW.?WuC}s`g~޶wlhO)qhsDh@" regǙ1Ν-M o^zBMǏ믾'ۻ{wmtγLK'DN `ij g^Z HuYG2`.#ˈ286n jf4-@c@ )Rxd<ݯIh܍|ҹurB3'&ݵn}kq*:''L51<4xB y$lgg4hp`׮NN..nn +̞ebQ&X~x7D5* FLh ]o:T6.6:stI)?4-֎Rq,d~ejy4aF f f22&# Id6pTh4ft$54ݣF*<Ώ#YٱfLgԹp&;;Hz󹳧O;rۯs7/ *K +ӳ2$M<)s8",h(1T&E1d/Ufszق ,HrrrJJJjjjl:|Lh&h϶tBy_:ϙ]0Ӛ3-#m!+L3hq)hhT2LŬ$!DeTPFsrrfg8BihZZ,ǎQ) +uRg^fLgYڬѹt^yyV,]4^ٜ¼YSY+lgx~@ϏijYfԙtӹGw`:꺵kV\xAEyI34 Yhx|V|@s聂i.@2w2̒ddTed2 .ˠ2_PPPXX8 7?Ԁ4B 1E?|<Rgޚ٠]N[sMuթG:oo~+% +Ι]gxNOMN< }T|8 4Fsz̒dvg2E2`^Pyh2p\TT\\<VyQJ JCK(l"-Ϥ36r7͘L.tnA:aK/<+/)<5%)!>.6&JYIJ3ŀ&h43-NpeHf.3 2r#,bV\X&䒒Ҳy NJKi@.D5@c@~DG'| +g7YlƳYgOgLgMLkW.w~۷ڴW^~U+-^P19;3=MIYڅFs؁],Y ɬ2d&3)0EP%2z\QQY9>QeeEBH3 hhs%~ 3(MxVy,Y&qvipf:S:kun#kmt>:e󛯿n+/Y8^ų5'iP'mf6>'r}߇(".\ ,.( '9jSkhڦm1ӦIT3>_H3ggpk%4 Dьi6v\D*,y)gJ2ed̜T9EʒJelXpx!I,d:XмϾ>^[]7K3|Ig9,,n'l0L!GG@瞓mǚ@Jm&_̑b<&'DE3%%34MB`4)=}x * fJf[2{̾ 3&s$333L,g9rBT*sayn +Lh4 #^ˤKh":t;Oo?3tv`_͍]yiQ:W,9?)!.:2y))]6:}f@CAD4!ML3SX&\2s2of2's\|B"L*+dJ/gSU*ZFgXsxXHp`>?=wx^`ogkm?A˗-x^`y<ԙgQgqs1gܳA+F >rP[UQVS23RSc ً%D4 + Dр%lmc Ō0Y $sDd$s$333 ,j$P)***...a+-e k4@5(Fќ4 h^fv6b9*ų@:{q pP?SL_2v3]'Z5ՕZgEaD9"yf34 +MDр4n;-,<%sxDdtL,$ebP.FʴZmyyypp.jjPZDCG h,hI]:6VkV\Y|eQgqs6g ,? :5uorcϟ9vPxV)岬Cf&^On&3$4G4"mMN Peta fS %釰y2\*kQJVUU:֢LhZ@S@s>Q>>[]wq2.913gq t&!g17^8:24s娱Pȑff YdzGi;teRzyL0d2{O9eޟz Mɜ%!e`T!5z`0qZFhVsdR)I PėB>?y7 τXYx>gKݳ:tO:ߟ}Ƶ˗F ?uXSc=s@Ȗff),%yuv6kV\lo.@xu7Wq=tg!?9փo_2v١.jue%3dVb|lLTd8  Bh(Ng@y .)CB#"bL2K2 +)+*uT frYFӰ^𢧧LhZ_[S#5\%,|zz޹]VWXt7!y%O7W߮|!u{gbձ#,;[[ Ue3o 444F ep`F11#cḃ322kJJX2 u3sc U{{qg3=](4 @>k*)2< j˗.Yp&,nn'l:?yޣw~8uork/a<bk[{!VX̩ijQP@./Ī#n j .e h*h4|lK<6nEv,gΘ>m +sYF;:ⶺ& h9 QH<[53ٵsVͲx&ӦL4οx):+?<:gɣAnkKM"kNr@>,, 6`Z6 Q/K. ll;p.dNHLN9d2bT&kjjk굣#nkkkkHj4>@# %Ko +3TV{Lvlۢx^M`ޜٳ>%N4u5tGm:s<Ώ=wUϵe'J+Ƴ0 >X,%IhMFmpZ3`22L.`E2;:9{zhe2d.@2kaˈeRLoh8wܗFۆrH5BsA#̌#)g T.Nv6*K=&wn7x^x^p\3OďчG^soΏz{wݹ}Ku5K4pဖ&ѦPX>MLMHeL.kav̔>~AB´2!sr+:N,Y eW jBn!j79 mUV"m\vK/7gO0wӠEgeou +c`/_S_?y44AOWg=y<3| 9>xyz%A4"‚gssBJvٙa̾~AIo\xYp,$rS5:+˦&vэ 4|(~..Gʐvf%dz͛Zt%Ǐ3C gEgeu +caoG}=;Ϸ83Ueܴ bFG7ɀ|\R\9>6:2,$8=ųvCׯ]rE ~?:O}3/]٨+tgHgu74皳U'J|3"z{Q74B M@ Օ3SbCxQe3,{wܾ|/]hxI-x8@ +A! 7@* %ظÜ̩iY9yG +077S/eRIݗo 3MFМ7$Gx󹲂x.)Ԕqёa!~*˽fF 6Yb~-썦^wSi?͉^^L\UIe`]`޽` + c@t9e> ,`^FQe&r< 9wPg9TWVy>Ӧ~@w=jStvutVkζu][x\w +y>y.B1)3RcА h޺!a8 JQ&etY9(892:&6.!dN%MɌ 0C/k,s/.'i$ M$ B|)z +xz_~fƏ9aC :uej-٦f{cIgs<_Pޒʌe3KĤT!~&]fUU:̜eN%e+D44jcGxNKIJHuukV.[p9g_ud tf :)~ζ5 :3g3U I9;|€@@4 HCIM޽Ue"A,9ߪ,kj$e20ytʐ&Ih}|.>x?c\`dNf 2q2k,`FenUצ!S@CAK>c>K盀(D:F7*3ed2ZȬ'3,TvӴԌh44\<L؏9$gNsI5G$ۺ8;ΔLgępV{)mpFu63|ܨ%%\|\gYB'%BDѱ40џp(2̂f̖2d0S.sķn/Mi!4U p̓Z<ݵ}&O+sfh:6d0t~QgWuneoYS8Xck|ynx|>C}4 +D$3aQ"*23,3d5̓3Y|aPMB#O\oZVz# σxNIJ ޽kyyQ׆ 8o^k:;9:4^2MΊ: yYZR97;3-%1>&r_hϞ۶:" ߷Wn]:wء#ҹtV:)muVth&)—=UgNx.ׂhJH4 H#E$5}A!e` 2[:|S$I凖3́]PhlkTWV@<-:t /'3=%1.&2<$B)'M?nyΝ:vhAQgj?v +g^3#@;,D >C@WC@3Qhjh Ait0<eTY.K0C2 MM.^tYJ20[HiO๾H\VR|‚x[yY{w옷Fܿo]m]]Z ,YS8:[g:8 55\HQzM)RD@""((Q좢"v#{b# Rؓј'f2+Yw>y3NJT 4& FLc5Pe22fmYd f}fxf| x|ꕋϞ:q ӆ& tvsv2752衧EJ'7t m#8铊g1A@|F 4*h,4C40 | PF*Ci!t2?i} +e~!Gf:903@h?ѷ"_!q<4k:ܸz҅O:غѹ`Yi)I Qxy:;47:kki ++dhFDwӂuXe2e#3P"2,e1iϜ"3/ުq҅sH}y: +tpu031ޭ +3Igwy,3kg*!HhD46 }9-z@wIf2safMbB9>B`xFtnת/O;r3K +&>lHb|LdxHoOwG;[+ ScC}=ݮ:55TU(YI:ygexc&3%*! ]#2 Xf\,F484k:_z3U%EyƎ<8.:H`_޽ܜl,M zvTWckdY)&ry33h$4M4B4^S1Z 2 X,< +\ +xn}ზFYUϟ30RQ#M70",8ɾ~n]u4UoH:g%YyhJhh`4R;z +Q*Yd~a+ˢ,Ygx$9Ǐonw֮\lΌiSrsdHKIJ/P_ONgM 5UdYY Ͽ yfg h4@hh`c#j1c2d2 3?B*Bef}Ʒ<;߾eiG77!knpu޲j yaӦN1,%1>&2<$ȿO^nv6&F=thki0:3Ig6> HRPWʘe+2 3b^&4g|*πg'oy;ҹryOe|3 3fϝ:ٹmU͞1m3S  twq2752衧 YS]M?I:u`g%Z"L hZhhd4ʹh. a1eY3;@W/?k}2Cܺj% ͚^\7a쨑Ç&%F١Ng-*GGpVƉ%\fFDSHsc>f)-1]YZxйW/_8{{wmۼ~eKΛUZ?)gLVư!#‚=]lp:w(h#8I3hh.rƾ.2Yx,O珔ο0: - wn\:;|`έ֬\`̒)3SF&L)Fp&|kq~|?c %u~ +un:޺y3'ڿ{ǖV/(/= oQ#R#Pl.3LdhBE}3Zi;Y0nYB[AQySϽU9TiuEPssBTTDP@TTD̘d$#A &rvt۫{;LO3i7vu}S@93=erb|LTxHc/;7ssqv`Ό)&F:Ztnt FSſx,4ܱ~eyaVo Ϙ:WUV{")!idؓ_o{_p6{vm\klѼY&7VDg & 23L2}.4;B&u=+̬߯JיȳRux`޼v;ܶyKRt9|E8äM_ +-$ طĄۿ+rojPJ ߣ:de$'D=sųN=tp]":OC@gAaaJɩ)B}gεt%\A뼜ԗI 1aO|=ݺ~GwؾܙSM&ɡ(΍ 0Aaႉ+J\|KdΥ%EιٙR_u(A睼tỜ0a8NVUfZLҹݛܬ'ޞh:v@thΚ):ӹ Ί83L7c:WV":dLJ{;AC͙t1l~}4ztnGљ33+Pgwg)_U"ιٙR^<ys[D:q:d )uEu\UQ^ZRTM~NVFE޼~΍Kg#2Rg3L ΰϜ2DYsA秈":y-M z:45ztRg>u+2~ gL4<:TWUSt :Ϟd`?^j;oۚs3e0cO h 1NJ$:t.&#sH[.?tpޝf̙1H_W{Ԉ(:wܱ}6tnttfaEiyV8`ɥs#Â|zܹz>+˭֭Zhެi htܭK(:qFunLtfUn3V>Ca0q̥;Ωα΁":8:[6^cyUB ,,b܄P dy8`):?E g\vغi)E z:΃5zHLYi,̸.cr,sDcL}8`?,:t~YltxH/Igsn.GٳcgOGt7v4*y 3Me iN8`I,ι$F?}3'eaq҅sgN5`5b}tnDt[fvqE0fZi qثŸ>zpUsNu<`{ǶW-_<٘5{T:: ,tEn;nhe3cO(^&%!:!:'|1'{wm\(Ϊ\̇f\]&Gq2,t]8`ɤs9E缜L1/=u∣ݾݖ6pܘ#O,̜.ocghNynT q8B,A~^o]t{woـ` Dg}]mν 3ˬ$XsroXh|s!0w|tCMίRcžx8-rϟ;{#?߽s!_za>bfϘ*ssvfZ.<84d3ìrYV>QBknNȳYLhtnm8S:_83 +Ёko޸?g4U:/}h̓YUVal3 +k-2з3u>{湣һ F:*?yӆV,Y8otH籍#kY:id tهh.f#ee׎s%݁6S,p3y:_Ҭ~{vg6[r٢sfB:oj:dPa:hϷٜf}43`VQF}`5WZ!Y: M,&f}Vg;i=O,&f2t|QJØ ?S:Տ.]6tV3(}S4+if23ftXf(sq1i4F%>3ls'g8?,/@:9u(OmGJ֯ylSX:װtɂtNY-&]U4ѬY3U"`lqqhNj{2yt,p3Η/gO6uvحA`|c4j9, e"Pfsz: ,#(raaaQQQ1D7#3Ss'g:-/7_a:? yHM8aİ!egNNsA:86 t la4;J4̱q222 *#eea4(/'H4 + M@31eϘٸsY:^3xPY)sfZJR|l uG=:P6ijN hv:ѬYkYF+ʪ! \TV"Ԅ4#.W|NKYϳa<x7ǹuҹ8+a+<Ѓ3{cFP/?OFjJb|ltTDXht|3nZh6< (#555CatójK4@c?糆g=ڈYLL8|J .ߐǖ/^0Sk\SC!d&'ƹP`h-rÈ{Csl'Af5eK +2&V[;|𺺺4᪶**f<P<-#ؾ nV\3"=$Jgs-UxxV̈g꒩[8.ufqfN۴W/|cٱeeK%IBA0כlin1uY矇yE3D3 lďfgWwO1I1˄eDEJs`feI4"MM Mƀ&><|T򬧫Lx&:SwL]z<;Yٱ6f:D7ߑtΝ>qо]6^\V_]^R+MOI x8YƆKu~Ygz7G9J#Ss <]<DfHadfrQFs + + +ɖ¨OpLgDhh,hh⳿O϶6 ty[?<8cmLK?A: 7]pԱ#ܺqmoWGkS]UYqANf8!62<$Κknblx'c)[DŽf %3s f4{y2C2r`2j\TT\\\RRLepEEh5*KM&@C@} +|VyI<Ϝ%q33;vZ7t~Ϝ۷l\je[sCMŲlIj(&2,$:ZqLFyH<~~{(͋f#B3Ɩfwf?9*:YLL\P(ȥeeJ𱼼.F Xq1 48(O峫gE: 1(-/33;vZ7b:]?|SǏܻkۦu}+K +2R⣅_oW'{[+ : 7Y H>M)E[_u™سcƵkz:Zʊ rĸAtkUdT=i6$4[phh +#h)̙,3qbQFd2 Q4M-HKM!>DG +1}yrgz: ;V)[^_h,؍Q7/=yxW/?}}o0zҢ4qBlTxhRux̳Kwj< ͓)4͟͟ O E7fAX0*&6^͜N]Edu9s,Ch &>cc0Cggْknfbldd<:1.y\̎(6t~wo߸vSǏܻkۦ}+77T,[-IMF@gS:ų*< #DJf%͓)i’4b4 #cD +! !r e2ѱR1|6QDh,|1sgWܔc<$33;v#_t~;3'>g֍k{:Ze%yYI0Й9T9\gy֍{~P:SRiI2C1S0ˈ2ݽ +CF>QWWg'B݁F@&>gJSSH>%Ύ̄y3gB:8c7)t&8Dҙot_x7_t􉣇޾e\iFJR|0,$:[+u^0Pg%M2$Y;z@A׏"%&S22$0+e o5l cۃLw@4%4]]UY^F|͖fR Wٯ(<'ǜdw5 +XYcPEH.UJQzfFzQD,qm ٽ9920\gߗDҙǙ?&t~ 󓞇iki,^%' ⢯_ts>ost:3Y"Z?dhޤy+м hޯDfK+k[{G,3Nf(ffp9 & IIBP$%spRh,44x>etg[7kx^3*733?~ +ml:g@?N秏:;ۚj+J +r33REQWB|<ܜm·t^ at֘L3|e%K_0S>Fj@aلDyGg*`P0,A䔔TXG>ũ))42@\ >8C>XG>Yf,3YR4/ay=yyhfۇ~5"L],H䬬X.g$;;+ 9-AFCGCE Qg?_o<مYsz%/ξLhySpcufᡁ/?{~G{[sCmueyIa^D, rwqgRgg~t&:C:!A֦[7+J +r2"A\`^ΆTst&tgX-e +3#3 ͓1Sмp,[i>v$EE_P,3If 3rR\TT\\RRr|.))..FTyHh +H} !1ʳcGٵS :jS' 33?~nt~;24Gtyޝ-u5U7J r2SEqQWB/z^pv:۳ tܰñá:{ַ3xVQA(̣2hJʔѼ{fSPh ~%"dNH@2bҲxx3!Ai0 G4Z$~ 䉣KyzPc>d󴉪33?~NJ~{{wikn˯\KO&F] ꬏uނc|$)J,_QY)вDȃfifJCREh<{ vjdt jf&3 TF&WTTVVVUUīOp? t!4491!.&923x07=ehpȡ8oKF:|HI\yQ:(B:?homn󲯥b#C|<ݜsuގXp|dysq<:LKYJsN90KLhVRRde| +c1~>6֖gLhK?U,Z,fc8쬦1DMJ* bC&&j-b/(ؑ{U!BS1vf9- {;8|_ 8r8 |94,"2:6.!eY23ed\__ v[><8z$?lL/y,tv( %:sDggez3#Ws['kpfMue9NEgyj% ϝ5sT7IN< ƌJg1h-cZC f.2uf}CcyH4oݮ氈̬ܼ"Y3XF~ZbF밠% 33Rϗ/ >tCڱ}u%ϛ<@cYh:2e-׹9NSC=\\(} yтy=ݧbQ<Hgς hfFe3KfIfH3F3ЬG4[r'"́N +>{%9*&.>199/X.3\f,`qџxNL(44t \^V9#-z⹳'<pyz%Lr:#}2e:Ψ33u׫mϟ>~x4ݮQSU:gK:c׭K>e2ʁlinjld<,3,MBiiT.(Qf)@HݟDHsBRrjzDs~AaqIYyE%eedLӌhM>c?c>JYY^OYUH_^wz\ssjR|LdM_ź}ڔ.lafjld7VgZ ,LJ,fHf<,,OA'9!^r4i>#4gfW^cL2C4̘2Ie0B!MDSCCA?zD>P>ϵ*<$%FGb<x=W =Uu#~$ܿ?O2L;>tt_΂O *:;mްv5to/(;7Wنlbdh>2G\hP6a0!A/$Y4[?iHo$9;'z퍛ͪ2?y0.s_^i9Ҕ 4- p\RT '%ػKo5Ο2|s2e :d:?~QugOD8oٸx;{ty"q&B>S?3.`szYGPYt`dlbjna9nDg@`!* OҜi.4ެgL2dbF]*cgiQh*h ǏsscmzUe9񜚔OtjTyC΀3ܯuVpV6{zުsYqA蜜t>yvĮx^d9Ty/Uՙqf¹ HWt{PTEBKPl "b%1db&ʚo9tb?wgBz344JO2Pfs +͎.n޾~A!L%h#4i9wBŎKhɌ0\f*?)4!Ƃ&>~x +a=w%;Chku:t@gDgY4i_8SI: u~|"ѹtm݄p,_pu\<'DρgWgG{Ѷ6VF\@&B`4nl`d,ʆfWw/o_9,i?y inE/_|S^'LfoCi"4 ,s-'jI<ځGX + : +ꜪTgCO[ut&:YYL|Xڣ5NJPi$S`ʳX;ϖϦ4 ИЄh0(->FY&.3e2[,=|樘89g2vGYi4 Y f2㙦B#D}|>OdGNL_Šd9Ihk 3#}]s_Y]M{%Ir'=-+ y榆z躃8*^z E3I3Rb#9=]]ǒ|~6# @CASuѸaOTYo,ށF_@Pph8Ҝ"yFa74a473/] +4@eǼ9_MF!ϏsLy~N +Aaѱq I)@s9SN/(*U*y3\oh~LK^f f1&6 -3<n܉F\_{uX :/(+-a:$Eξ^.m,L tu}4V3YYYO?N&ǡ{wUoyQ9K +q<$%ϑ$yhRDh$d !,X,AfO/"s`pH)iY㺠yC%y>Bs-hq=fQ42 `V@w~ +H3>|I]NgGGyU˗.^0x!9591>.&:| + Th$Fqc> 2/ +ќ 4(Y2{N,[!2Qi~Ѭ 33]M$41y!>s[<2Ε2LJON g:[269bjkQ +:ΨgHg gi>NL͍ uǸx޺icź+/Y`\๐9;3=sLT$4 + Da>éAD昸Ĥl)S!? 48؜͆*uQ޻bAz>C{U v@K\K\sߧ3Ì`0j澼/>HQ:O6̎dqu~>cՉ⹹0/'+#591.&*"3f&Ɔ೎։ 4jj`44=NUU02ISz̖[{|f94<2:6>19uB4eh)3f!|&3ϣ dxARayVFz:'4TۻkVXd~A!aٹu$͝bi~$JG,OB2KDYL?Y8_( hG/@ب`>POც{vnۼaK/TV3{ +2"Wggv& 38[Q>bu@hhhM 0:N ; (DL 0A3[ql<fo搰Bg1ͽDEc38܃/dvuP:c=\KsC]ޱu5+,^0_ yt9Y)ZNggv&9Βu~錳|5UsFd>>651ѐѠ@c2b\a6538ciщwshEьhNJI4 0ͯLo%,1BS>3x+O22@%XȰ ?ow=ǎ߷{֬\d򼹠 +dH:OQ:8c7ى_:Oq{ Fg֮Zx|%Ίd 2%̎ݤ7q8FTf1,Nf,K$Z"BL +ҹҹ:X618uQ{wm߲qK,TV3{eeh::8c &33'u~ xId7޿wW}: +x..Rp>>{yS<3:ֹ8?'#51.*,݅k9cfyڞ6oXjt.'+-3֙ř?Y<~ȌK{fR9'+# 3s/ 4!4"ALs@j<قʈeef_ Q1 I)T4WV546;qA Di~i~7.Ϳ @K= +Q q(?;#%162,HOwlݴ~e*ͅtRA^NFNiS,}3#^|t<߼~>sJsQA^g簐`h nhgud'.sƽ\0C2GDFfNHJNM\VQU][zh?04=$3AhxE|d[K22EDFđhNgIe9y +U_Q4N +GYUfge&D{{޲v߳cu-Y0wÿ4oݨtu6Z: 8 f`xM̋Gwkk+y<ˤLqzZJRb|\ltTDx( }miP5lm,1EQ1T4gdfIsr +ea +h.7unBY :S:Eyy8޼qS۽}ˆ5+͟mj2y¸# ؿOAg„pr:A78yxNmMUeE9lI8#s\Lt$9H@{Bv-0mRlg ,.{D!q I)T4K1Bs\Um` p_#+!s2?G,`kei~̉#ڶyKΛ5cƎ>t~{~/us'0a_Tֽ;Մg5ųQ#su~:ׂΥ%E쬌Ԥ3'ػMW/_pS'A:ҹ7Ν;vI# 3Lh!1 (4!:8!a"490((.k,&2Pfeh.Ks_h~gLxo uO=w\*Ti 1A.v,.=ym^f҅f͘:黱 y,,L׊Z KF t(0 No=AXYud.e.iF4?oO4{+:7t֔ y285)>:"D`kei~̉#~ӺU/3dG 2^t:wѨ,,L xy~֨33|V|F ht( LGʐq2],9\h&47|F83#%~<=~:WWjJK +Y)qQa>nN6ׯ\:wء}oٰf٢ygLLy~{b:wM翴m: 8 չggE5>+y@ `4" LE-33OffG:'%M/ziͨ4G>2qBt~ +:߿[[]Y^*RH3ӓb"C=\o޸jqɣ1ׯ^dܙ!njҹ?„t $ܺhZ4h0%h_")ˤeR)LEY<_:?k\UQV*dqZR|tD߳cƵ+͟m:mqF %W_~A?O„[6_4<))h0h_"22f6y2ь4744>k4뜙[p'ܻSS)+).fge$Ex޲sa׶͐KΝ5}*΃etp&1<39M Dр4( LL&c,K2237iyLvJsC}cԹRSZRϑf''Dy{8޴4pđ$W-[< hH灘ݍ„̏g]g:y]Thb4 J㲘QRDUF $2 470/;ѹƆu޿[[]QV*dqjR\txitTC[[sZ~nZRźPhŵZEŪED@qe5% dd͚$nw&-s93,7wߘK=ģcG{r뮽+s8cXY}< Z=g:3 rtQa͌&HӚїPʔee3Mf*s,EFs + 3G9@NX_[]YV\xؑCܺqݪe,}s $|#|7y?#3%paYL!yI>w|>7),]ZRL& όfHSrsle2U9?\\RaLdLD[@gʬChZCu&tv47TU=|0{wVƖ kV,]ɇsft j:ؖ9Άx6癄3E3htEyZM2+͜G_&X,S+$ 5%EJYFgnou55T9wWMW/_<fMI^|#`|.}7;x6y&3M4 -&F\j>'PLU,sY1dnljnvH2k9DsiY393\g/hkq5VW8vP[6]iSH:?=6v{~˰׋t/&3LيSg3gsk$BWh4c8zX,`,dv2hq>AY:t>E9ZkKط{GW,Y0o.M^!>#I:UI+lIga^gYg3gm> Y@  h4Qd e2e +3]mfA4;`XɿNnou55Tt޿wg֍V-[G)4./JN:g KƳ%ϒ6hUhF41"͘6]*3E2eќ:45:#t εeyGޝeγgMr:0?\u/mIgaI!y<})>@ :4[ 'T&, C2UE4wk9hufg+ҹIn:T9wWM$ϧTϩ|+I?ٖÒXxVYYZ͉&FSiث e2gY,'9R4;Qgν":>P[]YV\xؑ{oٰv҅|H$=%vM:_tYlƳϪ*"Ђhj4SQhǮ"ff2(͡3#t U<ڱmY$'t~I5b_:g K֢Y!E@3)-j뭊ʪ!u29 +>Uʹ8sy:w"yy:Tt>[7t3DOĒΟOL:g KcY$RBhBXKe2wK]V`YKsP3=>3I..yGط{Gf%t@q33%qayV|-|@B \ivc1~GaYuY|Z9|4;Qgz4NyP:3mėi:?JN9/Or:g KYh!4%͕VZ, u0˜4MuMҹ[]M $X:fŒ4""Mnjy:іtEВhW_\0ʬو9νj:΍5UEssx:[lѧt~M'3%{|̈́Ds-&VYf.`9Ui6M>t|6]:?k{:g kx}- bZ??f SNgv< u5<ޣMל9f>K@BF멖8Uָ,ì"SlDgΝ~եs. ?Ib:g sZ#jt)H.ka6ʜ4I:wt.g|v}:?cs:g wxV|-8>3#ʜbq#dt&T_[]QZ\w4>]:j?LV:g {:>VCg-`N¤sWӹ"g8"3?FUez\Ӏf9yIGHl:g sĬy -W8ͽ.k`˜?[c:1M+:&39daY$;os4IJ: s.;(39g}[l9MIgaNG=cAZmlQ\¥stVb8cfdXf|3OM*i:oJaIOgaΛ&@Lj}_?^3I^t.|i 1̑3CJh #lv8"Okҹީ 1̩33 +#q^+ HgaN%$:U1m:Lt6s>K<Xx3p0/ Q#=Zyi:URap:Yg]:wZm:?mW:g K'MϢI63pư\iѤsc8cXJ*G7yi:ߘtڃיsi: -t[8cWuNtK" NgaXZ/tn2)DZt9BM_" 1 K $׬ЧQܕt?r"t.,'Y NgaX/t.5L8c %뜖ð_"gf3p0,'9g \iϑt~[ d3p0,g]i:g |*r:ϊ2/w:g .('t~DJkMga i:O:_BbM:! 1  !syη{ߵL \ga`X|' 1 -yNtAB8c6(s:gH0κ{b?oφmػkkGE"X]AEEH齗B}%LO|fB1 ӍL -jΈ3ar5y4Mg0)%=3;\T\"aZq,y4c"):yzW/:;mcktM_BM7_ :+&c⼏[H_)ƹ"g ôle6KYX(8g$%2tpwc|,-(:ϛ5d}{کC;-):7fLYDq-Ks*o8'q.(qә3aLL8|^nvfzjrb\tdxhk?Ϟ^=wC62tfSMA燏 yK✞ +E$ :Ka-Ĵ'I y$iɉ1QoC}<_=t̉#Y[Zl4]gL8v!ѕ٠uϿ4jP_ 88Ϙ`銵fvGO|k&IL BL%yF1 ӖIDm38de$F {{_xQ}6;nZfsfN<~atnoFEߛ6iܰ~,TΪy']v7w`Ĕ|lea+aV̶$ErqN  ~Swn^|Cfnfr٢yO0xȀztԡ~K΍6W3U4TܡS7$#ǐ8^dŚ ۬q7 84<2&.1s.ҙ3O0 pI3fgir2Sb"#ކxpw{x™G:Yo߲qϞ1uҸQ#ۨ[ [ܨA}=:-gο8q纝);IwRde يB!,!TȾDY=M朙~14Ιq^<" z$aQ$e=|T^YS?4:1=rt&yށh?I myu`Og[sCmuEYIa^Vzݸ@?oO7g Vf&5T%%Ąu޷\gz: +u&|U ΦΜsr +K p_ Τ[<&4QGM8xfG{^4=,T 51!&2,ekKsS#}M5eyC"B\8X qEmיęf88K*89gt?3Y]SK{w*q߽ x>Bp8t"d&8ןSp8j +e46#l<1:Dp8E费IL8j+Je܋ rH_GSMY^Fꐸ?/v6f]$tgNngeg kGw/߀{)EO7vt MN-,-\ txǿC?q8Z"lڄL4Sly}muyGERbn_dwZ* +GיL\gZy=yKW|ߌ}')-3E[gOΈg3 .$ i s]Mₜq!~ޞ.:X[US:$."un/_;:_p>͋pW|%O؄9ŏV=on#y&pTo}@0 8/-Ώ s31A>W.8ڞ;sꄑEx9ά̌ t:w8cp8)7:qy;'7oЈEO*k[uRg3 pT!yڼ \Er/>&2,5/wZ*g 1a>n231uQ8s +< pV88u札U踻)YyUT6y|rz鼊x FDSzpTл@.!66 qh\RpNy#dw&Ǐik*IKJpXqF:Ӑ:8101p8ST345utqp#;iŏV7< 4"pp + `Fмmy|tx✗H{QU%yC"<\8 85]qYVQECq3 k\MHL}_TZ^ ]18=\G@#Lp85E \~e46OO(*$͹^ +uE88s!e5u O>{_`Hi9tB FSZp8i&`y~%D3y +<:<sW{;|̩FZ*g1a>g&/py7=#3 OPXLBRF^IMSGĩ3l]ݽܸ ;!uͭHѱI,p8 )./-kyjr<lhkin8f|- Li?3 ;Y,-zTG+>Aaf>< o*JcTA@Pޤ "RTW;ޤ* + +`&),gMYp>._p3\DS +JZ&-Ϝ=weoЈ뱉)5Mm=}#cgy @!^oi4zsbenn¢R'eU4uLͭm\<|EFu+*f50:s&fVu3 DFs/H 6)yi^^z0OlqnidUWdNNvLt,FpSTV349muBqas +*kXDa,򼼺>H4kFC!XO ȼ4/NOzqegܽz˟U5t ,m]/y3뜞[XRVU[߄: ML!ph':MhjB=zȼ4LMsFfvWGksCsAnVzjQWC=\>ЧpttfpGeTԵtLͭm.] +O}^v^r=C#yfn}^^A>i^i4Z?zľsH3l3FV sQ^;ɉqC.]p->Ǚ1A!QqI)2*jz&Μu<|'-3'ѹ,(,"&8+ijuvvq~-:6!]Թ~Yeu]}c3?08@s'id4Mh|)DkT @_/"6feܽupRWUV9)qg!Qq )2rʪZfֶή>WB^Ht/*)!w`|":gWVײ.jF ` \r__/i,/-)dlK9PO[SM,p`p>&(,"&. 8+*ihZK~:gf p s Bwi`F:.Vb`FXHsE9VRb܍C`w@W[CMEQ^ԉ3|IXgUu-}#:_Itv/+'Ṫ}njnA;:.F"Y]`֎.4705UeL8O2ug X *HEQ`Ů{7Xƞ>)IffZtr}Ϲ޾NwK SѡH%qvmҢB:S)_$uNM#sLPl4c^?Hy6x~wI˿x7<+~A,x7lo⛗fcѱ>a>Ye-7K9Yje\gqg*5[BVSS<93xkg<㞟7 _%?}o<1~^2XA/_:6o=xo vwhk][d,605jBf [ g9%E B׹d9\յ 6Q % ߽by<'Y ~`.~d>9:ʹk+KG#6i +sYiqaANT*d8矮39t2Rh.V9^_}cSK['y,_\^['Hh( Yx<'aPK ӽЌm^^ᛇ"}=́6&cI|_95[:_\2KMsă5S`xd|1|vzzr|txto<73lj5kng ٠֨UJ,ss: %Fp?04: <>\D>?!! >%=x.vr||6o 4NO>$;B-Fsq5*<#ssns?2 gArJ\¢᪮-m]}$񼸌}^[$>~zŎx<fwxv2d^[Y^d4ǢÃafsSVqf3 +YF`SJ:gu\\ZfV9ܤscSK'y&qϳ4yvY{< f_Pl{,e yldh6w 6zN"sNFReps o8cRXg"7C49?/hz}c#(xx$  E<;=5<qmYqsj8+(,*1uo6ut1FFDZϓS4z DյzB<w#[  N2=]mAfG`qHg6_δwuaY9 :Y.,l /WD/7C:%Zy..1q4&}@JR <D"e_mm L0K2WH4 + rs,vY94si ^(MNKx</Ey jM.q\٬N|{ Yd:k/, rAirUxəb*;v3`f2_9/WGۜ`s|=/uV%|$4]iZxIS.'Pm`\xfA[;m\aSmmRB4QԨRaf=666 { ǣiؼ\,{sgفVh1ZN[M]U~."7fEy'|8t^<'g +-DѪND4 +3."Hs͍΃lY|@F"-J[_]L\/+Ufjzݎ/Yy~< + -F?DD.hPe},4*zmnm08YRM7Qg9Mx~ @B٘vs& ʢ{_w&@sWUcǹ΍xN<hZMO.5 ʲ0r?=lyl8u:zk<-hCژM옹srYehۼ|IQϿ*sZhSHD4h(',lYmV;6?  hZ6$+ s Üe4| 7sـvhEhE8gY\ y<<hڌ6?D_bMSe>ɜhηyq\g6Qj"X3ew/s9\CؼMgy<>+*NR͠ۍ9,g]gOsg9Bfuh.%"s%@se~8W:9\@ntP蚈hՠM*+ sCm8:<|VMh#:"&"K7Wym K_whk J]MF wYO\\gyBKfTl.'{4=gڅFDD3-Wl24q \54uav7d{:<>GѹFk"I2i>+(t6嚈h%0{4Wy|=*5:Wz(1i~?Vi"y5$/|,+7Ah ;,aiu.x.l"[+0,67<|.ކ4Ѽ<4:W>7B6ͮU(6h ЏPh^le>c>wk"iAy\x~DDe3Dыmy(MD/m>̏hFLidh")].: DDN r۩!":iFz""g=W 0F߉ +endstream endobj 264 0 obj <>stream + +endstream endobj 259 0 obj <> endobj 265 0 obj <> endobj 266 0 obj [0.0 0.0 0.0] endobj 267 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +344.8800137 0 0 167.2800066 -22.8964844 -50.9606707 cm +/Im0 Do +Q + +endstream endobj 268 0 obj <> endobj 270 0 obj <>/Filter/FlateDecode/Height 697/Intent/Perceptual/Length 80679/Name/X/Subtype/Image/Type/XObject/Width 1437>>stream +Hwg%@($BCE@EpA,hђ +({yyy [fr9s7@!B!B!B!B!rlmW![ܹoZ͗d0BB B%[La4Bu]W F#˷,m!ZDtۿB߫C;]B^J {BU=M5!"k՝!2yjܥͅnCũL^۰fJ7_!F0׫X#ke].ך\ָZDgвH^UuL\70Y.yJRw"m!4:œs9r +H1{Bs +K]#4|F-:M˱Cq7vQVnGNXom*dn4|F>u s N͍`#]%::>#^er>_$tHt t'3Bhil20],(G ;}4*:P:@] tg!dj6a]NTHn  b=Zs@gɜrUPd#kJFW綿 +Bhed.er'9x5R_Z{CsB !4Ź egrk6FD'Bns!dNaNqٳ@6n3mބZ[-ѱu||F|&s˞e ;. +^*mNݕm*ʩ̕ɼ\9cYQ&; Ӯb{m6JnF'Bg%ZW2Gse˲W٘lAfwwK{|Q tVi5:$::!J%WG2NeCeCxJO +#gZvFEA#t^7>?Bh9\d,.:e. Veg)_:tP +38F ѱ ɀ<#^eyWe'¬2Wafe-,*; ȎCᠷ8 Nicḧ́v@ogV;32'sfvyԺC]fe+ʊl8fHG]3d+Ԫ -F;>gЫ+GsGc73v/̲Qٛ [cڻ+9b+^i6ZvNNtU!Hi\Y.+e%Y=f{F:aO/(mDg]|nc"Kh+2Gy\9r2lLVc6$wJ:Iȑ[Ei5:! ]:/9! +9/s4d\eUfd}:ý1'rFkZfhZ6ztF9;3Bhx4eO,̓gZ\Oa; <潬.[Ce&YAp"-w[kZfh"ZVM z]f@>oq>3=|2#{bSy'D ̡˴eQ٣$wK.}~_Zi2Z#6^ 等̳!egs@:Nf3d.̃yz:tֲlTVd |CMg. jUZ6Fд@OMf|Ũ8~44G2'yΉ]v|ǽ33eʢ&1{J8 EjfhD4h'fBs>D@G@O=1>o<4480xn+#^r6WiUs2d"0`>uw2L[YT6(3X|ڵԏ>ܟXiM;ڬh }&y@ON>~^sxF-\ټVl4ќ9̓4d>xa>`>0w`Vy.ZL*P&Ȣ1|ƍr?>$lVeJѴeE>uJ>&@<l3Qy<#9ٍd>pa~;>l2,kY* J2߼ysvv3sS^ 2HLh+&瑑ᡡ|. B-9=f6G4hMC< 晳3|Q\kY* L2,n9 _С-RӤ Fӎ!MZ?@[̀}޹c1s?xF-RUlNiyp0's0L0sfra.Zv:oeYʌ Ʒok7ڗA+:je%;Zv@K}4><(3xF-x%e64<2ȼe޻7\Y\&eˎe$"oQw;SVic+ ]3>)>|f-f> |#ͽ29+299/e2lQfdgϞL/Pfib)mVc=3:狱gЂls8OsEp2+<Ŝ,.Z&A3糑Kj#+i]\0q6 h^,Hfa.P`v2 .3˨2 333py7ԉGpJ\#Ĵ40DZWJ@231Qa'C)|Kϳ5̳g99ϙ7nf=$s0ˌ 2s2q2#̅E`V]'˓SPʈ2 ij7a`_ lZ( HCIOMN*D ]]UY!}NW}|Vy|F)Yϋx^ܗ5C8;yVY4S4R3fنɌ0 Uf]0. QeBLF۷ܹs{W|38&j`FhhQ:FZtIqQA~^Nvl$M q1Q||<+y,''>f%f7A ,d6VYMf a1lpy,ʀ2 sss󰇸oľCS~)iP3ӈ4 TxZtyYiqQ9-5jI4')<>ijgrrrNoWh)fwO/oD@ GsTt 73ʜ2C2a2B2̵uslf`ZUd$=f=z@{bw8cQjfhh&'4 @47A@TUV϶dkR6NE,YNN[86S6lvs4+`JLY9̅"SsfM0.S-VF e4EFAߧO~=~@S~)qP#Ӡ4!!D_Dkftur@7eHOMZ&簓A'E=vD`P0Asٖ_2W֟dd0]Z&Ae ea}Oap?s8z8% j44MD?YXxBx<`ꪊR\%є<y'xN<.YƳ[k17lܨؼl޷!w/ÔAaL595=ennimd'40kY*#h2_8= 4+ HH4V4D#4} |"ƆSu5Օe"33R-x9T˳_y75񹣽tC}m9ٶdkn<^<_CNNn%(ׯؼ]l=6c6G͉9 hhSeUyW &eeedTVPFc~Oa&Qi4-Ɗ)B W._p^LWG[ksi5 sm)֤DS|\LTby,x^ϫe;>9uNIٛn#s .Q\, e2D?=КJ#l4V ;Z' 9޹yb|ldxG"9<'ky  3ƳfWO*ɳV8/gyټl`xfsfVN^AB3Gso0|¥Wgq2 zwP +˨2L&3H`G/wjrFhhhZ$Z s>_pnjs/ssC}mMU򜟋<: y&grrrKktm;wwࠛsgsAQIYB3G|uWTU(Ɔ`GޤX( 6F+^) >;N2Qc2IL{}:׺/w}ַ$3܂`Ђ\e2BL@f?F{k5U! F3iBF}.).,?{p) qρ,ijx:LY+fq'Nbdas@Pq ˓VNa4h>p(7/d.-dnd!`fe\˘e26(~?i41 ̈́ B#^F\UY^VRTx$0^۷B>oaVDhhhP hYs[ksScC]Mu%Ç dg_;꿊܏A8p +g#cSs+;gWw/oY%qV$NlޔmNBs~AQIiyeum]C#D0epYa2FH t)^S189ѢПZ h܋|n?|^\];wl۲Y7Ago/OwW'{[+KSuijYNN<*'B8O35uprqlN\:u}]?h.oؗCygx{y:;:Z[YLC3fΙmް13kCq4wt'b20 0?| +f첚e2YB'\39ҔhAqBcgJ>ŅGr׮%"3|<]h}sCsy)y5+a/?78(`L?Zg3f[86aE`󡼂Ҋ&LsO) ._5`3Yf2gLhMJ1ѸyCQA?{k 4|qڕ/|n?ւx(+QsxN[:/dN8]xyAgrrt89c ǩwfK'N%6{ 7hKL3+Wy33Q2?zX f 9 edf?gjhF"4*w7]r"ghCHyxN\d"9(ƳgSϓx5dzYNn`pFp=FpDY#-\$nYҪ’Jc'1.hy ,$GtìLXf*+&3xZ.UPsјh.4Mh +˗B@s?MP>Z 0ϻY2֯MY,>v⨅ 쮊g#g3Q<#rrsZ8!nj57~d#csKk;~P8GD&$LY}g6|ڍ[͌SH/4`&2UYAYSwV&D+B#~ϟ}r/]; թs}k֦iS׬JZ,~iLtTDX輐94=x6j43y3!g g==ΣF57y aKW$YfsCS 擧ϞwT%/_Yq2SY4_}֑ +ҔhAhиi@~žϝ9u$xh͙7K]2iyBŋ"# Tleinfy"Q#q<3Jq83UqfM *h:D$( +"A@AAD@$$" (*ꔮ:S{yNshT }o_I5A8pՍf3Z÷h%HWfwYe2" 1 i$da>O+/?׋uxNN'$8\8xg.gg\gR0):Sy3fljYv +J*l5OG g]!aѱ Yy-]zNlwV3D3Yf,߼ Y22 eIi$44|ycվ/@O<\xJOMN8w@?^۶8!lIij.Ϫl2g3Ҹ1km&p^p^,ନRU uWp^o΀=Q2s Kʪj'N"<0 *3 3e i,7b'qEF Mgh>߽s._c<6z@+3(Ue%Eٙi)Iq1#B}wlGƳφ0|GM$y33fsr8!8q^"t +[h2Zv/}cӳU76]|wlf\f y8TRx06:*bA~>^nX<[lYK(q9l3gοgtflgYrObF{-ۼv s0)53y`pd(Td02H,i BCрF|D)&oxs(sC]MeԤёBwƳϫVjl +ijRa:ctflw"/@p]"t2KU^ozv,R2r*k[:tEm60hɳiPW]Y^Z\?"|OHP(7񬧫%48j,eDgyFgf$p^p^,#+' h2Zv'iYy5퇏6;'j4#220,3$XF4h*ԀL3Ϸ%yhki(+-*HKN<Eg;[k4 @9=; Σ=z/\?84xf@O?AɌg \6Mڷ1MZd%|gϓT/_<)֦ꊲҢܬdϑh{ʵޛ@l~+mFYD3f0ӳߨ&;#W\p]M e%9Y)IQB}ݶ8;lXgf%s5,1O3p"iwuii/":#CF;O8>=35 w0q +H(hZ9yG'gaùh515f-]L4CLfb|"h&#<>CC=7g,|BbRrJj6aQyUuOvt<53|`އ4|L4&'<yϓc/_tPW]Y^ZT83@?Ow'{K3C=mM5e9iI1A~.vVݾu:3-XxFtF2v4oݹ_X\Z^Y]/(<:!%#Ys['#cӳ˫ol}>Kh0|y `o7sG[KϵeŅp<`kenj(/#)."|2OΟCtFp23+pDLbjfnaieƖ׽p8Vެo߄m'sȟ 5&3&A y~YC]M^<@WK]UI^VJ\TH UDgd(rDq]řG@DBFAES; $26)-+֎}#cp8{s`3TX?擢|H>y=7;=51sS(KxNJ + twu436PUVdgab Pg@x Ox_RQu0jbj =j&-D_wցxyrbltdh๫0 rScC8Y[j(Hp2?L x83qA8+iG'dT>ildžΐlƑ80\>Bhr>3qyyqa=;359y s[~!1)9%5m} [G7OR/F'g Kkopml>,rЇ|&Ϥy^Z\@NOMFȰ_/W'[+sC=m@gY)qQ!^n6P; 7:_x2J<󵛷12cpV60urIL-*{5>5^\^][x _~!#d5]&4|&K蹙ɉё!l<7C\Y^RH_GSMYAVZBTX2 +qOę37HDlRZv^QYuzQs+o޾ywOۃ4$xބyyyia=;359ƍڪǙi qA>.v*rbuEtFvNv&FDgd(p'YC; 42.9q~qEMCcK{Ww zayum}cskgw·lʌQ>wK㹥I}MUyiQ~nvF٭\D@Kb76I4EM5il{Ċ"J"]zWB!w.[aYqg{k;n\lv[筛~]U+ϝӻ HepJ# Ljpp1{:jz•>rr}peUYM-8K 3*Y{nn 3L<''R#B}<]?} Gg{'HYHXgn$}g1#GI⼁,HM"pf8&aKqVfV +Ymm-3:\6I:Ԥ _/W'v߽ma~gO0!u޼a=y岥@@XgnP%󰏤pp3h֬۰eLLϚ]ay/L8?/*)8s!΍g,G%y"ygZrb|ltDhp37'G{{7_t>rpvn:Y u^L26k^Rs<EO>B:_8wX_~:/G::pnͽ|9-sxt|-=\Z^ds5u -g`NIhͨ>!P3<ϥ^ΏwnݸvOmYބ:=t6 tu{:)yH<~dE88߼cmGCIN!pfqxյ8-Ymk3qۀE繢꜕FKN + pu~|% 󎭛TY q:p^y!Tsqęgm?DYy.y~nvFZ +5K-s@#lH p&tPJ86wK\X\V)¹Y +p5 [;ϝ$gbҫ*JyLO&Q# t>_Γ$tF׹5=1NtGp pT3<8kq&g!}|dTUBrSiI q1a!"޿ t t6:A1@g}ñ8o8o۵|I3U%p42#˳ye򲒗s2hɉ1Q!>Oηf@cPu +u G@Xgn>D8&(ĹՅY;rZrXLzUsvfZ +5Dlot0lv*:Lu6Upj"Iq~@ 7 yVxIk<ɨ(/-.zQJMF|<ϐ:y:qcFt8pV³ynG\W[- t,:egCcD:?:[Y޼X lt&gNS +q.*)8Fyn +5>bE:s?AΫW:5{4BqPg} !!XgNS[jiGQn t8lsEYBsVz*9"4SN:fe@@" u%tiy~IUG;:P:RgFy~NVF*5Mtl*y/H%|pg&G#3 Mge~[BRgfu:Ӓ(qu6޽cXE@Y3}O: uJꌯ3a+e<:wuF\[-#+KD:'(y;y +ysfMJ{sO)ҙ t~tn: +Jy1::_6;wac.0,컌>0wB D46F4ݞg@4 spϹ]-L t9r2Hg:ҙH@:#΢3 q_ݢ癫3~/#!o:1sOʲc"B]pu8ꪓ:Өdt ap_sgL_1#y.O<ձ(/;cER|tDHK(/+-)ΠQDtNMu5WgJ&tKW/]8Չݵc˦ukZjʊ3V$Gz9 t9L%yYiIqB&vg hgGtMy;o\_[YZhgmajRUVLRHDtqE1E&u A_z[Pws|+Ο9t޿gͣC;V7Tf%'Fy8ZikTd$t*D@:#q:C8 OW?b:?t{+Ǐܿg|摡֦U9b"B}ܜl,͌ t9jL%9iI B&vAgg:?C:?o\|iľ[dž7]XWUV2cER|txHG(/+-)NRHDtqyYCAgR¹'طkM:Zj+K S‚=\M t,e9) J&gLg$<tH'wnݸzٯN=t`[F7vw5Tf%'Fy8Zik1%%4 +HXƻ3u A_t[\pu~;_yGwnZU]^\<>&"$PWe*JKө]g\gQQ$,oa߾??wHׯ\:#662׳(eƊW';k S#}-6KEYQNFJAI3o3 IGt7WWH秸wo߼v9L}Ƿ lX׹0/;=%16*,PO[TR`(d"a:sutt/2y)W?zpo\|O۵c˦m5%9Yi 1^n6f uU8J!u?uLe`|wLӔ] +Y}ϒ{֬,EQBH$ +*ʒ-k}}w88<3-;{ȓm{:SQ:CpH[u^Ft#:O!:vw57Vdy$,$m?oWg'SVF:j +%Eyql,iI8BySgXgn3e%~soWGkI¼/b"?kW\r9ifb$DZBLDye>F:ZXgf:y0jom,+.~">&2<48M_/wϝ8al('#uHTX f&Fz:dFu :CvpTyeSqD羞ƺS?{aIq!~^';L 4꼃?8g?":B\Bt!<4PW]^RUB\߽zPO[CUI ]}:RoLE A rΤuFu^@thmn*/.H}2>&*Qp^./;cmq!Q!^n.6:S% ]Ma!://d{[k*ˊ rަ$x,2&2n.L.t7u t 8c:Ig"a~@owGkS}MeYqAnVzJRb\Ӱ{_z҅sglN06RWAYTζ4-_鼾 +qiqa~nfjbld(?'3ͫبGwnz\<q#}M5%#b"|<8:3!g7N0~]u:33~vfr|tx0/;#5E|Ldx?oˎ6f&zZ*r2RDxH@OKCM^gT$t 8cpQgdiD硁֦ʲY)IqO?kW\pqc:GՕdK8YYcdEՙ +76u&./f&F{[+Js2^Jxx福)KsSC}mMU%#b|\Yl^g;ՙdWWK ٙζڪ¼ϟ= wZ*r: +"̶4[y :CFuFy? 뼲DNO vw6T/x&)1.rwxi+F:j:HO߯gR3fkku{Hjoi(-L{2>&2I1W#Bφzy;171PUdgű`1MgƯ3BEgz::S(0CәHZt~rfj|thygG{Kc]ueYq~NVzrBlԕ gNxtsgmif('-!*L`㘱L; 33Z32)鼲H\{;`ϳۚj+-̻s+.;p~۽&4ՔeE|<;錇3m:#:3| '3i:/HDh:Byblxɣ֦%)qёφ!`62%ńJT3Ψj5ΰtt3y03C;;6UUd''F]tǎ>hHOGSMYAVJBTϻ Œtpuކ +3;)鼲H\{;`_ϳ[jT޽s5"ܩ _/wg=&J2"B|<;9Yq,X m:A tpFYtuHyD"#yjbtx8?';#%16J؅3'|<923RWQ悦3 MgΌ T J8qCәHZuꇧsÆڪ{EywnݼqKO>n.M5eY)qQ!?<,HggXgz mpgz::S(鼲H\{;`_wדG5K +r~lHnm U%yI1A>.NvV D@gQjә2yD@Ύƺʲب+aO8~v֖Fz:Zt&rsqqXh:Sufuf:@ +LCәHMgO57<(-{;35)>jDStvqcab R"B>lxf 33UA tpF_q Og +m:Sc}]O4UWfg$EG]8s2>k+3cZ*rҒb"|\8,:!}yf@љΟ(i:#yݛ/g&G{w>n{X[u(έ7_|އ805TSV&rsqqXh:#:oͣ3]W},81::Sh:/Cyӓc#tnm_QR{;35)>&2ِ _/wg{=&J2R"B>lxfo:3Yg4]*A73*[gx:ShyD"R4;[*ˊsғb]8}#:43RWQ@tfű`1L;`:8Z282:#Ue"iayzr|dm *J LՈsz`Po0 љ6Ѯr DKą^LM uw=yT_} 7;#%1.:2♓~>ݜm̍ vkk*H1ch:oθ : A;3JteD"yfj|tygGڪ{eEywnݼqKO8~v֖fF:Z*rҒb"|xf u+$7(tLt&ӓc#\_sԤB}<]lXTSV`gű`1uf鼕GN7AڟtLЦ +m:Bybtx-uՕe9Y QW.9y`љ32QfyDA586ә32㶇 ޽s+._::8v֖F:Z*r2"B|<;998f,f󿾡O;\޺v!|Z33jkKą^LM uw=yT_} 7;#%1.:2ِ _/wg=&z4Ք%ĄY,Xtf(:L^h8U8teD"yfj|tygGڪʲب+aΜ :0㍀;M +c  +ADADPHGzw"mE'N.3=mϞ,LPwΝ2CI^Yy8fx 3 ,1NgTgx::ZVWC9=%1]DH}]m-3T۵}˦kV-_pY*eJKILŬ>aft +(Ph3H8 s}NvwWgƺҢ̴䄘WnvM n^rcGݹmu\d93Q%!':<՗ 0 $Y By+4BOg範fuuӹ0/;#5).:"4药 WZ5uC򅳧O=ώ7]rfC:+tK֙xD3.Ob04$;tLtps}mUEiqAnVzJB>.Ol-LjkiQ?zhaK-;{ %i2ҒSB<:"<px:#8%LO=6 u5%9iI1ao=ܜlܿmZgԏڿ{B:/^8y,$\gQ΄ŢWfdL`S<)@3 x eg> _ttX_[]QV\륫M n^z)5Ճvo kW@uVfY љxO0eMfy*c%&..NzKt'3|W"puŦGҹ(?7+=9!6*<$3{[kKn\xNڑ{wa:/]`ޜD':C"~ʳ\b&c+C3\i@}t)A 88Q0/'3-)>&2,8wuu._8wıڶe5%% 'TLy|e$3f8ʨ㈍?<4h _ӹΝt(-.HM z{<~{v":",<b<@#yEf f\M`;őƈ64hπgppQpJΟz8lV4[\SU^Z.<$sZ]zIC:o|"LgiSI:3se&3f\'"Mb +=;Z _u,y8Dΐ:Cәlokmt,+)LK + x噽]C׮\:qUH[7o\GY YJbI̟=b@i4q&OFz; M3$C:bcCKSc}mUEiqA^vFjR\td?o7g'6Ɔn\x^㔚}I:R, , bL G0̢ܷ\).c(K I2qF&M3q>ACyX81{8lVWG[k 4kKsScE~`g=;7t._vQgyi2ҒS&#:c3M&h^F\FT,5i9%|,1lhh~>3 3pQp +O^l:䰻:?45VWeg&D~㇖&Ft`t^tBDrR΄ &*<8녫̓Ɔn^zد訫3=nRdS @$!$L !d' I`BH &(bRb Xڪ(ժkaɾ{$=}ym&/ ߫b>8K9<4t:{2s~̬'YR>Z+t{THd$3/fY2L$^^^l3x1i$ZZZs}wl7XafuPw֍kW.?WuC}s`g~޶wlhO)qhsDh@" regǙ1Ν-M o^zBMǏ믾'ۻ{wmtγLK'DN `ij g^Z HuYG2`.#ˈ286n jf4-@c@ )Rxd<ݯIh܍|ҹurB3'&ݵn}kq*:''L51<4xB y$lgg4hp`׮NN..nn +̞ebQ&X~x7D5* FLh ]o:T6.6:stI)?4-֎Rq,d~ejy4aF f f22&# Id6pTh4ft$54ݣF*<Ώ#YٱfLgԹp&;;Hz󹳧O;rۯs7/ *K +ӳ2$M<)s8",h(1T&E1d/Ufszق ,HrrrJJJjjjl:|Lh&h϶tBy_:ϙ]0Ӛ3-#m!+L3hq)hhT2LŬ$!DeTPFsrrfg8BihZZ,ǎQ) +uRg^fLgYڬѹt^yyV,]4^ٜ¼YSY+lgx~@ϏijYfԙtӹGw`:꺵kV\xAEyI34 Yhx|V|@s聂i.@2w2̒ddTed2 .ˠ2_PPPXX8 7?Ԁ4B 1E?|<Rgޚ٠]N[sMuթG:oo~+% +Ι]gxNOMN< }T|8 4Fsz̒dvg2E2`^Pyh2p\TT\\<VyQJ JCK(l"-Ϥ36r7͘L.tnA:aK/<+/)<5%)!>.6&JYIJ3ŀ&h43-NpeHf.3 2r#,bV\X&䒒Ҳy NJKi@.D5@c@~DG'| +g7YlƳYgOgLgMLkW.w~۷ڴW^~U+-^P19;3=MIYڅFs؁],Y ɬ2d&3)0EP%2z\QQY9>QeeEBH3 hhs%~ 3(MxVy,Y&qvipf:S:kun#kmt>:e󛯿n+/Y8^ų5'iP'mf6>'r}߇(".\ ,.( '9jSkhڦm1ӦIT3>_H3ggpk%4 Dьi6v\D*,y)gJ2ed̜T9EʒJelXpx!I,d:XмϾ>^[]7K3|Ig9,,n'l0L!GG@瞓mǚ@Jm&_̑b<&'DE3%%34MB`4)=}x * fJf[2{̾ 3&s$333L,g9rBT*sayn +Lh4 #^ˤKh":t;Oo?3tv`_͍]yiQ:W,9?)!.:2y))]6:}f@CAD4!ML3SX&\2s2of2's\|B"L*+dJ/gSU*ZFgXsxXHp`>?=wx^`ogkm?A˗-x^`y<ԙgQgqs1gܳA+F >rP[UQVS23RSc ً%D4 + Dр%lmc Ō0Y $sDd$s$333 ,j$P)***...a+-e k4@5(Fќ4 h^fv6b9*ų@:{q pP?SL_2v3]'Z5ՕZgEaD9"yf34 +MDр4n;-,<%sxDdtL,$ebP.FʴZmyyypp.jjPZDCG h,hI]:6VkV\Y|eQgqs6g ,? :5uorcϟ9vPxV)岬Cf&^On&3$4G4"mMN Peta fS %釰y2\*kQJVUU:֢LhZ@S@s>Q>>[]wq2.913gq t&!g17^8:24s娱Pȑff YdzGi;teRzyL0d2{O9eޟz Mɜ%!e`T!5z`0qZFhVsdR)I PėB>?y7 τXYx>gKݳ:tO:ߟ}Ƶ˗F ?uXSc=s@Ȗff),%yuv6kV\lo.@xu7Wq=tg!?9փo_2v١.jue%3dVb|lLTd8  Bh(Ng@y .)CB#"bL2K2 +)+*uT frYFӰ^𢧧LhZ_[S#5\%,|zz޹]VWXt7!y%O7W߮|!u{gbձ#,;[[ Ue3o 444F ep`F11#cḃ322kJJX2 u3sc U{{qg3=](4 @>k*)2< j˗.Yp&,nn'l:?yޣw~8uork/a<bk[{!VX̩ijQP@./Ī#n j .e h*h4|lK<6nEv,gΘ>m +sYF;:ⶺ& h9 QH<[53ٵsVͲx&ӦL4οx):+?<:gɣAnkKM"kNr@>,, 6`Z6 Q/K. ll;p.dNHLN9d2bT&kjjk굣#nkkkkHj4>@# %Ko +3TV{Lvlۢx^M`ޜٳ>%N4u5tGm:s<Ώ=wUϵe'J+Ƴ0 >X,%IhMFmpZ3`22L.`E2;:9{zhe2d.@2kaˈeRLoh8wܗFۆrH5BsA#̌#)g T.Nv6*K=&wn7x^x^p\3OďчG^soΏz{wݹ}Ku5K4pဖ&ѦPX>MLMHeL.kav̔>~AB´2!sr+:N,Y eW jBn!j79 mUV"m\vK/7gO0wӠEgeou +c`/_S_?y44AOWg=y<3| 9>xyz%A4"‚gssBJvٙa̾~AIo\xYp,$rS5:+˦&vэ 4|(~..Gʐvf%dz͛Zt%Ǐ3C gEgeu +caoG}=;Ϸ83Ueܴ bFG7ɀ|\R\9>6:2,$8=ųvCׯ]rE ~?:O}3/]٨+tgHgu74皳U'J|3"z{Q74B M@ Օ3SbCxQe3,{wܾ|/]hxI-x8@ +A! 7@* %ظÜ̩iY9yG +077S/eRIݗo 3MFМ7$Gx󹲂x.)Ԕqёa!~*˽fF 6Yb~-썦^wSi?͉^^L\UIe`]`޽` + c@t9e> ,`^FQe&r< 9wPg9TWVy>Ӧ~@w=jStvutVkζu][x\w +y>y.B1)3RcА h޺!a8 JQ&etY9(892:&6.!dN%MɌ 0C/k,s/.'i$ M$ B|)z +xz_~fƏ9aC :uej-٦f{cIgs<_Pޒʌe3KĤT!~&]fUU:̜eN%e+D44jcGxNKIJHuukV.[p9g_ud tf :)~ζ5 :3g3U I9;|€@@4 HCIM޽Ue"A,9ߪ,kj$e20ytʐ&Ih}|.>x?c\`dNf 2q2k,`FenUצ!S@CAK>c>K盀(D:F7*3ed2ZȬ'3,TvӴԌh44\<L؏9$gNsI5G$ۺ8;ΔLgępV{)mpFu63|ܨ%%\|\gYB'%BDѱ40џp(2̂f̖2d0S.sķn/Mi!4U p̓Z<ݵ}&O+sfh:6d0t~QgWuneoYS8Xck|ynx|>C}4 +D$3aQ"*23,3d5̓3Y|aPMB#O\oZVz# σxNIJ ޽kyyQ׆ 8o^k:;9:4^2MΊ: yYZR97;3-%1>&r_hϞ۶:" ߷Wn]:wء#ҹtV:)muVth&)—=UgNx.ׂhJH4 H#E$5}A!e` 2[:|S$I凖3́]PhlkTWV@<-:t /'3=%1.&2<$B)'M?nyΝ:vhAQgj?v +g^3#@;,D >C@WC@3Qhjh Ait0<eTY.K0C2 MM.^tYJ20[HiO๾H\VR|‚x[yY{w옷Fܿo]m]]Z ,YS8:[g:8 55\HQzM)RD@""((Q좢"v#{b# Rؓј'f2+Yw>y3NJT 4& FLc5Pe22fmYd f}fxf| x|ꕋϞ:q ӆ& tvsv2752衧EJ'7t m#8铊g1A@|F 4*h,4C40 | PF*Ci!t2?i} +e~!Gf:903@h?ѷ"_!q<4k:ܸz҅O:غѹ`Yi)I Qxy:;47:kki ++dhFDwӂuXe2e#3P"2,e1iϜ"3/ުq҅sH}y: +tpu031ޭ +3Igwy,3kg*!HhD46 }9-z@wIf2safMbB9>B`xFtnת/O;r3K +&>lHb|LdxHoOwG;[+ ScC}=ݮ:55TU(YI:ygexc&3%*! ]#2 Xf\,F484k:_z3U%EyƎ<8.:H`_޽ܜl,M zvTWckdY)&ry33h$4M4B4^S1Z 2 X,< +\ +xn}ზFYUϟ30RQ#M70",8ɾ~n]u4UoH:g%YyhJhh`4R;z +Q*Yd~a+ˢ,Ygx$9Ǐonw֮\lΌiSrsdHKIJ/P_ONgM 5UdYY Ͽ yfg h4@hh`c#j1c2d2 3?B*Bef}Ʒ<;߾eiG77!knpu޲j yaӦN1,%1>&2<$ȿO^nv6&F=thki0:3Ig6> HRPWʘe+2 3b^&4g|*πg'oy;ҹryOe|3 3fϝ:ٹmU͞1m3S  twq2752衧 YS]M?I:u`g%Z"L hZhhd4ʹh. a1eY3;@W/?k}2Cܺj% ͚^\7a쨑Ç&%F١Ng-*GGpVƉ%\fFDSHsc>f)-1]YZxйW/_8{{wmۼ~eKΛUZ?)gLVư!#‚=]lp:w(h#8I3hh.rƾ.2Yx,O珔ο0: - wn\:;|`έ֬\`̒)3SF&L)Fp&|kq~|?c %u~ +un:޺y3'ڿ{ǖV/(/= oQ#R#Pl.3LdhBE}3Zi;Y0nYB[AQySϽU9TiuEPssBTTDP@TTD̘d$#A &rvt۫{;LO3i7vu}S@93=erb|LTxHc/;7ssqv`Ό)&F:Ztnt FSſx,4ܱ~eyaVo Ϙ:WUV{")!idؓ_o{_p6{vm\klѼY&7VDg & 23L2}.4;B&u=+̬߯JיȳRux`޼v;ܶyKRt9|E8äM_ +-$ طĄۿ+rojPJ ߣ:de$'D=sųN=tp]":OC@gAaaJɩ)B}gεt%\A뼜ԗI 1aO|=ݺ~GwؾܙSM&ɡ(΍ 0Aaႉ+J\|KdΥ%EιٙR_u(A睼tỜ0a8NVUfZLҹݛܬ'ޞh:v@thΚ):ӹ Ί83L7c:WV":dLJ{;AC͙t1l~}4ztnGљ33+Pgwg)_U"ιٙR^<ys[D:q:d )uEu\UQ^ZRTM~NVFE޼~΍Kg#2Rg3L ΰϜ2DYsA秈":y-M z:45ztRg>u+2~ gL4<:TWUSt :Ϟd`?^j;oۚs3e0cO h 1NJ$:t.&#sH[.?tpޝf̙1H_W{Ԉ(:wܱ}6tnttfaEiyV8`ɥs#Â|zܹz>+˭֭Zhެi htܭK(:qFunLtfUn3V>Ca0q̥;Ωα΁":8:[6^cyUB ,,b܄P dy8`):?E g\vغi)E z:΃5zHLYi,̸.cr,sDcL}8`?,:t~YltxH/Igsn.GٳcgOGt7v4*y 3Me iN8`I,ι$F?}3'eaq҅sgN5`5b}tnDt[fvqE0fZi qثŸ>zpUsNu<`{ǶW-_<٘5{T:: ,tEn;nhe3cO(^&%!:!:'|1'{wm\(Ϊ\̇f\]&Gq2,t]8`ɤs9E缜L1/=u∣ݾݖ6pܘ#O,̜.ocghNynT q8B,A~^o]t{woـ` Dg}]mν 3ˬ$XsroXh|s!0w|tCMίRcžx8-rϟ;{#?߽s!_za>bfϘ*ssvfZ.<84d3ìrYV>QBknNȳYLhtnm8S:_83 +Ёko޸?g4U:/}h̓YUVal3 +k-2з3u>{湣һ F:*?yӆV,Y8otH籍#kY:id tهh.f#ee׎s%݁6S,p3y:_Ҭ~{vg6[r٢sfB:oj:dPa:hϷٜf}43`VQF}`5WZ!Y: M,&f}Vg;i=O,&f2t|QJØ ?S:Տ.]6tV3(}S4+if23ftXf(sq1i4F%>3ls'g8?,/@:9u(OmGJ֯ylSX:װtɂtNY-&]U4ѬY3U"`lqqhNj{2yt,p3Η/gO6uvحA`|c4j9, e"Pfsz: ,#(raaaQQQ1D7#3Ss'g:-/7_a:? yHM8aİ!egNNsA:86 t la4;J4̱q222 *#eea4(/'H4 + M@31eϘٸsY:^3xPY)sfZJR|l uG=:P6ijN hv:ѬYkYF+ʪ! \TV"Ԅ4#.W|NKYϳa<x7ǹuҹ8+a+<Ѓ3{cFP/?OFjJb|ltTDXht|3nZh6< (#555CatójK4@c?糆g=ڈYLL8|J .ߐǖ/^0Sk\SC!d&'ƹP`h-rÈ{Csl'Af5eK +2&V[;|𺺺4᪶**f<P<-#ؾ nV\3"=$Jgs-UxxV̈g꒩[8.ufqfN۴W/|cٱeeK%IBA0כlin1uY矇yE3D3 lďfgWwO1I1˄eDEJs`feI4"MM Mƀ&><|T򬧫Lx&:SwL]z<;Yٱ6f:D7ߑtΝ>qо]6^\V_]^R+MOI x8YƆKu~Ygz7G9J#Ss <]<DfHadfrQFs + + +ɖ¨OpLgDhh,hh⳿O϶6 ty[?<8cmLK?A: 7]pԱ#ܺqmoWGkS]UYqANf8!62<$Κknblx'c)[DŽf %3s f4{y2C2r`2j\TT\\\RRLepEEh5*KM&@C@} +|VyI<Ϝ%q33;vZ7t~Ϝ۷l\je[sCMŲlIj(&2,$:ZqLFyH<~~{(͋f#B3Ɩfwf?9*:YLL\P(ȥeeJ𱼼.F Xq1 48(O峫gE: 1(-/33;vZ7b:]?|SǏܻkۦu}+K +2R⣅_oW'{[+ : 7Y H>M)E[_u™سcƵkz:Zʊ rĸAtkUdT=i6$4[phh +#h)̙,3qbQFd2 Q4M-HKM!>DG +1}yrgz: ;V)[^_h,؍Q7/=yxW/?}}o0zҢ4qBlTxhRux̳Kwj< ͓)4͟͟ O E7fAX0*&6^͜N]Edu9s,Ch &>cc0Cggْknfbldd<:1.y\̎(6t~wo߸vSǏܻkۦ}+77T,[-IMF@gS:ų*< #DJf%͓)i’4b4 #cD +! !r e2ѱR1|6QDh,|1sgWܔc<$33;v#_t~;3'>g֍k{:Ze%yYI0Й9T9\gy֍{~P:SRiI2C1S0ˈ2ݽ +CF>QWWg'B݁F@&>gJSSH>%Ύ̄y3gB:8c7)t&8Dҙot_x7_t􉣇޾e\iFJR|0,$:[+u^0Pg%M2$Y;z@A׏"%&S22$0+e o5l cۃLw@4%4]]UY^F|͖fR Wٯ(<'ǜdw5 +XYcPEH.UJQzfFzQD,qm ٽ9920\gߗDҙǙ?&t~ 󓞇iki,^%' ⢯_ts>ost:3Y"Z?dhޤy+м hޯDfK+k[{G,3Nf(ffp9 & IIBP$%spRh,44x>etg[7kx^3*733?~ +ml:g@?N秏:;ۚj+J +r33REQWB|<ܜm·t^ at֘L3|e%K_0S>Fj@aلDyGg*`P0,A䔔TXG>ũ))42@\ >8C>XG>Yf,3YR4/ay=yyhfۇ~5"L],H䬬X.g$;;+ 9-AFCGCE Qg?_o<مYsz%/ξLhySpcufᡁ/?{~G{[sCmueyIa^D, rwqgRgg~t&:C:!A֦[7+J +r2"A\`^ΆTst&tgX-e +3#3 ͓1Sмp,[i>v$EE_P,3If 3rR\TT\\RRr|.))..FTyHh +H} !1ʳcGٵS :jS' 33?~nt~;24Gtyޝ-u5U7J r2SEqQWB/z^pv:۳ tܰñá:{ַ3xVQA(̣2hJʔѼ{fSPh ~%"dNH@2bҲxx3!Ai0 G4Z$~ 䉣KyzPc>d󴉪33?~NJ~{{wikn˯\KO&F] ꬏uނc|$)J,_QY)вDȃfifJCREh<{ vjdt jf&3 TF&WTTVVVUUīOp? t!4491!.&923x07=ehpȡ8oKF:|HI\yQ:(B:?homn󲯥b#C|<ݜsuގXp|dysq<:LKYJsN90KLhVRRde| +c1~>6֖gLhK?U,Z,fc8쬦1DMJ* bC&&j-b/(ؑ{U!BS1vf9- {;8|_ 8r8 |94,"2:6.!eY23ed\__ v[><8z$?lL/y,tv( %:sDggez3#Ws['kpfMue9NEgyj% ϝ5sT7IN< ƌJg1h-cZC f.2uf}CcyH4oݮ氈̬ܼ"Y3XF~ZbF밠% 33Rϗ/ >tCڱ}u%ϛ<@cYh:2e-׹9NSC=\\(} yтy=ݧbQ<Hgς hfFe3KfIfH3F3ЬG4[r'"́N +>{%9*&.>199/X.3\f,`qџxNL(44t \^V9#-z⹳'<pyz%Lr:#}2e:Ψ33u׫mϟ>~x4ݮQSU:gK:c׭K>e2ʁlinjld<,3,MBiiT.(Qf)@HݟDHsBRrjzDs~AaqIYyE%eedLӌhM>c?c>JYY^OYUH_^wz\ssjR|LdM_ź}ڔ.lafjld7VgZ ,LJ,fHf<,,OA'9!^r4i>#4gfW^cL2C4̘2Ie0B!MDSCCA?zD>P>ϵ*<$%FGb<x=W =Uu#~$ܿ?O2L;>tt_΂O *:;mްv5to/(;7Wنlbdh>2G\hP6a0!A/$Y4[?iHo$9;'z퍛ͪ2?y0.s_^i9Ҕ 4- p\RT '%ػKo5Ο2|s2e :d:?~QugOD8oٸx;{ty"q&B>S?3.`szYGPYt`dlbjna9nDg@`!* OҜi.4ެgL2dbF]*cgiQh*h ǏsscmzUe9񜚔OtjTyC΀3ܯuVpV6{zުsYqA蜜t>yvĮx^d9Ty/Uՙqf¹ HWt{PTEBKPl "b%1db&ʚo9tb?wgBz344JO2Pfs +͎.n޾~A!L%h#4i9wBŎKhɌ0\f*?)4!Ƃ&>~x +a=w%;Chku:t@gDgY4i_8SI: u~|"ѹtm݄p,_pu\<'DρgWgG{Ѷ6VF\@&B`4nl`d,ʆfWw/o_9,i?y inE/_|S^'LfoCi"4 ,s-'jI<ځGX + : +ꜪTgCO[ut&:YYL|Xڣ5NJPi$S`ʳX;ϖϦ4 ИЄh0(->FY&.3e2[,=|樘89g2vGYi4 Y f2㙦B#D}|>OdGNL_Šd9Ihk 3#}]s_Y]M{%Ir'=-+ y榆z躃8*^z E3I3Rb#9=]]ǒ|~6# @CASuѸaOTYo,ށF_@Pph8Ҝ"yFa74a473/] +4@eǼ9_MF!ϏsLy~N +Aaѱq I)@s9SN/(*U*y3\oh~LK^f f1&6 -3<n܉F\_{uX :/(+-a:$Eξ^.m,L tu}4V3YYYO?N&ǡ{wUoyQ9K +q<$%ϑ$yhRDh$d !,X,AfO/"s`pH)iY㺠yC%y>Bs-hq=fQ42 `V@w~ +H3>|I]NgGGyU˗.^0x!9591>.&:| + Th$Fqc> 2/ +ќ 4(Y2{N,[!2Qi~Ѭ 33]M$41y!>s[<2Ε2LJON g:[269bjkQ +:ΨgHg gi>NL͍ uǸx޺icź+/Y`\๐9;3=sLT$4 + Da>éAD昸Ĥl)S!? 48؜͆*uQ޻bAz>C{U v@K\K\sߧ3Ì`0j澼/>HQ:O6̎dqu~>cՉ⹹0/'+#591.&*"3f&Ɔ೎։ 4jj`44=NUU02ISz̖[{|f94<2:6>19uB4eh)3f!|&3ϣ dxARayVFz:'4TۻkVXd~A!aٹu$͝bi~$JG,OB2KDYL?Y8_( hG/@ب`>POც{vnۼaK/TV3{ +2"Wggv& 38[Q>bu@hhhM 0:N ; (DL 0A3[ql<fo搰Bg1ͽDEc38܃/dvuP:c=\KsC]ޱu5+,^0_ yt9Y)ZNggv&9Βu~錳|5UsFd>>651ѐѠ@c2b\a6538ciщwshEьhNJI4 0ͯLo%,1BS>3x+O22@%XȰ ?ow=ǎ߷{֬\d򼹠 +dH:OQ:8c7ى_:Oq{ Fg֮Zx|%Ίd 2%̎ݤ7q8FTf1,Nf,K$Z"BL +ҹҹ:X618uQ{wm߲qK,TV3{eeh::8c &33'u~ xId7޿wW}: +x..Rp>>{yS<3:ֹ8?'#51.*,݅k9cfyڞ6oXjt.'+-3֙ř?Y<~ȌK{fR9'+# 3s/ 4!4"ALs@j<قʈeef_ Q1 I)T4WV546;qA Di~i~7.Ϳ @K= +Q q(?;#%162,HOwlݴ~e*ͅtRA^NFNiS,}3#^|t<߼~>sJsQA^g簐`h nhgud'.sƽ\0C2GDFfNHJNM\VQU][zh?04=$3AhxE|d[K22EDFđhNgIe9y +U_Q4N +GYUfge&D{{޲v߳cu-Y0wÿ4oݨtu6Z: 8 f`xM̋Gwkk+y<ˤLqzZJRb|\ltTDx( }miP5lm,1EQ1T4gdfIsr +ea +h.7unBY :S:Eyy8޼qS۽}ˆ5+͟mj2y¸# ؿOAg„pr:A78yxNmMUeE9lI8#s\Lt$9H@{Bv-0mRlg ,.{D!q I)T4K1Bs\Um` p_#+!s2?G,`kei~̉#ڶyKΛ5cƎ>t~{~/us'0a_Tֽ;Մg5ųQ#su~:ׂΥ%E쬌Ԥ3'ػMW/_pS'A:ҹ7Ν;vI# 3Lh!1 (4!:8!a"490((.k,&2Pfeh.Ks_h~gLxo uO=w\*Ti 1A.v,.=ym^f҅f͘:黱 y,,L׊Z KF t(0 No=AXYud.e.iF4?oO4{+:7t֔ y285)>:"D`kei~̉#~ӺU/3dG 2^t:wѨ,,L xy~֨33|V|F ht( LGʐq2],9\h&47|F83#%~<=~:WWjJK +Y)qQa>nN6ׯ\:wء}oٰf٢ygLLy~{b:wM翴m: 8 չggE5>+y@ `4" LE-33OffG:'%M/ziͨ4G>2qBt~ +:߿[[]Y^*RH3ӓb"C=\o޸jqɣ1ׯ^dܙ!njҹ?„t $ܺhZ4h0%h_")ˤeR)LEY<_:?k\UQV*dqZR|tD߳cƵ+͟m:mqF %W_~A?O„[6_4<))h0h_"22f6y2ь4744>k4뜙[p'ܻSS)+).fge$Ex޲sa׶͐KΝ5}*΃etp&1<39M Dр4( LL&c,K2237iyLvJsC}cԹRSZRϑf''Dy{8޴4pđ$W-[< hH灘ݍ„̏g]g:y]Thb4 J㲘QRDUF $2 470/;ѹƆu޿[[]QV*dqjR\txitTC[[sZ~nZRźPhŵZEŪED@qe5% dd͚$nw&-s93,7wߘK=ģcG{r뮽+s8cXY}< Z=g:3 rtQa͌&HӚїPʔee3Mf*s,EFs + 3G9@NX_[]YV\xؑCܺqݪe,}s $|#|7y?#3%paYL!yI>w|>7),]ZRL& όfHSrsle2U9?\\RaLdLD[@gʬChZCu&tv47TU=|0{wVƖ kV,]ɇsft j:ؖ9Άx6癄3E3htEyZM2+͜G_&X,S+$ 5%EJYFgnou55T9wWMW/_<fMI^|#`|.}7;x6y&3M4 -&F\j>'PLU,sY1dnljnvH2k9DsiY393\g/hkq5VW8vP[6]iSH:?=6v{~˰׋t/&3LيSg3gsk$BWh4c8zX,`,dv2hq>AY:t>E9ZkKط{GW,Y0o.M^!>#I:UI+lIga^gYg3gm> Y@  h4Qd e2e +3]mfA4;`XɿNnou55Tt޿wg֍V-[G)4./JN:g KƳ%ϒ6hUhF41"͘6]*3E2eќ:45:#t εeyGޝeγgMr:0?\u/mIgaI!y<})>@ :4[ 'T&, C2UE4wk9hufg+ҹIn:T9wWM$ϧTϩ|+I?ٖÒXxVYYZ͉&FSiث e2gY,'9R4;Qgν":>P[]YV\xؑ{oٰv҅|H$=%vM:_tYlƳϪ*"Ђhj4SQhǮ"ff2(͡3#t U<ڱmY$'t~I5b_:g K֢Y!E@3)-j뭊ʪ!u29 +>Uʹ8sy:w"yy:Tt>[7t3DOĒΟOL:g KcY$RBhBXKe2wK]V`YKsP3=>3I..yGط{Gf%t@q33%qayV|-|@B \ivc1~GaYuY|Z9|4;Qgz4NyP:3mėi:?JN9/Or:g KYh!4%͕VZ, u0˜4MuMҹ[]M $X:fŒ4""Mnjy:іtEВhW_\0ʬو9νj:΍5UEssx:[lѧt~M'3%{|̈́Ds-&VYf.`9Ui6M>t|6]:?k{:g kx}- bZ??f SNgv< u5<ޣMל9f>K@BF멖8Uָ,ì"SlDgΝ~եs. ?Ib:g sZ#jt)H.ka6ʜ4I:wt.g|v}:?cs:g wxV|-8>3#ʜbq#dt&T_[]QZ\w4>]:j?LV:g {:>VCg-`N¤sWӹ"g8"3?FUez\Ӏf9yIGHl:g sĬy -W8ͽ.k`˜?[c:1M+:&39daY$;os4IJ: s.;(39g}[l9MIgaNG=cAZmlQ\¥stVb8cfdXf|3OM*i:oJaIOgaΛ&@Lj}_?^3I^t.|i 1̑3CJh #lv8"Okҹީ 1̩33 +#q^+ HgaN%$:U1m:Lt6s>K<Xx3p0/ Q#=Zyi:URap:Yg]:wZm:?mW:g K'MϢI63pư\iѤsc8cXJ*G7yi:ߘtڃיsi: -t[8cWuNtK" NgaXZ/tn2)DZt9BM_" 1 K $׬ЧQܕt?r"t.,'Y NgaX/t.5L8c %뜖ð_"gf3p0,'9g \iϑt~[ d3p0,g]i:g |*r:ϊ2/w:g .('t~DJkMga i:O:_BbM:! 1  !syη{ߵL \ga`X|' 1 -yNtAB8c6(s:gH0κ{b?oφmػkkGE"X]AEEH齗B}%LO|fB1 ӍL -jΈ3ar5y4Mg0)%=3;\T\"aZq,y4c"):yzW/:;mcktM_BM7_ :+&c⼏[H_)ƹ"g ôle6KYX(8g$%2tpwc|,-(:ϛ5d}{کC;-):7fLYDq-Ks*o8'q.(qә3aLL8|^nvfzjrb\tdxhk?Ϟ^=wC62tfSMA燏 yK✞ +E$ :Ka-Ĵ'I y$iɉ1QoC}<_=t̉#Y[Zl4]gL8v!ѕ٠uϿ4jP_ 88Ϙ`銵fvGO|k&IL BL%yF1 ӖIDm38de$F {{_xQ}6;nZfsfN<~atnoFEߛ6iܰ~,TΪy']v7w`Ĕ|lea+aV̶$ErqN  ~Swn^|Cfnfr٢yO0xȀztԡ~K΍6W3U4TܡS7$#ǐ8^dŚ ۬q7 84<2&.1s.ҙ3O0 pI3fgir2Sb"#ކxpw{x™G:Yo߲qϞ1uҸQ#ۨ[ [ܨA}=:-gο8q纝);IwRde يB!,!TȾDY=M朙~14Ιq^<" z$aQ$e=|T^YS?4:1=rt&yށh?I myu`Og[sCmuEYIa^Vzݸ@?oO7g Vf&5T%%Ąu޷\gz: +u&|U ΦΜsr +K p_ Τ[<&4QGM8xfG{^4=,T 51!&2,ekKsS#}M5eyC"B\8X qEmיęf88K*89gt?3Y]SK{w*q߽ x>Bp8t"d&8ןSp8j +e46#l<1:Dp8E费IL8j+Je܋ rH_GSMY^Fꐸ?/v6f]$tgNngeg kGw/߀{)EO7vt MN-,-\ txǿC?q8Z"lڄL4Sly}muyGERbn_dwZ* +GיL\gZy=yKW|ߌ}')-3E[gOΈg3 .$ i s]Mₜq!~ޞ.:X[US:$."un/_;:_p>͋pW|%O؄9ŏV=on#y&pTo}@0 8/-Ώ s31A>W.8ڞ;sꄑEx9ά̌ t:w8cp8)7:qy;'7oЈEO*k[uRg3 pT!yڼ \Er/>&2,5/wZ*g 1a>n231uQ8s +< pV88u札U踻)YyUT6y|rz鼊x FDSzpTл@.!66 qh\RpNy#dw&Ǐik*IKJpXqF:Ӑ:8101p8ST345utqp#;iŏV7< 4"pp + `Fмmy|tx✗H{QU%yC"<\8 85]qYVQECq3 k\MHL}_TZ^ ]18=\G@#Lp85E \~e46OO(*$͹^ +uE88s!e5u O>{_`Hi9tB FSZp8i&`y~%D3y +<:<sW{;|̩FZ*g1a>g&/py7=#3 OPXLBRF^IMSGĩ3l]ݽܸ ;!uͭHѱI,p8 )./-kyjr<lhkin8f|- Li?3 ;Y,-zTG+>Aaf>< o*JcTA@Pޤ "RTW;ޤ* + +`&),gMYp>._p3\DS +JZ&-Ϝ=weoЈ뱉)5Mm=}#cgy @!^oi4zsbenn¢R'eU4uLͭm\<|EFu+*f50:s&fVu3 DFs/H 6)yi^^z0OlqnidUWdNNvLt,FpSTV349muBqas +*kXDa,򼼺>H4kFC!XO ȼ4/NOzqegܽz˟U5t ,m]/y3뜞[XRVU[߄: ML!ph':MhjB=zȼ4LMsFfvWGksCsAnVzjQWC=\>ЧpttfpGeTԵtLͭm.] +O}^v^r=C#yfn}^^A>i^i4Z?zľsH3l3FV sQ^;ɉqC.]p->Ǚ1A!QqI)2*jz&Μu<|'-3'ѹ,(,"&8+ijuvvq~-:6!]Թ~Yeu]}c3?08@s'id4Mh|)DkT @_/"6feܽupRWUV9)qg!Qq )2rʪZfֶή>WB^Ht/*)!w`|":gWVײ.jF ` \r__/i,/-)dlK9PO[SM,p`p>&(,"&. 8+*ihZK~:gf p s Bwi`F:.Vb`FXHsE9VRb܍C`w@W[CMEQ^ԉ3|IXgUu-}#:_Itv/+'Ṫ}njnA;:.F"Y]`֎.4705UeL8O2ug X *HEQ`Ů{7Xƞ>)IffZtr}Ϲ޾NwK SѡH%qvmҢB:S)_$uNM#sLPl4c^?Hy6x~wI˿x7<+~A,x7lo⛗fcѱ>a>Ye-7K9Yje\gqg*5[BVSS<93xkg<㞟7 _%?}o<1~^2XA/_:6o=xo vwhk][d,605jBf [ g9%E B׹d9\յ 6Q % ߽by<'Y ~`.~d>9:ʹk+KG#6i +sYiqaANT*d8矮39t2Rh.V9^_}cSK['y,_\^['Hh( Yx<'aPK ӽЌm^^ᛇ"}=́6&cI|_95[:_\2KMsă5S`xd|1|vzzr|txto<73lj5kng ٠֨UJ,ss: %Fp?04: <>\D>?!! >%=x.vr||6o 4NO>$;B-Fsq5*<#ssns?2 gArJ\¢᪮-m]}$񼸌}^[$>~zŎx<fwxv2d^[Y^d4ǢÃafsSVqf3 +YF`SJ:gu\\ZfV9ܤscSK'y&qϳ4yvY{< f_Pl{,e yldh6w 6zN"sNFReps o8cRXg"7C49?/hz}c#(xx$  E<;=5<qmYqsj8+(,*1uo6ut1FFDZϓS4z DյzB<w#[  N2=]mAfG`qHg6_δwuaY9 :Y.,l /WD/7C:%Zy..1q4&}@JR <D"e_mm L0K2WH4 + rs,vY94si ^(MNKx</Ey jM.q\٬N|{ Yd:k/, rAirUxəb*;v3`f2_9/WGۜ`s|=/uV%|$4]iZxIS.'Pm`\xfA[;m\aSmmRB4QԨRaf=666 { ǣiؼ\,{sgفVh1ZN[M]U~."7fEy'|8t^<'g +-DѪND4 +3."Hs͍΃lY|@F"-J[_]L\/+Ufjzݎ/Yy~< + -F?DD.hPe},4*zmnm08YRM7Qg9Mx~ @B٘vs& ʢ{_w&@sWUcǹ΍xN<hZMO.5 ʲ0r?=lyl8u:zk<-hCژM옹srYehۼ|IQϿ*sZhSHD4h(',lYmV;6?  hZ6$+ s Üe4| 7sـvhEhE8gY\ y<<hڌ6?D_bMSe>ɜhηyq\g6Qj"X3ew/s9\CؼMgy<>+*NR͠ۍ9,g]gOsg9Bfuh.%"s%@se~8W:9\@ntP蚈hՠM*+ sCm8:<|VMh#:"&"K7Wym K_whk J]MF wYO\\gyBKfTl.'{4=gڅFDD3-Wl24q \54uav7d{:<>GѹFk"I2i>+(t6嚈h%0{4Wy|=*5:Wz(1i~?Vi"y5$/|,+7Ah ;,aiu.x.l"[+0,67<|.ކ4Ѽ<4:W>7B6ͮU(6h ЏPh^le>c>wk"iAy\x~DDe3Dыmy(MD/m>̏hFLidh")].: DDN r۩!":iFz""g=W 0F߉ +endstream endobj 269 0 obj <> endobj 255 0 obj <> endobj 257 0 obj <>stream +H v6Agαcǖ% jwU`Uu/k]Y};XQzjWWVS7+o+{:׋˨c:/ kK:Ӌ WGz5=F([]73pbuUNiq^V}X8:/ Tyai0/>.Pׅ󩫼p6uWNN ùE1JÙ=n>2H+y53E6CY-n>4DFS)!5AVc 6@^kCp7V7PN}p 87TRu[-GPߞCoS١S׷쐩U}wm>`:*nMz 0Z_Iz!0X_Iz!0V]_'cEz"0T_7CAz#0RwG#=qz$0RwG9qz%0PW5qz&0N]wg1qz'0Lw-qz(0Jw)qz)0Hc%qz*0F]wC!qz+0D#z,0Bz-0@+!\euD< {W z0!T^T'ģkxX=xM]'/qfu?< ·gԫz5RVsvxR=xVOOYr9u9<<ہgz<:^QWWKhxMxT /U1u1<GԽ0@="x@ #+յ0D=#[ c;{խ0H=$S +Kq{vjw7O_ro9RAs?L~ Vw/=Ǩş߄I|(|&7 κY^ ~azV9ިIa'g~f7ՏKm<R}y!ȆBWj_Im<C8Շ~7bcִx#>%SGb;cy$^6iDTwok/NxV}ڹ<ޫ{3%[Yyx TV< w9­pvuSίRc +N%,:K"T#,"3:Z/>" +R`W_S'ծ,ve`Iu Ok]W}9XTxU U׻j:7/>.x=`qu˩^L}.X_]Zk/_vm$/g +4~Q 㯤\B_G})Pp/2g"3u5W KWRWP.~/>\KW_.~ӫWS˩_}nu>8pE_Y}O> \SU_.~ӪWUYw˪u}NU>*pa{R}Ϩ \Z'T/Wt?~6='?p}K} O>AR3oP?ԧ{?G'Qs7R)G;#~ V?p/ǟ@}{f>WZ?Nz~cp?׷o oLJ;ToT?~n~P==Szz;pSg]տ_w۪RU?F:Xzupg'/ԛí(ԛíԓýX^nNzpsu\=8]݀V WG`znZڀkX`+[`: S%X.:,S |W`zh໺;?1X"Ou g~kF2K5ꕁ_,Q Po ",PO .|u>0]=0Q݄ꁁ&V l(LV d*U T.LU Luf0Q=-H]iG2S/ u3VS7]~Nu4TUWM|^u5SVg=znu6RWw-x~u7QoPvu8POQ tu9qX=pLݎcvUTz7:ճG8 81jau>WqH=p\ݏCр~Qod;PO.~b[W/Nn`{Vn^^UN\T>ZR.XQo Pdz+`:$;S#%١ +.vRuJSY=0Fݒꡀ1lU Rdz&`&35٦^ 6J0uN6GƩ{I=0Nݓ-ꍀlQo Tez"`(#Ey^NK@XuS^ƪJ0XW}꨼PVWz`*z`:+ƫz`+&z`,f\ 0Ee)>/Filter/FlateDecode/Height 883/Intent/Perceptual/Length 73395/Name/X/Subtype/Image/Type/XObject/Width 1141>>stream +HwXJB[Kb*AI$LB,j,FNL1?x.Y9D\9?'u}c1c1c1c1c}j_{+{jqCzc(c*[(cdUB}jYצ\{jޒߥz[zj0Ʀ +I#S +&ה'W9@T%;}8,l,|JS߆1V*RSZBU,N67qJXF O'XU|kf啯O'&Op06*;rrDp4'jĕϤچt09|@O$OOܝƝp'vfXJϜLrgU$N8pclܸq<#}!_hR}`OJ <ޙvScHeG.G'{nZc,mmo+*{,=^h3kvXmK&Us=9*N}(Lph(4[mҗh{<}[!أ#1GSN};w"wc5.*$ǝUG6?0q8fߨ7hj])@GQzDV<ά+06Μr1g880q<8rOo Qfv޽Gkk7F[?#xxc-NC,wfʚ;L&'9rV-]̉ +q։87c::::.>~ ycydDxZ[ZݩKY9Walj2'$gV9:rpVUvXpRoL=Ԩ1=Rif?sy +A#=z l<;x47gVbĮ;T_*{W5sVǁ}ojk/0}乼VGQytw0xBwYwܙ;+06e%̉_Vy]d#@G)p#@# igBG{#6O1'rgtiʽ +ةT*sW#''M m5PG k<}̙y72{0{D*OwV,Ǚ,+Kalj83[̙c.LrȱgU Nf6sΟ?…Icቼ (=^O4xwveN*b0Vʚ9 c!.~XJGU"N[$N7r#6K._tEf}EK >/;鹳BNSSʊ;TTb…JNCU:rpVl {usV`jի׮].HgU ~DcQyxC+p'rWV^Yqvf±S?co٧U0sbբŋ主JF=m1'nDܸ1::6vy1666: +cypo:w 3kSe`'9vcUJ]VzYe#w9{;U%pp7X7WTF3nݾ}Ν;kwm[f*9>#'l@0399鿥_3~E>}trA#+3ԒszTN_oOwWg=2wv|sWz{eN}]CuB%O+̜9jVjYfm38tlW1 ǂ#fL6b y/^Gz0L=+Oxup@wfa,JNaX~Eu{JcOpel/ 9wvufз9OĹ~'=endPW_yax /^~GWO!uj,;XpWu7g{Ns9n sh1a͜ɟN>(IJI#h^>WSS{tJ17 Yݺu6}@C`(y x8N4Ʌ;i)ɜYjlŕv-]̑8'` i,;IbRG>}V?HҊg1se*` JJjOA8p{C:-Ҧܹs{}MwFC(zXAjAh;rdgfpfa좹U*+bJagHcz{Ib:сO띍wie7ǙVjLR3eE3GYBwU6笪HIeoh݀ܿ~~xO}ŀON 9{Ȭx;q;c;X4veVG׺!r؜aNs$x3ZV6nb'FNq)gSJ5q7n ijȖG=~;Ϭ#a{@)nY<4xZqh;'J +~~;RYNvB;AX;'qbywwQgS>}:3qS "}hL3fCeyKAV9`87 6tyӧO. >W$(z!HSsxyiqgl;);Fe Fc 3mX:AaP'PGO}{4gd3&SZfj}q ' ]UN 66X8jܹK7nԈ2Ϟ=%{>=c؃գxҢwʊeŅnjC$ZʍeN| 詣O`oHZv$J+9s̙*zظ{d!'9QI#YPT᤺aoh7y~->|SewɚJά|̝ ;,Wv̱ǩJC7էﭼYgs8<>JfN8)؝OHJNu%GFN8J'8 p=[w[E >l#pm<Zpxqgϝ<̝LWv֯[2k u :6g͜lON)fZaYaStK8z( *sYur1boh܈6xq? =1NKsSYdVM;FeY؉~e츨3n'Gpz]}޾9Ȝq&zKZrZYn\V"r9ɩohjnu굞^8&8 smtvoa{<2yLxЂ;ɝdTm NIQCm[X4vB1v8x:#%ѧUg5睗3탴99/]3' +3eu)vW#PO)oDta=~7(z }ޠA!s&xz9 +^r 4sbw+e_TBT 9-LNWUw}}_# {aj pwb}=,Oss.,;bv2R0v6E!C- 3}ѣ(^3i)Me˝]=}V̉OLIee=HU1$ +FdU[e*CđPm4Oiy{"<֖gϐ̢sVΆuɉq18vV`b9-wՙf8eS3gdY/r\fNuٹy[wS\B!auYyЪBpPpCAZQڃy;t\hmEα#PY;7dac؉ pufXʹ47f0eXzS税+qt-3̙j8bƬ9sYZ{ ^euE%4rAqHT_zCԼ'Gե<̝.]Њst ÇS>;NB\td8$ K3#Ǐ%Sg:M@sO[ΰ3o%Vn~B"&$]>U}eJrZ 9dqnӍ<Ĥp7d0lP^i}pz<<p N'sdΝښߝv*Y۷bcee$Cba,7jXc`N8qם9}hL+y /#ii 3'5=+gվU*rpeB8p(8 5?[!@j#sܡE,`}{±:Xά ҙ::ĉS99cS3g[_ɅUĚx97eU}ĩFUd(šCۓaHr`ISj0U?E_ tĉSRϜes,ќh_`P: +3s%vQýѱZZ 994ǟ^JG3UGn! +GO{p*z<;/%wXfAvv:^LNsS$Wgy9i) 1Qa~^nΎt?vΐjtD_17؜D4UաOJ3k7n}~T#G8tHp7&=CKv Yڹuzg;X:E;oHM +p%SǚNƍEj~}ߧ(J#GݚC3hgL0gUHv]f5ҪS3՗<|&ki(Fi4N Q,5;±sԩc^i}V:VTxJ2u.Y8oLK3cCe_  +#'N:Bsx\Qs4'&߲}LJLs-l`Y^yɡ|+7Zt><&C+E6Ls\Ғ=;mLK\SeVMX_Qt}%@G܏4ջOnNɜќFfJs|ќ(0'5= QXTI6${B{/"&(HTPA) +TVTJ ""Dw5{6/~e{^u7G|iwn9}66>C=fn4Fz(xCy6]XXSuGjvٰ. _?owG{T"љŢÎc\[ 1ǁ˜d`F`NaIi94Pm]}c3J7g(+>r8YECg +kC<<4gwՁoCF>39PW[s`ﮝHOY"&"$ۃWʊ1ysf/::f覈+h$0g +0GԜќM}5G8~JGCʊgjn#*"؁g$V+ϝ>T~xWl@_h(ɣbanJsDā92r5 9n9"s9{s[Ow'!xs!(O'W_ܡvCvAչ}ڕ] )ٶeƌ䄸`WNl̍ tU0:cGM@\} Ё戊KHJhs|9T"s=7pս n;tsh䠮gՔ[pg&7]^;2פ&}hgmnbP#ЙËYt1?q%%#@^QYUCKG̒4'4UAosNu;7x2VO=G7SV?aE8F=`vԹ֍(:ۚOSYVR9g|<\Xh)+./.*Ag) +#Q34-rrE2+nFiEL@ΏUUAww ;?@X:޿s: 3ٹp+tWQaAN6fEy@g6;vx|q5 6GDL|,+uMm=c3 kdȘ$lN>2g?eN/2MlL+!'r50_f!v>}g%Tg|ltd{oW{*J3פZiYb"tEAt9R25 m]#S k[.e994s74s_tMV#c/_^V|KofPg +3]괷48z +ն9׮N\<"$ +ё|CC^v3t +JFƕ4 &ߜݽ._q xo`r#lz0db u$ +-6KK ]PO[CUI# +}Ţn::Lq̑横k[;:{.]NS9Js408V +3󋴙=B;F Wt۩kk@_(HON + t]locaQVXH3E;)JL|,+UuM=Cc3Khؕ)r sj)s.^v]h/PZoUVgzL!@w8C(si\W{+ˊ 3פ89Xhtd$狳cGlqQQ3X-rr ZrUJ ل9hC&|ɕVB{#T"AgwoE\ v}Ukgɶ9צ&X`kiQH!tên&::Aqk`dj  +\bUrںy[ K*x͹r&0Гn$ ACSa`qWq_579w-6[rydH"[+3cMuEy;vpG'9Z:F&V]ܽFƬHHN[>+w붒R`N:ҜAlhγzZ}psr,|uF}uUkkQ5wcFZR|ld2Dg;vMW85u M,mݽ|F%$^e[qinsqy iG<ROD`c:ZO=t`oeiq~nVFzrBlTز>.v&%@g6FgWWzfvnKC£Rdnܴ|wUuMm]=euʜ/_cshits! + uuFGP_]xʲ₼ =@POK]#+-)!&2EǕ"'Wؕs6(UuH]}#97oB7G;tv١C]^9PwWiu6U93&8H +J))"% (:;sy}s׹?>.fFښn*JK ]8s1@>~D>.CGO>'(zUʪ>506utG% #4szHL!zsh !_Ipu}UW]QR`mn(wEc88W{:{W@D\RZFAYEGF6.޾!Q`N5s9C/_ӘC]Y}QrC#quf`}5 Щ(-JK |`c@GKC]EIeqa~a :pph_)U\qu+a1IkJ7o߽ohbac" 8<*1'9S9oQs(o-/!wh!_z:ۚj+ˊt}m,jWWU9u07ݔ`qvrMNƭ;O [;yE&$cT04g909_:w(ԡ:h_3:2X[UVdkaT;Pt-!:pu䣳|t^ YW[:ȥWe+k<|/(42&!9-39xZ(vuhztʋs2Ãݝl-M\$,pܩ:;mAٸa=Dnـ48Hq+ ,.)-v#]cSK[GW~1|ĜچNܜS39QsmCY,,| +Egx '#%!&<ﹻޣwn)+tD :ppt7oڰߛm9. IH]Wy}-}# o߀ Ԝ*̜n,TCjr| ӇS_]P1 Gt~ѣrt:HWroR~bhbnm" 8<:.15#;?Hg·M#ګ<+ζĘg{+S'ܽuCAF +A<%: EZՖmX\qSŕڽ>3srMLI̩-fN, w:Sc#=m 5:(:.Vfwo߸.#%!"s謁QY"vq+%WZ:z> +MHN-(.odݜus1:>"n~nё!2:yYȐO{k6 @đqڹ :pr,w޳m\ݹĕo`hDL|rZ&jNu]cs[f9ti::tft^!t77Ve%Fk?Бя?: RE@Hxt\RjfN~QiEu]CskGW#s𛳬!ԡ+:/{[:e(:q.f(:7Y@U耸ztv޻'"D%?8,*.15#;3o`hsФRSCP[*Jt\1t4Qt!:ppcxt֮_rtvsه/e\ZڂzWXR^U[Nޜ}sW/g'E蘣T9s(D?u.ν\耸+o䴬܂ʚnœɕi3tf:c:uUed/W3t]j vh\d߽gOJ*^G%fUV5uv |33ǒ9K ( +G@9VN9Nstضo] @tVLBǏΖm;88qq>vy^Ҳq *,*61%#;33>9R͡Dw0Gc@# сGs)-3o`hdtl|bj5s#_t޳3E9D4ή{s_XLRZFAYU]CSWh\5uvS3RAt+Gc8:G'(z5y0<,:{G^z=19fv<0=0 +3utJ +r2Âs!ܟΚE8:\9s72uqUnAqya`80gfhtLM,@G G?&vc=4\q_TVYSكK,5-ot晠 с[|N"GGDU9<506sr !UEu]#W9S39 ?}Zi| zkCGvtdU54rA*چ֎^,&@\Qa/YkNctt:G8:Qypt[;{F&28s9r +J9fhڑ{`/4)ҥKGE@* HRDs;&լyf-$df?קs\_|sb+on:@?lt*`t h}#3ttΧesU\UckGwɩ9_xgs`t ͍_# 0/tvR}jQIYemCK{z;15ʹ9yksotb@cLYJ (+@A'*.΍[Mm=}k\nq16Y.(f8!Fbйw:WOxss`t A? +Gp Y +oU44)\MҝOP6+lηGg?QczW˖AG[X`9A ιtKoW5v1ʹnG|́с XA ; ::ITT6wa :Ws5=nߜߨ6F;`mTBA'NuN:OjsūA\tAGh?VCGt1d_ZTB@N#LL!1 :9yy:FgWd@Z ` +4UM=[ٜtv?v6.ArAͲƖo3A?W0:ĕ{Wb 萤dtյLw=xO@HDtBr*εMt95N +t3B?@FC"t֊t+hhw蘵o`hd칔\:5 -ݽt+#txus`t 1+4::ػ¡#!)AgNGlN{G']ȾrvUNς @1Jl-յp蜰st IHƭ +:>Ǡt> :4Lt`t 㖰{W:Ļ"Iȡwkhkm]<|B"/^áSEB< 8v +AGZqyE m}cs,ܼ΄M:_ytxxs`t 㘠 +AUt$$#PR50iq)oԌkťۺŠ342WCgс c]Y+N۸eαvN1R2s oU6ttA+: :0:itC]J,VyEU c=[ڜtv?t!=բ򪺦;w2Cg㻃с Z栃+qtյwu석o`hd̹܂›e-=}ѻDyAgAgA] {W+ji W!5u޹AgAxW7F8BܻRV54Eq[䋗r߸UQK@gtG +F8tw%z IxW*Ff:fm{&llE%Uu=w9#щ(t/җQ9Ttcx]9vS(t8yQ\%?8"&15+x yW(t֙CH}s']qp9Dĥ4u̬=|C#ҳ J*jpt?׿l~N:^onR,t@:=wGޕqW&6~A )eUww NNzN[d:o(: `$owB4⮄ŤdUoܼu?$"61-+nG=wCB>i+:ܼg] HHwelnmSPZY磌optyWʸ+Hfo!BI9yQP34ut IH+*kliFüյufP@:6qWpK)22sv KJ/w;02N2+2t^ܤ\tmvΖt9Ƽ\WV506qp +O-,ohtrz>H'B:o(: `wuI+:w%,&)zCmSK['7oĴjzǦ- ]mH|wW'O/qW"Jj:F.>Qq9%uLw5@qW9Ի+!CӜ|D%eT4 M,l]cR3sʪ#]1CZw6/tȻ!BG@X\J[ͬݽB"cҲ+j6302>Bgvna wE{?t;CܼgqHH+k8xEǧdV64 Bg~C% + 9o(: `wW8t]Bb]Z:yG$fW5vM=y:;G[bՎc;t@: SfOl3txɻSR72w KN.(wpd1g tVVבtsxW `]#tNw%$*)khba[XVua{w$qWEFP@:;Cgp:rI|Wۡ#,.%zۦVvN!IiYw?߾+:+87tHBwu+:gqHH+k[;xE'gV`/267tN9s¥ׅ$eU5 M-mݼ#bS3ʪ[Z;&gյuft@:tvq"t8yϞGw%(".-odfm_RQ荒w`de|Wdz' +9:<|DJ(1qt +NH-,ohtrz>H'B+HX}7fp9BG@X\JNI[ͬܽB"bӲ˫] O=y:;G[z3 +|W̻ +(~sķppx嚐o`XT|rFNAiemm]]/wvE +,"CUa1)YE"tL-mܼ#bS3ʪ[ZۻȻ- 7tWS@:* 2B+:gqHH+i[;{F%gTmw`d| +:+ +9-Q2tNspu!1IYE m=C [GW/脔Ҫ; ۻF'Й_/!ҡyO|VйBG\ZN3+;gwؤ꺦֎ᱩ'3OghKZݾ?@: roPXt|rFNaiemm]#]=_wCIgKOJHXBwSRqmS+;'woԬF:Cc]FK:' eu:.aQq9%5?B3;D ]m_TrHXbg|:~+tFHpDLBjfnQY՝}CD/җQ0 +;wV=WoI"t8q\BGBF~+t]<|C#ҳ+j630<>dmqWkС]t>{;tdGW/脔چm]}]=_wEΫכ sM M}#:>IiYu-=c3hYY[ C eC3t>UT34@SBރq:s Kd蠻`Vt@:ʮp!Cc[C +/=")̓AQI<(EQ!!BDd 4%Aͣ{(I{{kg?;ソory^m&J?~Z :ρttB +c(EWPt)Egq;R蜽y#;-=~o EGT +A MQKtdpQV70 :1&9͜EeaՋ~]EA MCt%@\ΐ' :[wNJIuNy=\t:_x?DXttЄI\f,p5 =ɩGXSZYsѓgMlu]WLAAAșCgCt+(C1})iGS\^u@tY +2G +A MIRd-:Sd0DN.:]=Pt EGt +A MQոq"-=CS +9N>.:Ohne·_cWa\AQds +N^aiEMCLtZ;{^%: 蠡 s( +,E%U :F@tݡ3/.e>0[tttQq5&:0fi341 D'Wt +K*>~+LtsΟ44A`+耸#&!)%-#'k`)d1(k5cec$+<{13֝J :O贴uvBWAСk9'`̙̑`Bk;GoWqufN^aIE=Lt^4vt`q;ډMi#4{F&s&#'odb6";gw/p:w۹eU=y +9:p=ɾ=#}񜂜9 sdN̙gc7 ($7ߺsm]@̡ m elCGdD9Rl横k34;g+#"GnKÎ켂r<Zۻz󖎢C *@0s"$̙f46st [,wt\"|ͺM1̸:όJW /[:9E#DA68)#`-9i`Ib̙1G00/084|u-qx\eͭ 3DCAСG0#<#}H59̙9KQ 0G[W0gEvn^A!anؼqUWZ;1f`!:i%::4PHd |3D 11̱]$hʈѱ;RҎW /:z ⊞#Orpd09y!N9XZ39j:lz/]"bͺM1;v;p(=ԹYzESk;#@\c0"::=CNn5} .L CyV6BDm}#Np͜’jDՇOPtE'A!8$XQ24wHé990g.oаQ6oݞgGO9ڍ܂*v\uaub-#L^`ÍFA Ç;#t"p1g`9Rp1GИw/Uk7DnKHLJIK?~YVbqUW@t0NttDsnܐcf Do;$b^#̑̑.'v9A!+WEߙS.f^T商|Mt6UDDFQAcwc{^^PADl1j,fV;+x|?ϳ}׾M/:NeNv9FK. $c<*V SQuڣOAF0eyX~]{$qu_=~B;f lQam3zzt|,+uZ)S-ZإG3~Ys.Yzݦ;?||\e()N6mqĊGF&NdzTy#1"C7)^" 5'кm.{8t'M5gemܺcCGJ֌¸̱бq$G'762ymD&H@ 1"㚃ӊSM)YJgN+bN~=nԙs/^r-w;H́quFy\ƕN6%GU8764_'G8Q((G,ͱб)9h*Gk@S$X㣶;.6߸cPs\<<)X,S̉F0e ,_n?9)ٸzl\AǕ lpͬRQqø)1|=Tx#w!2;7S_s,\ۧXqfN*ժ3y ,[vLy8TvCʹ +䰚5O5Mhզ}=z9M9s~&_jQőUVeXL9Ԍf*U9F~?̙=Y5'U5'1w,::#s!O*Q*zùi蘘XLb " >`;<2X%S.lQr 8YLe\VJ͉[Q-`Zuڣw9@sV9#+ +a{f+ ljY͡_0rMUJS~C!܀6B *SVژ:j59DB{=(t[BwJHxJCwpgPy{l$ 88ʔ_ 9QjkUz?pQcs-\LgՔ44eA,t$9/8>aQp8NpH pk~WYabg:0 + +nZQ@HLHCHHB @$HH""MjZ+֭.Ŋby={o|LS9tf>ׯ(f9Ub+(yLڝŎ;6bQ 8qq؃'䑵iѝ;#8XXq.e{cM9]o-a91񃓇Oi;aҔi3f͞&9}Ps# 9rƚUxr<%AaA6$&&%%%''Az“!="? +Gˣ߁w3\iNJsk%==;xȹȲkΈ N©%OWV,\԰tnߵoΧ0o2E)mϭٜ /9DUaq7 6Τ 6l82BS\ |`O [ O8wڻF Fkcy*-ozeի7k+5籑w;kwȣcQ!78BDgY kN̬<3`Ne+^s67ќ})s7|6:9ʲRwѻJJ*s+7f 6&==#cԨQG9n32(>G<~xL NN{>8:"Ȟ]]r&9fY'3n|D5fϙ~ɓ077m۱[y=9'h0?~ Љ7_seq}b/4)86iĆԐ̱cf!T_<]f& ?y<Gʣ1Kν^wUx\x6ԜYUsʹZ صyØRâ֜;t"8a/ie՜K9!`":>q4Ӌ'**U8T +MM>5hڴiӑସT4Cy,x£ww^wry8h~Q7ōxh*/$~"!)#RGfgj901V]~㖦m;vٷ૯|bt"5͛9[5G*SrDEbIJ ހbCjf())-9s,OxҒ}cCx8Xxwty;wz1CQ(|FzDzqV1q$gc#s'S]~Vo⶝ylNNN$tZ)sgYr.Jb\qPq8:SVV^^^QQ1tÏ8(//+@О"z(K G{&w#j/h{ǟ+6T5n8|hP"IKeW0iJR]s5,i܆/lݾ󥽯8o9;zO\s}`NDdB͹@Lrr9PrUEqTapCm 3gNuu\yո"A%q.<<OC!>;rkh#(opTőYEqB(9dX@Ψ1cղZ\25gA]}+WsZmnںcמ_9pH9_+sN1t`NND*pYu#Í]}`W=(KOICd8RpiofTRCcjjϟY pSSCO؃z<*<2Bs)<L-%G>k1Hx77 +]qnsbɱ(HN渜 JgW:55δڳoGxw}O?BߜsLt"0͘cM+OqUN)Ms}1tِUA1 xA5tnѢEz'NjjkkC{@Fƒ“56r'qNo &Y&7 !5 fkQQQqq6\s֭=JW<6xjpg֝p睷]wlHh.C} {`R9tӫD,9gΞ3/jŪ5knSY;Ԝoܺ s̱j@wz!xZeΫ9-Zj֐O8=%MJ∃p 6Ҕn߾}n2]i) ?Shq\`9č vq#H=GQ|O(7 &SMFD9 gAFe\Vy6m)fa|xS;^y{<| s1CC'd.8sk2iUofN#9XVmwV;H=L`TIp 8pClH )۵kWyyn=?<.۲2D|`cAL-ϢZ5wg˺hk {>铖FizӈY5pDN'2,\ty64si90ڍ_޾`!>ȝAQxLtОԇ'6r(8"G 笒q>UknRT}gM2Gy {9/A4eNoftZ 9 UqrrRp,)F!4UUUÇ_|wUU8x<9kjtg$qg4݉9"bXа$x,P6䁜[Bq3ǝV!w?^tmȍMT6qsU8@IBYGrKeuL+vZslx<\ɓi WoIQqdVi丟!j.̹r톝ViOV9O9PZ9VʹzI3e5ha 'nL9Y&r 6Zq8Z82r3g|Tw_wNlpCopcFqUQI@9?9\V V֜9̩ɲr8|,^j~OUdA‘9oP7a?||wB{=\ǁwv`hYw,rܙ:%yĤDZO# 8>Gk6ʍxc8c(δXBj&YVc_IcfgN-W9w̩[`Zl덙9V1**fD3UɰA~O8UHTqqn@s?>=/Cz$z\x<:jrgϝY3MMI5>!ށ(=@CP3pm z3Ja$aU8@9'NYVȜ V4gγC'$s~%gZ5i%32G&a7StN6ꘂ# n i9z(4  Ybqg9tg 3/C{?CH=7 6pCoHLUEqG"9e,s/2s߼ߴs 4?9C'yg?V&s#sC愅e5n|ҤSeX)Uq4q 87؈3pyOD|hA|jGSs'7gq'3c!I%C+edzP=gCxr7FDj@p8g4ddf-Y/$~@r| Ly8ʘgNTsyɚkfZi2t؈HYV&&LKr 99:I޳w߁JGsFA(7F._.qpsb36pc*J3wނt*"S>Ci#,+dΝ~EWUa_Ŏu@+ZRy2P&!$SI2\2  0R <*X?}>瞛{徜)w﷽\iu4%rsA͜ǟ5 0tQsf *4lQ8 r?x9viTHp`N7 aдBRΩ^1@ڃ`ʣ౸S(wRѝhZ!xB<@z.`憼 PX\rJ5rZSykQssڎ99ќ_д88`YsfΞ`.5FE99۫Di+VW FhC 01CB !y`偱ƒ4;;НJ;NMc(xXZϢ ̥Hͼ6 &p6ªbq2]Trhz9 :9G.]5GL{i%:>2I2y0GN<=VԜ , eކ؍S5r`W78䆬Y.b.q.dCɝ,tG -Z:C >|i*7̍fgS|*gK(9#r#9?;9-hY]U䘧wbZ9?s%slcӪV&N5g+"֮[9! vF*.94UÁđ7 k#:""|CS +rgt)Cw +WvVf: M OGC>+?)x Y 7 8)iRxR,9bz-7n~)k]Sy`99qo,Л9/ܥk} IS͘5kUᴬ6'gf4r`WilYYQ7RA5uЍs:;vY⢡'hd mkcH&QU\RZ&Y%G<z"& sL51st4e04g~ <[xYHhwb6nNLe_XRZ^YU_c{ā Ao6Dmm#juÝ}MpG'O#!{l>q&FOvܐ78\q**80)ɹ8y\y5wӵ{>~mcߘ8yVWE@ـ5'5U2 :39q⊣1Qs ~=BM-*<!wʾCSGz >ObBO8K(oʪC)L/+9jʹṟt2ҵ{>ym&L< UN@͉ÚM˪ g?8*Ur8Pq8TZ[䍁Cpxѫ;Z8rG#!{h> +OI1Na.9Dt#ǼAr8-s~՜G7aV8VE\jN~a1, LU6Hpn4jy#1GC iS=OvVYYdM ܰ78.MS>\VwŲXsi%:0s=z?hƌh\VaZEmNHNˠJ|vPap~#!WQ:Qt +@ +> Rx 6̍ m*Yq qpVD''FZV51Ƿ8)94'^ :`Էfѧ9%Ʋ:6csEv)C}<u;glw֡9s8836EM;;_xtGƒ`!z~ kʑr;j#Aoi1s'rʩ9ΜeΣ FsM,\|eVY|9;rh%M]lbGGٝ}GʃA{BI5RSSؠ6;ߠ7Tp8m#ɹry8#mkt`Τ)ߞ=wOťeu'A#Tr{R0876<0F£s ܹl*< < CB~JsAmv~EUr|q_Vδ1:~H;+:dN{6ds:hbk΢+Bå98 K*jv7`́eψ:94RȊ#1q?]ux%$ $0*$Ujzczc `c{Q PL{ +de9g̙{%L^83e֜ (99Tإ;3lΘ=O56n޶ciY]Bܾk /̎*7cG9ICwX1:-@umްAc,9O7r9F0'_B*sZ9Fs&O9rVl߹לSϜ;ҕ,F"*{,u!wc -N-<$҃@u S>VqUE5ߐCe99GyTjNP0'$ sz9N@s,ZtM[wڳ?՜3gٲJ9?[F_U8voTظc;wG*u[(>a 7o†#*s8\^eIG4:G92e2-̉sms sL5w%`Z}j>59cYL΋RQe8uT |@s r#!p8|TIY%JW֖U@:Js>Bs7nNМss s9Mќ`g`θh/\koig_!VIUŁ36dx<{/5` `CОHqY% I_4:G5*:`Nɛ͉'s*Zsf̞G|nߵwa6X́u=ZVt9Rqqy! - Z(I>H +5Pn7781ZUB#G/wF(́qY+4'$o9Ieqs=nT4g+~vд:Fʨ9򲲓Z:OVq`S5<;;l ݁'҆q#Iu884iGA9QL9YȜIɥsnm;w;ӊלKXsnQ1ȁe!G*98ƅݑ#1{ d N0m877UUFJ&'`x9d *̉$sJ*JdZf-wٟzVeJM8F!ϻ〇a>6 S7 q|Ed$OWdc;O#-TN!s;Y+0g-wQ1\jHeq=Q5<<&=`\g®ql@FEծrk;Ge*3/:Yec2',HLb%KP9Fm4l40g0g]{03BBw<p +  >-Z0m oQ%V1EPht˸ ,Yrs#cɜZu6ntO6g97g}p͹x +V<q <pG$!|FKa0ohR p(J&'x*[М0(Y$h*Vs4jֲmӜs=~ԙsqZѴz\shYq|~A;<zÜ?nVie,+:R&91mOx.c)<<y8= ҇ Irm7>!&'x +qb%KP9fhӾs^}۸9\t#ee'ǧ85eĝ7NwpyaGIO67XQAMN`*-$S8<*:.>SvOhݾS}>jĩ3_d3g.aٟМlӊcYyoTyr !{ gmzoxÑ*BM·FǣW`NP>#c˔Tzz 4oݮSמ} f1g-7ȱ9V@Ks|;%= K#UJx*(8{7',HlIɥˁ96lܼU]{0hȱ̘=sӜ̜`h{ +Yslʅ~Yq<D*ԬSQӖm:t޻gCG0yyh*4gNN>{̹u}0)æ渓/8 $#$)#Yõ1Qcǥhr'I +OHJ.SRJ?mڢMz8dĘ͚pR7sܽVΚqrg N+iJ;NxXF~kùWMN"΢W`NQ1qK.WJZu4n֪]Ǯ= <|ԸISg]\f=3Os5Gq<\q, 3Vm878 +q49.qUU\|BRe+TNYAf-vңOAF8uƜ\57mh7͜Ls5o͟;vx2?<Ƽ#,Ŝל.%f̠}SB!(B(EZ)J}#"R Ki1z_gL{{{~~Haf7R@04tfp+qIiY9$6*iYXu+!"%$p[9@9siE9|M񌘇( +h,\7lp8P9 %7޼fG8}_@`HXdL\|Rj99D 3|p)~8ZpA=p +W.@?P:B\aҡ+ m=#-۶{<_OLESQYUCA4XC.^ qvrzVGOjGq5Bq^rxH桺oq,P:LC <ÆWR7ڼ~#N>skQo&$e{99C.ޡ:B}7\# ϤJaxռ E3WH\kon{G<p98,2&.!)-u ;VyyStCglr\IH/ƕWN>s|@`ȵ7o'gWTV7:Qwg _~J(<WZ*.%|J$XqeաOy"q_TzѓƖ9qx{x}/_z$W ECG\RZV^WN#qt5":6>)5Np΃GO::x9Ι`׋x(Q/;%atf #v +er+иRfǕ=;.^ q+1%#;[s~A󶻧꜉VTF _r < + QtDq%&!-+& m} v:8:9U+ +KT56=z +sN?9΁>P: AW#%+e5-]CSmG¥ v\7z8/s}  +P: A Й+c|ª`jYX3_-Yq5aЁ΁Lt:y  d(᧍ZzF[,mv:8:9qr 4 +8U/WCCs΁tWZ~`踹{\t5"&.!9=+[\P :2!s<:1IiY9w?Cg\A@& +P:yD, 9Y R2ѡQYMKt%2t]Ozx\q+1%N~QiyEeUmCskG'18CBx3A + Y9UkQ76ݽc'N{\t5"&.!9=+W-H\| ;> +q'ȄJgu@D+tP\Oյб)ϳ~ѱS3s˰jq3 (q~<2t6(jcC爋ٯ(-1v @&ޱ+ b]A@PzzGl J`z7wlw{faeLo8u.]u/0$,2VKbxjsQs%98:u8:&Ng%104fcc:{m:{ +1I:"\t>s;nShji';n$K+;+lزusPHXT0%=;@Z\@+pZ[to =H)lg踭9|՛wF$$e,(*.t=W?0ooM1tXX9M5BgރGݽΜ|@Ixt\bjF6\窱I:slt~Aa߅e ++)t4:Y 79bi.3,Xm>~Y؄,NaQqYeW2B :t0Й +q5oѲUk7nܸI9 tJ+D5 +lo\a< GÔBG[u[Cg&GNt.]u/0$,*VUےj:\a<GZC+N/ ,ts@g Z;ΞOk!+:1Ii9/ K+j$乢a75j:: >̹ :}@?'LȦ)UsU/a4tac`h 1;t/w[i@݇1 \:eZjj\+_pwCgX3IVv tVٰssAO£:^~#B3@+p ::lg@g>g/^ЉMHN͇窸J,Nsk`< G@3:}Z(ttƍЙ5Bgރ3[CS!/NtGNcj>q +9 l 9y@_`@GSR^Y-%/Zpt8[tSk;'΢enJ йqO#R3s,(*.0|05G@gX3IVve9xs:9:b#ݜ?nƧptTOi63ٽs :jq-\b)Nft4d1O3k;ttWQoMttL(t:Z@@ :1Ii9/ : t:LmQ5ϕ:r1:0YMs@%)t(t^航%R|nj"V,U.,tzʠ3Bd4@gTk{';N2x)R0@+B}8::=#ԒA3n<άy t ܸI:/ K+ӌ+j mg0xSS(t,Yz':n g)_з:C:&:vNEVHs̅+,tb2s t: t'BSpt:J +MN9Ytl\d9ps:q” 7t$: >75B7Spt:taS:F&:Z;@g!/)tr)t*LpJ:V.3R: й}?IxT\"@ NB&:])tzihfC+ +S :/lڶ йya@phdLBrZ@P +&lBSpt:Z4DWo K +KWٰss:Nt|bjFNFRG+:"t0 Guj:\ j104fccLSUmql= "X (]vwcww"vwa' b &H(* +zk?s[9pw#|ָ@ :V:;܈OLI}87yt@7FN}NN.]\ݼ|{YoSB'IyǡC2%C1߻μEΦ :'\йˠ)CmOhtʗ`SGcn!CБC@s:AOt-<*й(ˌ\tJ:)WS4tmZڷnܹO6 Y{(s%,2fmEСTN:t@ 9v :+o- 0|TBARS4:IǹBi  Cgr@gNt'O_HT:9)Oѩ"SSNC[;N~@gR@g N::ٹyJ#ЩgsըӊC7 CNx5,2й Je蔣SCYm\q8:w7h3u\@gF@/_OHtҵH)t9J}蘞~ht7n!ʡ3dĘ :+:qGJá6P:W :_ :J1Jzska)cck//AgԸ@ :V:;܈OLI}87yt@7htL0ts4tڴwrS@'x:ɀN;J蘚 @::B$wZxTsQڳY +t(FcbS4tmZڷnܹO6 Y{(s%,2fmEСT j: qqt;qkЉKt +t>*C/q1t(xYٺS$@t9t>}).mhtLK9:Utjiȡckۯ,\ +la B'C';7CUhtL tY\5jbq 3Cg|@gf@бSg/^ t=t2tB;ARe4:&7tr23-#+GN: tΜ 8r" )N: :ŀ6C5SNV-t\9t3at@g@g>[Iw8trJA+ARu4:&TItp4u-,tllt<%(Ag*@g1)?&=NѡT N}NN.]\ݼ|{YoSB'IyǡC>㓡S_@g"@gSg.ey J6A'ARa4:Ƨ:5ј[бt:t;AgƜN.] t?J{2#+Wht4tMK;w<|If::{tEL-c::ʢ1SMt::^~Бc'NrmP:q :NG%t~t(Fcl:Ε:Nt\O::[w*Χ/%ߴС͡)GNM: 9tl:]{K- :Zrdt +N=KFMV:n}p̞l :vūaνNN|'P*FNUZfftsš܉CߠaԙsuGN|=":>!IB#At(uGc\iʺ+ΐc&LXǡ{+NVB\1|%P :8W:6:tF lc΍Ĕӟ~WAHt~P*FǨ C>Ns@M{'.n^=e,t) LС*H4:$C1߻μEΦ :'\йˠ)CmOhtItjѩ1ctȡw Ό9 @g]eFV:%bDcDS4tmZڷnܹO6 Y{(s%,2fmEСT j: qqt;qkЉKt +t>*C;q1t(xYٺS$@t9t>}).mhtN9:Utjiȡckۯ,\ +la B'C';7CUht tY\5jbq 3Cg|@gf@бSg/^ t=t2tB;AR}4:e7tr23-#+GN: tΜ 8r" )N: :ŀ6CUhtJ?t4:ZYq2b̄k]8t£bo%y_(+DSF@JSR@^@_ΨqttvйqWo +3oJ蔑aii˷ %N6%t4w: :TFp2t*> [l +s :B :8t0$P*Fp:SN ;@CGtfY:?}ҵ8@g/3r)!P)Nбiiߺsn:?i,@gWkX t݈݁݅؂ J襀^r93g<:W#co3 +_/FhաS[:o@gD^s/Nt\b2N6S$BD J K\I1t,qrt|e,] l߭N*+: :e_+IС͡c¡SONS[;k/Y*B'\N:Nn~Al4:F2 +8WZX:tܽfЙ l +t8qZdL1 +J#*tj175m#+Gn :tfYl :v*•qIiNlr@CС CGǡӼu7M6 YsA'*6v=¹Ci,0+]#s [{O:c&Lb kGO3_}WPQNѡht f:MtZ::;ps#CgC ;NJJN?NoO߀~8t.tlsE"t:t>1舛#B'AD4:RN]qte:]2 "BgENsɳ/_Mt>x:+'_ +ht :бik߾s :F8u\@gF@gȘ[)w9tBA1PuVN+@ǁA4~t:ׇˡ̡ )QBAN4:꩜+ :f:N.o +It=%@AKy7 :9vQO9:&:d4eбs[ "t%3t(GQ4j +iǠ0μ`@gS(sęK"c,U|'PFGЩŠSԴpt1 :Й1ga3sة WnD%%:t9tlAZ4:jCyK+6:n :G4mjNTl{ :9y s%B+Ad4:*0+]#s [{O:c&Lb kGO3_}WPQNѡhtT2& :\z{ ۡ@'CghtSO7 K->wCNO :IС4~*Щ+NC ;@KWCD̞ t=yQ'/^g+SAС^Щk;9:wɠ3l؉Sgtnt>\rC'(t~t(DWuVN+@ǁA4~t:ׇˡ̡ )QBAZ4:S9WtKt\/@:KW:w+ +<{JN!Niٗoths(ES=pԓӔAΡ#ǿo%t/t Π_@Сit2 +8WZX:tܽfЙ l +t8qZdL1 +JT*tj175m#+Gn :tfYl :v*•qIiNlr@CСN CGǡӼu7M6 YsA'*6v=¹Ci8*0+]#s [{O:c&Lb kGO3_}WPQNѡ4NC Nk@Cg'n~}d,tv(sCi<e2tj tz{ġp e.r)AG:? :Q4ԙбtte0D@ѓg_<|uVN:J(҇N}X۴oѹ{OaN:s.v#q@jdL:yFCi*EաS[:o@gD^s/Nt\b2N6S$BD Jȩ+ :f:N.o +It=%@AKy7 :96ёS N=:Mtl::<|VBgr@gp : :F2ilsլӎA/`yΦP@ȉ3E$::YNС4NeUSAi\18:wc8t$3c@gf@бS܈KJNt2%`s:ht CGǡӼu7M6 YsA'*6v=¹Ci>^ 52б 3f:+:q܌OJIK4wEEoJSC Nk@Cg'n~}d,tv(sCQHЩ'o%ΖmtNȡs_[@X'qsD$PF4ԙбtte0D@ѓg_<|uVN:C>tmڷܽ'ΰQc'N9Y8s52&V]G:U cg̩Ek9t>zΊ5ή}1Rn +䙅%m4:At::^#NTlUh:q:ـN{-tt(J1rбtjYټ]T@g +t +9t>|*-mE訣SE@ +z:έN]Cg"@g#N::2c:mp7tsxá3cvS.E$:w:YFCQht*@--k(Cŭ=N~If::{8sJt\Rr6GN)!PO1 NFvMt<8t 1f@gJ@'|7NTl[:9y sŠCQJ&sem#c$@gبq +t/tй~aٹ +2蔘OJhtLBN@eW!*t:a[йdHСߒytTTt[@g|@g&:Nй͠)VCmwETN56:5uV*t8tzeЙ:s. +9pb2<@CQxt S:v͜ZvqЙCOXwй-妀NY P'б0ƀ3o 3pȱ,[uNt\bN6SĠ^ o;:FΕ:VN] t\`: :k +:3:k7:?uRdLs>e:_ :UXͱ!+: t&M^=x4̅+qIiN::6CQd 4hdkT@ǃCgc&LttwsD&\OšX9W : :eStptmtt 5Nζ:WR=|";UA[ICIԣc +:u8t:-۸w Q ۢ @'C@ GEMQSo?{o;yV@6K@X;9 : :%yt*@:+k:Nv:=2L9 t8rQOgkSFС(cI9:Щj;fN-Zu̡'OtVtv;\rS@',t~t(ԣBt::^#NTlUh:q:ـN{-tt(Jc\c@V` y:Σr|(TZE&TЩBs+@S/nЙȠN:Nn~Ac:mp7tsxá3cvS.E$:w:YFCQ%ͱ`cYC@G9W:.n9tzL6 Y{hę W㒒L=t9 +tJlA otLCG'Ӡ]SCF0Y ͡p=NNb\1|&PJ&sem#c$@gبq +t/tй~aٹ +2蔘O%蘂N&N6=<}BT,t¶hsyáCQfmtTTt[@g|@g&:Nй͠)VCmwEUHѩjltjꬬU8:mqˠ3u\@'sȉ/G&:wd=p̘?|ԹK1 ΝNQ|%PѤ9ls,k(Cŭ=N~If::{8sJt\Rr6GN)!Pd 4hdkT@ǃCgc&LttwsD&\OšX9W : :e6F \jY;8 x)6jm;t'{Ev :%&FʓntLAN@eW!*t:a[йdHС?&Щq8p$`$)Yh/{ޛ==gM%Y4Qq8|nE}u<^@_`Ͼ:s:H9~꜀WN:lst~t(@Z?SN- @]{tϞ:aSk@sWO߀` A'\4|EU ՏIԱƹjiԫάyM΁#'N}d7E3M 95j +HCٵNC)3:k7: ?{jTlbR*6GN !P9}tCG'Ӱm3wAF4 YٵC'2&Fm7EҹbBС(ST2+]m+k;{G/@ :#Lt%cεԴ2y_At~P41:ƠSC)Ӫ['w2t:!۔й DСrёSt W@gB@g :Oйà +)CmE#-ЩFJӮ=N :gtGOp%2&й0<tJ :UT=:eS,tl;lڱ #N:Y йw=NI$P40:2t, @ ġ >zd :+l-$2|PB;AIͣc\c S@ hu:)'%p|,\RU2'N2ts;8t:w : :tI'PTS蘄Nkl:Aq̚8rNA|#PidtXͩQS@G:W:ή8t L1YwXًWbR =t9tJlAOc::ml s 6jܤiՀή:17Rnsd)(E3ՎN%#նбw 3b :KW:;\KLNM(ˬt@EHc :u9t:ںur.Cg1M N[O@j:́N7/}t.t6ns9; :" :9t0 PY{tN56:tV2tv9tzgЙ>{> 9n{gGu1my9Nλ-ϣӅNw :tLͭt]ܽ„YB'Abz$\¹bбdq h@'2sT|I:B3BǣC7GC9-8Wtl8xx7i9 tn;p͔BN:9:-)FG6tt741̠3fBxĬy:3$ɿàSUSHG)F\r16h3tn;AVzV^aGe^VT? +fa?GGttt x|5@g瞶)rA=BÔO#Ngб&qrAgJΎ:g_SBS i$yˠC7B+B~::dshjcA/0tX:[:GN>wʍۙ{K(mV)FG:]B@[N>Gwʍ +{K{MiE`R\ A c Йtҳ +Kt^VVbyˠ4t`©H@Mm=!t:vtBG2,^ЉIs̜NSN::wtU:6C(tЙp)@gαg_FS$Nc;Ia*HGG  бbq茝8e [:\Bsa:MV!t t0LEtpcбuxL6@g&N!ltj^5S[Hl)/F b&1025qtq Agή"e#t0I]GG.ttt\>@ǒA7 de:1::E%?y^.; `ѠK:\1a 5@gqg.^drЩAaCj::#ӧ g1#f[ 9|T|:w95407a*L=G hir16O3i9:2ܼEsQٳ:\ijЁi8:\<:'> x 5F% *`EU {+ + {6Ћ+X4dU4ϳ޿2aay1$ttem.@g@h:1qI :Ez:&Z:Ź8;'Wt6m +Б'gQW|dС0&itt:ttt gЙ8Bg͆-ū7nt2/*Ηu %)Nck &-GЙCG\ yMST򾢊+ +ŹB`ƓQ8W.z:F&:v:s.] ٵsNTlBJzoWsO5 :G44GGt1 ja5]}GàáS͠ab&茳sr̡i@?@'8@Gɢ)T|dСC aM:t +1 Π3q*Κ [:~:޸0"&>)-#yR%!t0LĤ5:Ӯ1t  239AgEVxtNz~x<11NI0%:}: :.s,YAg?@Y䴌':J +O08W +t+A +c&@gnΑ +DS:/_%Щ`\:9&B:`126=e|=t>FN&Nqi9BZ*)Ngo}@{g Sto\rqg|0qѦӱ9W :#t&MYv#@AιKBn{U@6@0ђ訇CW}: :3f_|5@k@' NDL\RjNQ*r(t!t0Lܤ3:m@Ε +܅K tv?š%OHI|"ͻ:5jG4FGt1 ja5]NQetr8tt t0L$3:tqvN9t6m*ESЩ"ȠC7BBHb:t +1 Π3q*Κ [:~޸0"&@yR%!t0L2:Ӯ1t  239AgEVxtNz~x<11NI0M':}: :.s,YAg_:iOt +::a%QqtW@M#'Љ't^zKSkmwtps0L$8:m9t:cdl:3zzl 9LN&Nqi9BZ6iNgo}@{g Sto\rqg|01Ѧӱ9W :#t&MYv#@AιKBn{U@6@0訇CW}: :3f_|5@k@' NDL\RjNQ*r(t!t0%Q8W.z:F&:v:s.%ٵsN2͡04N{::e:t:Æ3LJf@ū7n= +@?84195=^Wyp]@:NI'92NAO :i{\t!:XtVES-tu:FS3sytl t?}ҕ|CG>LJIˠ!UQBtՑk)+-x$7;3-%D'F窳ޱFgi +ijmN]: ~iĠR:&c't,Xuɳ:7C:q ɒ\v]yGTu?ȚCFQvN ΍Oѱ^j)x}tӰA}p]Q4#iնf.:QϠl@g?9\sĠ+ND\p~8*cNjrB܃Р78ӔBu; N} 茒Bgz^G7BE>{$aճywFC#\W,:Y,:\:}v[׮Z`4SqҸ  :uL1k.@gFCNx;wẊgD9&:,;p~79:u.DCt<_tу{l׮?::$:r]Iөk}j0| Y̞xu~<\Wu .!I¢L:4;;rp7is:HMD fѹp=m6ZX28A\tE?EGNڴE3`L9g w] OH/(*!ՁH×É=ޒy4W:J$'=  tsupđ{vm`b|KsI,:z[,:Jѩj܄B+͎]uz;puvu~?:6>1Y_5\2sJHd.![, QȾH$D!/!ʞ/!}KuTӜ:?0|>_2s}/?ܯ0:oCG4?qNl"F^:-=OաACك󞄄d%B7y+f32<8׃NuE pթu4ՔRRp:?|:K xWAV9uĩӶ:~"XUV5uv326> ̢ry=TޑDơ-⠙3;=5y G]ݍtg]mOct4T۽SR پ *:-Gg5C#,*!%gAêZFm]=|./C O br׈7$$$ln|PW8xL>s񹢇N΃{Qa!W|<\l,Oi +IHtTյu[Q\[D'++4u:`ACCBB̓ +SL9c#χ9-Mxek=ݝ-̌j(ݻKZBLXȵcףf-w6>~A1I]{)(ih36t<.)oDSVgxdgуa򒄄a5o33M3ghpT_[U}:𮂯_pQ#ʊr:ζ-<COE{ΪUZɠ#(iY:gt䴌9ehB  w`Lay=8s$$$+ܼ r=4VW=EC'!&=\mO:q\_GSMYAn)qQ!>GCg9:6:B";w=!:~Q1ɩd=**)khn܁A }3CBB, j8110?̩(+.FC' ?\l,Oh*Spbt֮ t] lݾC@HT\j}C:B"g¿BS6;O;w<`8$ +U9T1A "rz:Z9`NAÌx:A]9[[VW=,/oNI1A~7Q s؊%A!aw%S c<yeedª* p3 `q90skpScaܼq~WFG(ݻKZRLXpv@g#7'ΪUltVp:<:€rt]=<}^y;"*6+4uJ˱:M-]؝$Ѓ0yNBB +=p8=9`N2'Ȱw'X&yxx5h$z nFG8+47ZUU[9I10+WgG6tޕ8t Thg+qFD&$2uJ*d4v[1yGF( $fW@j#Z9<<o>NJSS]Y^R,  s`km!WGG[W9_؋S/dR'OR$--Sجhe@#f"900nț.lE#*/Ir29Q!A7عrΙ{WB/*t~PCtt T3PHxd̞:X`^Ԭh!x;===ЧO-c"Jj7X8EPSUQVR\XHz{_ù:8t4>}_ S:VP(S+3;Kؑax ttR稢^=VGԲM o&VV])o@zW_sr_j;9ca%eaWTZiV(ZOMr/m<<<ǓR#̖FNy)korA8W1a]@a_TSNl|b2NT2x O\|f1 +PD*% 78$+̉ 9n.Wm\cĆΞ۟:8X^L6v;pDZ&>uuEsamD/Κypʰq +%y9 'fNLTDXp?`53G:Cߕ_ |ĩ5}uh0vsD TTTBRO QF~hf%7FJcde2rpBn#@範7uT˙IMˀ;9Rsl!DENNvFNj2 +ǵ + s]̡su48t6t>NԡuCcG`'!1 @ )/uEa @QPDD!8EԨh%y^ ;@wm߶VGc9b2Я_烈+\9{B<>X ̑U}\ttNͯ6Z\_CsESGX^ =vV³zp@cg#7=Xm8 { gngc#ǵ+E*Qp88 23O9Cǡ:UegT1x #>G[f+MT*Wo#N5'1Cͩ)>u%QwpG+Wvh3=o 8'&'ǜߊ̩ԩX'ǎv; +{GJa`fv(8r@O;s9gcsCǣ=Ω@Qve93'T㎁IJc\eF|2N NU'dǺc$$e>1Vu{ĉi9:)v;)x{+S9>c#1ΎsSc= ;Ǔ3X;v,4:;> endobj 272 0 obj <> endobj 273 0 obj [0.0 0.0 0.0] endobj 274 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +273.8400109 0 0 211.9200084 146.2255859 -47.2530162 cm +/Im0 Do +Q + +endstream endobj 275 0 obj <> endobj 276 0 obj <>/Filter/FlateDecode/Height 883/Intent/Perceptual/Length 73395/Name/X/Subtype/Image/Type/XObject/Width 1141>>stream +HwXJB[Kb*AI$LB,j,FNL1?x.Y9D\9?'u}c1c1c1c1c}j_{+{jqCzc(c*[(cdUB}jYצ\{jޒߥz[zj0Ʀ +I#S +&ה'W9@T%;}8,l,|JS߆1V*RSZBU,N67qJXF O'XU|kf啯O'&Op06*;rrDp4'jĕϤچt09|@O$OOܝƝp'vfXJϜLrgU$N8pclܸq<#}!_hR}`OJ <ޙvScHeG.G'{nZc,mmo+*{,=^h3kvXmK&Us=9*N}(Lph(4[mҗh{<}[!أ#1GSN};w"wc5.*$ǝUG6?0q8fߨ7hj])@GQzDV<ά+06Μr1g880q<8rOo Qfv޽Gkk7F[?#xxc-NC,wfʚ;L&'9rV-]̉ +q։87c::::.>~ ycydDxZ[ZݩKY9Walj2'$gV9:rpVUvXpRoL=Ԩ1=Rif?sy +A#=z l<;x47gVbĮ;T_*{W5sVǁ}ojk/0}乼VGQytw0xBwYwܙ;+06e%̉_Vy]d#@G)p#@# igBG{#6O1'rgtiʽ +ةT*sW#''M m5PG k<}̙y72{0{D*OwV,Ǚ,+Kalj83[̙c.LrȱgU Nf6sΟ?…Icቼ (=^O4xwveN*b0Vʚ9 c!.~XJGU"N[$N7r#6K._tEf}EK >/;鹳BNSSʊ;TTb…JNCU:rpVl {usV`jի׮].HgU ~DcQyxC+p'rWV^Yqvf±S?co٧U0sbբŋ主JF=m1'nDܸ1::6vy1666: +cypo:w 3kSe`'9vcUJ]VzYe#w9{;U%pp7X7WTF3nݾ}Ν;kwm[f*9>#'l@0399鿥_3~E>}trA#+3ԒszTN_oOwWg=2wv|sWz{eN}]CuB%O+̜9jVjYfm38tlW1 ǂ#fL6b y/^Gz0L=+Oxup@wfa,JNaX~Eu{JcOpel/ 9wvufз9OĹ~'=endPW_yax /^~GWO!uj,;XpWu7g{Ns9n sh1a͜ɟN>(IJI#h^>WSS{tJ17 Yݺu6}@C`(y x8N4Ʌ;i)ɜYjlŕv-]̑8'` i,;IbRG>}V?HҊg1se*` JJjOA8p{C:-Ҧܹs{}MwFC(zXAjAh;rdgfpfa좹U*+bJagHcz{Ib:сO띍wie7ǙVjLR3eE3GYBwU6笪HIeoh݀ܿ~~xO}ŀON 9{Ȭx;q;c;X4veVG׺!r؜aNs$x3ZV6nb'FNq)gSJ5q7n ijȖG=~;Ϭ#a{@)nY<4xZqh;'J +~~;RYNvB;AX;'qbywwQgS>}:3qS "}hL3fCeyKAV9`87 6tyӧO. >W$(z!HSsxyiqgl;);Fe Fc 3mX:AaP'PGO}{4gd3&SZfj}q ' ]UN 66X8jܹK7nԈ2Ϟ=%{>=c؃գxҢwʊeŅnjC$ZʍeN| 詣O`oHZv$J+9s̙*zظ{d!'9QI#YPT᤺aoh7y~->|SewɚJά|̝ ;,Wv̱ǩJC7էﭼYgs8<>JfN8)؝OHJNu%GFN8J'8 p=[w[E >l#pm<Zpxqgϝ<̝LWv֯[2k u :6g͜lON)fZaYaStK8z( *sYur1boh܈6xq? =1NKsSYdVM;FeY؉~e츨3n'Gpz]}޾9Ȝq&zKZrZYn\V"r9ɩohjnu굞^8&8 smtvoa{<2yLxЂ;ɝdTm NIQCm[X4vB1v8x:#%ѧUg5睗3탴99/]3' +3eu)vW#PO)oDta=~7(z }ޠA!s&xz9 +^r 4sbw+e_TBT 9-LNWUw}}_# {aj pwb}=,Oss.,;bv2R0v6E!C- 3}ѣ(^3i)Me˝]=}V̉OLIee=HU1$ +FdU[e*CđPm4Oiy{"<֖gϐ̢sVΆuɉq18vV`b9-wՙf8eS3gdY/r\fNuٹy[wS\B!auYyЪBpPpCAZQڃy;t\hmEα#PY;7dac؉ pufXʹ47f0eXzS税+qt-3̙j8bƬ9sYZ{ ^euE%4rAqHT_zCԼ'Gե<̝.]Њst ÇS>;NB\td8$ K3#Ǐ%Sg:M@sO[ΰ3o%Vn~B"&$]>U}eJrZ 9dqnӍ<Ĥp7d0lP^i}pz<<p N'sdΝښߝv*Y۷bcee$Cba,7jXc`N8qם9}hL+y /#ii 3'5=+gվU*rpeB8p(8 5?[!@j#sܡE,`}{±:Xά ҙ::ĉS99cS3g[_ɅUĚx97eU}ĩFUd(šCۓaHr`ISj0U?E_ tĉSRϜes,ќh_`P: +3s%vQýѱZZ 994ǟ^JG3UGn! +GO{p*z<;/%wXfAvv:^LNsS$Wgy9i) 1Qa~^nΎt?vΐjtD_17؜D4UաOJ3k7n}~T#G8tHp7&=CKv Yڹuzg;X:E;oHM +p%SǚNƍEj~}ߧ(J#GݚC3hgL0gUHv]f5ҪS3՗<|&ki(Fi4N Q,5;±sԩc^i}V:VTxJ2u.Y8oLK3cCe_  +#'N:Bsx\Qs4'&߲}LJLs-l`Y^yɡ|+7Zt><&C+E6Ls\Ғ=;mLK\SeVMX_Qt}%@G܏4ջOnNɜќFfJs|ќ(0'5= QXTI6${B{/"&(HTPA) +TVTJ ""Dw5{6/~e{^u7G|iwn9}66>C=fn4Fz(xCy6]XXSuGjvٰ. _?owG{T"љŢÎc\[ 1ǁ˜d`F`NaIi94Pm]}c3J7g(+>r8YECg +kC<<4gwՁoCF>39PW[s`ﮝHOY"&"$ۃWʊ1ysf/::f覈+h$0g +0GԜќM}5G8~JGCʊgjn#*"؁g$V+ϝ>T~xWl@_h(ɣbanJsDā92r5 9n9"s9{s[Ow'!xs!(O'W_ܡvCvAչ}ڕ] )ٶeƌ䄸`WNl̍ tU0:cGM@\} Ё戊KHJhs|9T"s=7pս n;tsh䠮gՔ[pg&7]^;2פ&}hgmnbP#ЙËYt1?q%%#@^QYUCKG̒4'4UAosNu;7x2VO=G7SV?aE8F=`vԹ֍(:ۚOSYVR9g|<\Xh)+./.*Ag) +#Q34-rrE2+nFiEL@ΏUUAww ;?@X:޿s: 3ٹp+tWQaAN6fEy@g6;vx|q5 6GDL|,+uMm=c3 kdȘ$lN>2g?eN/2MlL+!'r50_f!v>}g%Tg|ltd{oW{*J3פZiYb"tEAt9R25 m]#S k[.e994s74s_tMV#c/_^V|KofPg +3]괷48z +ն9׮N\<"$ +ё|CC^v3t +JFƕ4 &ߜݽ._q xo`r#lz0db u$ +-6KK ]PO[CUI# +}Ţn::Lq̑横k[;:{.]NS9Js408V +3󋴙=B;F Wt۩kk@_(HON + t]locaQVXH3E;)JL|,+UuM=Cc3Khؕ)r sj)s.^v]h/PZoUVgzL!@w8C(si\W{+ˊ 3פ89Xhtd$狳cGlqQQ3X-rr ZrUJ ل9hC&|ɕVB{#T"AgwoE\ v}Ukgɶ9צ&X`kiQH!tên&::Aqk`dj  +\bUrںy[ K*x͹r&0Гn$ ACSa`qWq_579w-6[rydH"[+3cMuEy;vpG'9Z:F&V]ܽFƬHHN[>+w붒R`N:ҜAlhγzZ}psr,|uF}uUkkQ5wcFZR|ld2Dg;vMW85u M,mݽ|F%$^e[qinsqy iG<ROD`c:ZO=t`oeiq~nVFzrBlTز>.v&%@g6FgWWzfvnKC£Rdnܴ|wUuMm]=euʜ/_cshits! + uuFGP_]xʲ₼ =@POK]#+-)!&2EǕ"'Wؕs6(UuH]}#97oB7G;tv١C]^9PwWiu6U93&8H +J))"% (:;sy}s׹?>.fFښn*JK ]8s1@>~D>.CGO>'(zUʪ>506utG% #4szHL!zsh !_Ipu}UW]QR`mn(wEc88W{:{W@D\RZFAYEGF6.޾!Q`N5s9C/_ӘC]Y}QrC#quf`}5 Щ(-JK |`c@GKC]EIeqa~a :pph_)U\qu+a1IkJ7o߽ohbac" 8<*1'9S9oQs(o-/!wh!_z:ۚj+ˊt}m,jWWU9u07ݔ`qvrMNƭ;O [;yE&$cT04g909_:w(ԡ:h_3:2X[UVdkaT;Pt-!:pu䣳|t^ YW[:ȥWe+k<|/(42&!9-39xZ(vuhztʋs2Ãݝl-M\$,pܩ:;mAٸa=Dnـ48Hq+ ,.)-v#]cSK[GW~1|ĜچNܜS39QsmCY,,| +Egx '#%!&<ﹻޣwn)+tD :ppt7oڰߛm9. IH]Wy}-}# o߀ Ԝ*̜n,TCjr| ӇS_]P1 Gt~ѣrt:HWroR~bhbnm" 8<:.15#;?Hg·M#ګ<+ζĘg{+S'ܽuCAF +A<%: EZՖmX\qSŕڽ>3srMLI̩-fN, w:Sc#=m 5:(:.Vfwo߸.#%!"s謁QY"vq+%WZ:z> +MHN-(.odݜus1:>"n~nё!2:yYȐO{k6 @đqڹ :pr,w޳m\ݹĕo`hDL|rZ&jNu]cs[f9ti::tft^!t77Ve%Fk?Бя?: RE@Hxt\RjfN~QiEu]CskGW#s𛳬!ԡ+:/{[:e(:q.f(:7Y@U耸ztv޻'"D%?8,*.15#;3o`hsФRSCP[*Jt\1t4Qt!:ppcxt֮_rtvsه/e\ZڂzWXR^U[Nޜ}sW/g'E蘣T9s(D?u.ν\耸+o䴬܂ʚnœɕi3tf:c:uUed/W3t]j vh\d߽gOJ*^G%fUV5uv |33ǒ9K ( +G@9VN9Nstضo] @tVLBǏΖm;88qq>vy^Ҳq *,*61%#;33>9R͡Dw0Gc@# сGs)-3o`hdtl|bj5s#_t޳3E9D4ή{s_XLRZFAYU]CSWh\5uvS3RAt+Gc8:G'(z5y0<,:{G^z=19fv<0=0 +3utJ +r2Âs!ܟΚE8:\9s72uqUnAqya`80gfhtLM,@G G?&vc=4\q_TVYSكK,5-ot晠 с[|N"GGDU9<506sr !UEu]#W9S39 ?}Zi| zkCGvtdU54rA*چ֎^,&@\Qa/YkNctt:G8:Qypt[;{F&28s9r +J9fhڑ{`/4)ҥKGE@* HRDs;&լyf-$df?קs\_|sb+on:@?lt*`t h}#3ttΧesU\UckGwɩ9_xgs`t ͍_# 0/tvR}jQIYemCK{z;15ʹ9yksotb@cLYJ (+@A'*.΍[Mm=}k\nq16Y.(f8!Fbйw:WOxss`t A? +Gp Y +oU44)\MҝOP6+lηGg?QczW˖AG[X`9A ιtKoW5v1ʹnG|́с XA ; ::ITT6wa :Ws5=nߜߨ6F;`mTBA'NuN:OjsūA\tAGh?VCGt1d_ZTB@N#LL!1 :9yy:FgWd@Z ` +4UM=[ٜtv?v6.ArAͲƖo3A?W0:ĕ{Wb 萤dtյLw=xO@HDtBr*εMt95N +t3B?@FC"t֊t+hhw蘵o`hd칔\:5 -ݽt+#txus`t 1+4::ػ¡#!)AgNGlN{G']ȾrvUNς @1Jl-յp蜰st IHƭ +:>Ǡt> :4Lt`t 㖰{W:Ļ"Iȡwkhkm]<|B"/^áSEB< 8v +AGZqyE m}cs,ܼ΄M:_ytxxs`t 㘠 +AUt$$#PR50iq)oԌkťۺŠ342WCgс c]Y+N۸eαvN1R2s oU6ttA+: :0:itC]J,VyEU c=[ڜtv?t!=բ򪺦;w2Cg㻃с Z栃+qtյwu석o`hd̹܂›e-=}ѻDyAgAgA] {W+ji W!5u޹AgAxW7F8BܻRV54Eq[䋗r߸UQK@gtG +F8tw%z IxW*Ff:fm{&llE%Uu=w9#щ(t/җQ9Ttcx]9vS(t8yQ\%?8"&15+x yW(t֙CH}s']qp9Dĥ4u̬=|C#ҳ J*jpt?׿l~N:^onR,t@:=wGޕqW&6~A )eUww NNzN[d:o(: `$owB4⮄ŤdUoܼu?$"61-+nG=wCB>i+:ܼg] HHwelnmSPZY磌optyWʸ+Hfo!BI9yQP34ut IH+*kliFüյufP@:6qWpK)22sv KJ/w;02N2+2t^ܤ\tmvΖt9Ƽ\WV506qp +O-,ohtrz>H'B:o(: `wuI+:w%,&)zCmSK['7oĴjzǦ- ]mH|wW'O/qW"Jj:F.>Qq9%uLw5@qW9Ի+!CӜ|D%eT4 M,l]cR3sʪ#]1CZw6/tȻ!BG@X\J[ͬݽB"cҲ+j6302>Bgvna wE{?t;CܼgqHH+k8xEǧdV64 Bg~C% + 9o(: `wW8t]Bb]Z:yG$fW5vM=y:;G[bՎc;t@: SfOl3txɻSR72w KN.(wpd1g tVVבtsxW `]#tNw%$*)khba[XVua{w$qWEFP@:;Cgp:rI|Wۡ#,.%zۦVvN!IiYw?߾+:+87tHBwu+:gqHH+k[;xE'gV`/267tN9s¥ׅ$eU5 M-mݼ#bS3ʪ[Z;&gյuft@:tvq"t8yϞGw%(".-odfm_RQ荒w`de|Wdz' +9:<|DJ(1qt +NH-,ohtrz>H'B+HX}7fp9BG@X\JNI[ͬܽB"bӲ˫] O=y:;G[z3 +|W̻ +(~sķppx嚐o`XT|rFNAiemm]]/wvE +,"CUa1)YE"tL-mܼ#bS3ʪ[ZۻȻ- 7tWS@:* 2B+:gqHH+i[;{F%gTmw`d| +:+ +9-Q2tNspu!1IYE m=C [GW/脔Ҫ; ۻF'Й_/!ҡyO|VйBG\ZN3+;gwؤ꺦֎ᱩ'3OghKZݾ?@: roPXt|rFNaiemm]#]=_wCIgKOJHXBwSRqmS+;'woԬF:Cc]FK:' eu:.aQq9%5?B3;D ]m_TrHXbg|:~+tFHpDLBjfnQY՝}CD/җQ0 +;wV=WoI"t8q\BGBF~+t]<|C#ҳ+j630<>dmqWkС]t>{;tdGW/脔چm]}]=_wEΫכ sM M}#:>IiYu-=c3hYY[ C eC3t>UT34@SBރq:s Kd蠻`Vt@:ʮp!Cc[C +/=")̓AQI<(EQ!!BDd 4%Aͣ{(I{{kg?;ソory^m&J?~Z :ρttB +c(EWPt)Egq;R蜽y#;-=~o EGT +A MQKtdpQV70 :1&9͜EeaՋ~]EA MCt%@\ΐ' :[wNJIuNy=\t:_x?DXttЄI\f,p5 =ɩGXSZYsѓgMlu]WLAAAșCgCt+(C1})iGS\^u@tY +2G +A MIRd-:Sd0DN.:]=Pt EGt +A MQոq"-=CS +9N>.:Ohne·_cWa\AQds +N^aiEMCLtZ;{^%: 蠡 s( +,E%U :F@tݡ3/.e>0[tttQq5&:0fi341 D'Wt +K*>~+LtsΟ44A`+耸#&!)%-#'k`)d1(k5cec$+<{13֝J :O贴uvBWAСk9'`̙̑`Bk;GoWqufN^aIE=Lt^4vt`q;ډMi#4{F&s&#'odb6";gw/p:w۹eU=y +9:p=ɾ=#}񜂜9 sdN̙gc7 ($7ߺsm]@̡ m elCGdD9Rl横k34;g+#"GnKÎ켂r<Zۻz󖎢C *@0s"$̙f46st [,wt\"|ͺM1̸:όJW /[:9E#DA68)#`-9i`Ib̙1G00/084|u-qx\eͭ 3DCAСG0#<#}H59̙9KQ 0G[W0gEvn^A!anؼqUWZ;1f`!:i%::4PHd |3D 11̱]$hʈѱ;RҎW /:z ⊞#Orpd09y!N9XZ39j:lz/]"bͺM1;v;p(=ԹYzESk;#@\c0"::=CNn5} .L CyV6BDm}#Np͜’jDՇOPtE'A!8$XQ24wHé990g.oаQ6oݞgGO9ڍ܂*v\uaub-#L^`ÍFA Ç;#t"p1g`9Rp1GИw/Uk7DnKHLJIK?~YVbqUW@t0NttDsnܐcf Do;$b^#̑̑.'v9A!+WEߙS.f^T商|Mt6UDDFQAcwc{^^PADl1j,fV;+x|?ϳ}׾M/:NeNv9FK. $c<*V SQuڣOAF0eyX~]{$qu_=~B;f lQam3zzt|,+uZ)S-ZإG3~Ys.Yzݦ;?||\e()N6mqĊGF&NdzTy#1"C7)^" 5'кm.{8t'M5gemܺcCGJ֌¸̱бq$G'762ymD&H@ 1"㚃ӊSM)YJgN+bN~=nԙs/^r-w;H́quFy\ƕN6%GU8764_'G8Q((G,ͱб)9h*Gk@S$X㣶;.6߸cPs\<<)X,S̉F0e ,_n?9)ٸzl\AǕ lpͬRQqø)1|=Tx#w!2;7S_s,\ۧXqfN*ժ3y ,[vLy8TvCʹ +䰚5O5Mhզ}=z9M9s~&_jQőUVeXL9Ԍf*U9F~?̙=Y5'U5'1w,::#s!O*Q*zùi蘘XLb " >`;<2X%S.lQr 8YLe\VJ͉[Q-`Zuڣw9@sV9#+ +a{f+ ljY͡_0rMUJS~C!܀6B *SVژ:j59DB{=(t[BwJHxJCwpgPy{l$ 88ʔ_ 9QjkUz?pQcs-\LgՔ44eA,t$9/8>aQp8NpH pk~WYabg:0 + +nZQ@HLHCHHB @$HH""MjZ+֭.Ŋby={o|LS9tf>ׯ(f9Ub+(yLڝŎ;6bQ 8qq؃'䑵iѝ;#8XXq.e{cM9]o-a91񃓇Oi;aҔi3f͞&9}Ps# 9rƚUxr<%AaA6$&&%%%''Az“!="? +Gˣ߁w3\iNJsk%==;xȹȲkΈ N©%OWV,\԰tnߵoΧ0o2E)mϭٜ /9DUaq7 6Τ 6l82BS\ |`O [ O8wڻF Fkcy*-ozeի7k+5籑w;kwȣcQ!78BDgY kN̬<3`Ne+^s67ќ})s7|6:9ʲRwѻJJ*s+7f 6&==#cԨQG9n32(>G<~xL NN{>8:"Ȟ]]r&9fY'3n|D5fϙ~ɓ077m۱[y=9'h0?~ Љ7_seq}b/4)86iĆԐ̱cf!T_<]f& ?y<Gʣ1Kν^wUx\x6ԜYUsʹZ صyØRâ֜;t"8a/ie՜K9!`":>q4Ӌ'**U8T +MM>5hڴiӑସT4Cy,x£ww^wry8h~Q7ōxh*/$~"!)#RGfgj901V]~㖦m;vٷ૯|bt"5͛9[5G*SrDEbIJ ހbCjf())-9s,OxҒ}cCx8Xxwty;wz1CQ(|FzDzqV1q$gc#s'S]~Vo⶝ylNNN$tZ)sgYr.Jb\qPq8:SVV^^^QQ1tÏ8(//+@О"z(K G{&w#j/h{ǟ+6T5n8|hP"IKeW0iJR]s5,i܆/lݾ󥽯8o9;zO\s}`NDdB͹@Lrr9PrUEqTapCm 3gNuu\yո"A%q.<<OC!>;rkh#(opTőYEqB(9dX@Ψ1cղZ\25gA]}+WsZmnںcמ_9pH9_+sN1t`NND*pYu#Í]}`W=(KOICd8RpiofTRCcjjϟY pSSCO؃z<*<2Bs)<L-%G>k1Hx77 +]qnsbɱ(HN渜 JgW:55δڳoGxw}O?BߜsLt"0͘cM+OqUN)Ms}1tِUA1 xA5tnѢEz'NjjkkC{@Fƒ“56r'qNo &Y&7 !5 fkQQQqq6\s֭=JW<6xjpg֝p睷]wlHh.C} {`R9tӫD,9gΞ3/jŪ5knSY;Ԝoܺ s̱j@wz!xZeΫ9-Zj֐O8=%MJ∃p 6Ҕn߾}n2]i) ?Shq\`9č vq#H=GQ|O(7 &SMFD9 gAFe\Vy6m)fa|xS;^y{<| s1CC'd.8sk2iUofN#9XVmwV;H=L`TIp 8pClH )۵kWyyn=?<.۲2D|`cAL-ϢZ5wg˺hk {>铖FizӈY5pDN'2,\ty64si90ڍ_޾`!>ȝAQxLtОԇ'6r(8"G 笒q>UknRT}gM2Gy {9/A4eNoftZ 9 UqrrRp,)F!4UUUÇ_|wUU8x<9kjtg$qg4݉9"bXа$x,P6䁜[Bq3ǝV!w?^tmȍMT6qsU8@IBYGrKeuL+vZslx<\ɓi WoIQqdVi丟!j.̹r톝ViOV9O9PZ9VʹzI3e5ha 'nL9Y&r 6Zq8Z82r3g|Tw_wNlpCopcFqUQI@9?9\V V֜9̩ɲr8|,^j~OUdA‘9oP7a?||wB{=\ǁwv`hYw,rܙ:%yĤDZO# 8>Gk6ʍxc8c(δXBj&YVc_IcfgN-W9w̩[`Zl덙9V1**fD3UɰA~O8UHTqqn@s?>=/Cz$z\x<:jrgϝY3MMI5>!ށ(=@CP3pm z3Ja$aU8@9'NYVȜ V4gγC'$s~%gZ5i%32G&a7StN6ꘂ# n i9z(4  Ybqg9tg 3/C{?CH=7 6pCoHLUEqG"9e,s/2s߼ߴs 4?9C'yg?V&s#sC愅e5n|ҤSeX)Uq4q 87؈3pyOD|hA|jGSs'7gq'3c!I%C+edzP=gCxr7FDj@p8g4ddf-Y/$~@r| Ly8ʘgNTsyɚkfZi2t؈HYV&&LKr 99:I޳w߁JGsFA(7F._.qpsb36pc*J3wނt*"S>Ci#,+dΝ~EWUa_Ŏu@+ZRy2P&!$SI2\2  0R <*X?}>瞛{徜)w﷽\iu4%rsA͜ǟ5 0tQsf *4lQ8 r?x9viTHp`N7 aдBRΩ^1@ڃ`ʣ౸S(wRѝhZ!xB<@z.`憼 PX\rJ5rZSykQssڎ99ќ_д88`YsfΞ`.5FE99۫Di+VW FhC 01CB !y`偱ƒ4;;НJ;NMc(xXZϢ ̥Hͼ6 &p6ªbq2]Trhz9 :9G.]5GL{i%:>2I2y0GN<=VԜ , eކ؍S5r`W78䆬Y.b.q.dCɝ,tG -Z:C >|i*7̍fgS|*gK(9#r#9?;9-hY]U䘧wbZ9?s%slcӪV&N5g+"֮[9! vF*.94UÁđ7 k#:""|CS +rgt)Cw +WvVf: M OGC>+?)x Y 7 8)iRxR,9bz-7n~)k]Sy`99qo,Л9/ܥk} IS͘5kUᴬ6'gf4r`WilYYQ7RA5uЍs:;vY⢡'hd mkcH&QU\RZ&Y%G<z"& sL51st4e04g~ <[xYHhwb6nNLe_XRZ^YU_c{ā Ao6Dmm#juÝ}MpG'O#!{l>q&FOvܐ78\q**80)ɹ8y\y5wӵ{>~mcߘ8yVWE@ـ5'5U2 :39q⊣1Qs ~=BM-*<!wʾCSGz >ObBO8K(oʪC)L/+9jʹṟt2ҵ{>ym&L< UN@͉ÚM˪ g?8*Ur8Pq8TZ[䍁Cpxѫ;Z8rG#!{h> +OI1Na.9Dt#ǼAr8-s~՜G7aV8VE\jN~a1, LU6Hpn4jy#1GC iS=OvVYYdM ܰ78.MS>\VwŲXsi%:0s=z?hƌh\VaZEmNHNˠJ|vPap~#!WQ:Qt +@ +> Rx 6̍ m*Yq qpVD''FZV51Ƿ8)94'^ :`Էfѧ9%Ʋ:6csEv)C}<u;glw֡9s8836EM;;_xtGƒ`!z~ kʑr;j#Aoi1s'rʩ9ΜeΣ FsM,\|eVY|9;rh%M]lbGGٝ}GʃA{BI5RSSؠ6;ߠ7Tp8m#ɹry8#mkt`Τ)ߞ=wOťeu'A#Tr{R0876<0F£s ܹl*< < CB~JsAmv~EUr|q_Vδ1:~H;+:dN{6ds:hbk΢+Bå98 K*jv7`́eψ:94RȊ#1q?]ux%$ $0*$Ujzczc `c{Q PL{ +de9g̙{%L^83e֜ (99Tإ;3lΘ=O56n޶ciY]Bܾk /̎*7cG9ICwX1:-@umްAc,9O7r9F0'_B*sZ9Fs&O9rVl߹לSϜ;ҕ,F"*{,u!wc -N-<$҃@u S>VqUE5ߐCe99GyTjNP0'$ sz9N@s,ZtM[wڳ?՜3gٲJ9?[F_U8voTظc;wG*u[(>a 7o†#*s8\^eIG4:G92e2-̉sms sL5w%`Z}j>59cYL΋RQe8uT |@s r#!p8|TIY%JW֖U@:Js>Bs7nNМss s9Mќ`g`θh/\koig_!VIUŁ36dx<{/5` `CОHqY% I_4:G5*:`Nɛ͉'s*Zsf̞G|nߵwa6X́u=ZVt9Rqqy! - Z(I>H +5Pn7781ZUB#G/wF(́qY+4'$o9Ieqs=nT4g+~vд:Fʨ9򲲓Z:OVq`S5<;;l ݁'҆q#Iu884iGA9QL9YȜIɥsnm;w;ӊלKXsnQ1ȁe!G*98ƅݑ#1{ d N0m877UUFJ&'`x9d *̉$sJ*JdZf-wٟzVeJM8F!ϻ〇a>6 S7 q|Ed$OWdc;O#-TN!s;Y+0g-wQ1\jHeq=Q5<<&=`\g®ql@FEծrk;Ge*3/:Yec2',HLb%KP9Fm4l40g0g]{03BBw<p +  >-Z0m oQ%V1EPht˸ ,Yrs#cɜZu6ntO6g97g}p͹x +V<q <pG$!|FKa0ohR p(J&'x*[М0(Y$h*Vs4jֲmӜs=~ԙsqZѴz\shYq|~A;<zÜ?nVie,+:R&91mOx.c)<<y8= ҇ Irm7>!&'x +qb%KP9fhӾs^}۸9\t#ee'ǧ85eĝ7NwpyaGIO67XQAMN`*-$S8<*:.>SvOhݾS}>jĩ3_d3g.aٟМlӊcYyoTyr !{ gmzoxÑ*BM·FǣW`NP>#c˔Tzz 4oݮSמ} f1g-7ȱ9V@Ks|;%= K#UJx*(8{7',HlIɥˁ96lܼU]{0hȱ̘=sӜ̜`h{ +Yslʅ~Yq<D*ԬSQӖm:t޻gCG0yyh*4gNN>{̹u}0)æ渓/8 $#$)#Yõ1Qcǥhr'I +OHJ.SRJ?mڢMz8dĘ͚pR7sܽVΚqrg N+iJ;NxXF~kùWMN"΢W`NQ1qK.WJZu4n֪]Ǯ= <|ԸISg]\f=3Os5Gq<\q, 3Vm878 +q49.qUU\|BRe+TNYAf-vңOAF8uƜ\57mh7͜Ls5o͟;vx2?<Ƽ#,Ŝל.%f̠}SB!(B(EZ)J}#"R Ki1z_gL{{{~~Haf7R@04tfp+qIiY9$6*iYXu+!"%$p[9@9siE9|M񌘇( +h,\7lp8P9 %7޼fG8}_@`HXdL\|Rj99D 3|p)~8ZpA=p +W.@?P:B\aҡ+ m=#-۶{<_OLESQYUCA4XC.^ qvrzVGOjGq5Bq^rxH桺oq,P:LC <ÆWR7ڼ~#N>skQo&$e{99C.ޡ:B}7\# ϤJaxռ E3WH\kon{G<p98,2&.!)-u ;VyyStCglr\IH/ƕWN>s|@`ȵ7o'gWTV7:Qwg _~J(<WZ*.%|J$XqeաOy"q_TzѓƖ9qx{x}/_z$W ECG\RZV^WN#qt5":6>)5Np΃GO::x9Ι`׋x(Q/;%atf #v +er+иRfǕ=;.^ q+1%#;[s~A󶻧꜉VTF _r < + QtDq%&!-+& m} v:8:9U+ +KT56=z +sN?9΁>P: AW#%+e5-]CSmG¥ v\7z8/s}  +P: A Й+c|ª`jYX3_-Yq5aЁ΁Lt:y  d(᧍ZzF[,mv:8:9qr 4 +8U/WCCs΁tWZ~`踹{\t5"&.!9=+[\P :2!s<:1IiY9w?Cg\A@& +P:yD, 9Y R2ѡQYMKt%2t]Ozx\q+1%N~QiyEeUmCskG'18CBx3A + Y9UkQ76ݽc'N{\t5"&.!9=+W-H\| ;> +q'ȄJgu@D+tP\Oյб)ϳ~ѱS3s˰jq3 (q~<2t6(jcC爋ٯ(-1v @&ޱ+ b]A@PzzGl J`z7wlw{faeLo8u.]u/0$,2VKbxjsQs%98:u8:&Ng%104fcc:{m:{ +1I:"\t>s;nShji';n$K+;+lزusPHXT0%=;@Z\@+pZ[to =H)lg踭9|՛wF$$e,(*.t=W?0ooM1tXX9M5BgރGݽΜ|@Ixt\bjF6\窱I:slt~Aa߅e ++)t4:Y 79bi.3,Xm>~Y؄,NaQqYeW2B :t0Й +q5oѲUk7nܸI9 tJ+D5 +lo\a< GÔBG[u[Cg&GNt.]u/0$,*VUےj:\a<GZC+N/ ,ts@g Z;ΞOk!+:1Ii9/ K+j$乢a75j:: >̹ :}@?'LȦ)UsU/a4tac`h 1;t/w[i@݇1 \:eZjj\+_pwCgX3IVv tVٰssAO£:^~#B3@+p ::lg@g>g/^ЉMHN͇窸J,Nsk`< G@3:}Z(ttƍЙ5Bgރ3[CS!/NtGNcj>q +9 l 9y@_`@GSR^Y-%/Zpt8[tSk;'΢enJ йqO#R3s,(*.0|05G@gX3IVve9xs:9:b#ݜ?nƧptTOi63ٽs :jq-\b)Nft4d1O3k;ttWQoMttL(t:Z@@ :1Ii9/ : t:LmQ5ϕ:r1:0YMs@%)t(t^航%R|nj"V,U.,tzʠ3Bd4@gTk{';N2x)R0@+B}8::=#ԒA3n<άy t ܸI:/ K+ӌ+j mg0xSS(t,Yz':n g)_з:C:&:vNEVHs̅+,tb2s t: t'BSpt:J +MN9Ytl\d9ps:q” 7t$: >75B7Spt:taS:F&:Z;@g!/)tr)t*LpJ:V.3R: й}?IxT\"@ NB&:])tzihfC+ +S :/lڶ йya@phdLBrZ@P +&lBSpt:Z4DWo K +KWٰss:Nt|bjFNFRG+:"t0 Guj:\ j104fccLSUmql= "X (]vwcww"vwa' b &H(* +zk?s[9pw#|ָ@ :V:;܈OLI}87yt@7FN}NN.]\ݼ|{YoSB'IyǡC2%C1߻μEΦ :'\йˠ)CmOhtʗ`SGcn!CБC@s:AOt-<*й(ˌ\tJ:)WS4tmZڷnܹO6 Y{(s%,2fmEСTN:t@ 9v :+o- 0|TBARS4:IǹBi  Cgr@gNt'O_HT:9)Oѩ"SSNC[;N~@gR@g N::ٹyJ#ЩgsըӊC7 CNx5,2й Je蔣SCYm\q8:w7h3u\@gF@/_OHtҵH)t9J}蘞~ht7n!ʡ3dĘ :+:qGJá6P:W :_ :J1Jzska)cck//AgԸ@ :V:;܈OLI}87yt@7htL0ts4tڴwrS@'x:ɀN;J蘚 @::B$wZxTsQڳY +t(FcbS4tmZڷnܹO6 Y{(s%,2fmEСT j: qqt;qkЉKt +t>*C/q1t(xYٺS$@t9t>}).mhtLK9:Utjiȡckۯ,\ +la B'C';7CUhtL tY\5jbq 3Cg|@gf@бSg/^ t=t2tB;ARe4:&7tr23-#+GN: tΜ 8r" )N: :ŀ6C5SNV-t\9t3at@g@g>[Iw8trJA+ARu4:&TItp4u-,tllt<%(Ag*@g1)?&=NѡT N}NN.]\ݼ|{YoSB'IyǡC>㓡S_@g"@gSg.ey J6A'ARa4:Ƨ:5ј[бt:t;AgƜN.] t?J{2#+Wht4tMK;w<|If::{tEL-c::ʢ1SMt::^~Бc'NrmP:q :NG%t~t(Fcl:Ε:Nt\O::[w*Χ/%ߴС͡)GNM: 9tl:]{K- :Zrdt +N=KFMV:n}p̞l :vūaνNN|'P*FNUZfftsš܉CߠaԙsuGN|=":>!IB#At(uGc\iʺ+ΐc&LXǡ{+NVB\1|%P :8W:6:tF lc΍Ĕӟ~WAHt~P*FǨ C>Ns@M{'.n^=e,t) LС*H4:$C1߻μEΦ :'\йˠ)CmOhtItjѩ1ctȡw Ό9 @g]eFV:%bDcDS4tmZڷnܹO6 Y{(s%,2fmEСT j: qqt;qkЉKt +t>*C;q1t(xYٺS$@t9t>}).mhtN9:Utjiȡckۯ,\ +la B'C';7CUht tY\5jbq 3Cg|@gf@бSg/^ t=t2tB;AR}4:e7tr23-#+GN: tΜ 8r" )N: :ŀ6CUhtJ?t4:ZYq2b̄k]8t£bo%y_(+DSF@JSR@^@_ΨqttvйqWo +3oJ蔑aii˷ %N6%t4w: :TFp2t*> [l +s :B :8t0$P*Fp:SN ;@CGtfY:?}ҵ8@g/3r)!P)Nбiiߺsn:?i,@gWkX t݈݁݅؂ J襀^r93g<:W#co3 +_/FhաS[:o@gD^s/Nt\b2N6S$BD J K\I1t,qrt|e,] l߭N*+: :e_+IС͡c¡SONS[;k/Y*B'\N:Nn~Al4:F2 +8WZX:tܽfЙ l +t8qZdL1 +J#*tj175m#+Gn :tfYl :v*•qIiNlr@CС CGǡӼu7M6 YsA'*6v=¹Ci,0+]#s [{O:c&Lb kGO3_}WPQNѡht f:MtZ::;ps#CgC ;NJJN?NoO߀~8t.tlsE"t:t>1舛#B'AD4:RN]qte:]2 "BgENsɳ/_Mt>x:+'_ +ht :бik߾s :F8u\@gF@gȘ[)w9tBA1PuVN+@ǁA4~t:ׇˡ̡ )QBAN4:꩜+ :f:N.o +It=%@AKy7 :9vQO9:&:d4eбs[ "t%3t(GQ4j +iǠ0μ`@gS(sęK"c,U|'PFGЩŠSԴpt1 :Й1ga3sة WnD%%:t9tlAZ4:jCyK+6:n :G4mjNTl{ :9y s%B+Ad4:*0+]#s [{O:c&Lb kGO3_}WPQNѡhtT2& :\z{ ۡ@'CghtSO7 K->wCNO :IС4~*Щ+NC ;@KWCD̞ t=yQ'/^g+SAС^Щk;9:wɠ3l؉Sgtnt>\rC'(t~t(DWuVN+@ǁA4~t:ׇˡ̡ )QBAZ4:S9WtKt\/@:KW:w+ +<{JN!Niٗoths(ES=pԓӔAΡ#ǿo%t/t Π_@Сit2 +8WZX:tܽfЙ l +t8qZdL1 +JT*tj175m#+Gn :tfYl :v*•qIiNlr@CСN CGǡӼu7M6 YsA'*6v=¹Ci8*0+]#s [{O:c&Lb kGO3_}WPQNѡ4NC Nk@Cg'n~}d,tv(sCi<e2tj tz{ġp e.r)AG:? :Q4ԙбtte0D@ѓg_<|uVN:J(҇N}X۴oѹ{OaN:s.v#q@jdL:yFCi*EաS[:o@gD^s/Nt\b2N6S$BD Jȩ+ :f:N.o +It=%@AKy7 :96ёS N=:Mtl::<|VBgr@gp : :F2ilsլӎA/`yΦP@ȉ3E$::YNС4NeUSAi\18:wc8t$3c@gf@бS܈KJNt2%`s:ht CGǡӼu7M6 YsA'*6v=¹Ci>^ 52б 3f:+:q܌OJIK4wEEoJSC Nk@Cg'n~}d,tv(sCQHЩ'o%ΖmtNȡs_[@X'qsD$PF4ԙбtte0D@ѓg_<|uVN:C>tmڷܽ'ΰQc'N9Y8s52&V]G:U cg̩Ek9t>zΊ5ή}1Rn +䙅%m4:At::^#NTlUh:q:ـN{-tt(J1rбtjYټ]T@g +t +9t>|*-mE訣SE@ +z:έN]Cg"@g#N::2c:mp7tsxá3cvS.E$:w:YFCQht*@--k(Cŭ=N~If::{8sJt\Rr6GN)!PO1 NFvMt<8t 1f@gJ@'|7NTl[:9y sŠCQJ&sem#c$@gبq +t/tй~aٹ +2蔘OJhtLBN@eW!*t:a[йdHСߒytTTt[@g|@g&:Nй͠)VCmwETN56:5uV*t8tzeЙ:s. +9pb2<@CQxt S:v͜ZvqЙCOXwй-妀NY P'б0ƀ3o 3pȱ,[uNt\bN6SĠ^ o;:FΕ:VN] t\`: :k +:3:k7:?uRdLs>e:_ :UXͱ!+: t&M^=x4̅+qIiN::6CQd 4hdkT@ǃCgc&LttwsD&\OšX9W : :eStptmtt 5Nζ:WR=|";UA[ICIԣc +:u8t:-۸w Q ۢ @'C@ GEMQSo?{o;yV@6K@X;9 : :%yt*@:+k:Nv:=2L9 t8rQOgkSFС(cI9:Щj;fN-Zu̡'OtVtv;\rS@',t~t(ԣBt::^#NTlUh:q:ـN{-tt(Jc\c@V` y:Σr|(TZE&TЩBs+@S/nЙȠN:Nn~Ac:mp7tsxá3cvS.E$:w:YFCQ%ͱ`cYC@G9W:.n9tzL6 Y{hę W㒒L=t9 +tJlA otLCG'Ӡ]SCF0Y ͡p=NNb\1|&PJ&sem#c$@gبq +t/tй~aٹ +2蔘O%蘂N&N6=<}BT,t¶hsyáCQfmtTTt[@g|@g&:Nй͠)VCmwEUHѩjltjꬬU8:mqˠ3u\@'sȉ/G&:wd=p̘?|ԹK1 ΝNQ|%PѤ9ls,k(Cŭ=N~If::{8sJt\Rr6GN)!Pd 4hdkT@ǃCgc&LttwsD&\OšX9W : :e6F \jY;8 x)6jm;t'{Ev :%&FʓntLAN@eW!*t:a[йdHС?&Щq8p$`$)Yh/{ޛ==gM%Y4Qq8|nE}u<^@_`Ͼ:s:H9~꜀WN:lst~t(@Z?SN- @]{tϞ:aSk@sWO߀` A'\4|EU ՏIԱƹjiԫάyM΁#'N}d7E3M 95j +HCٵNC)3:k7: ?{jTlbR*6GN !P9}tCG'Ӱm3wAF4 YٵC'2&Fm7EҹbBС(ST2+]m+k;{G/@ :#Lt%cεԴ2y_At~P41:ƠSC)Ӫ['w2t:!۔й DСrёSt W@gB@g :Oйà +)CmE#-ЩFJӮ=N :gtGOp%2&й0<tJ :UT=:eS,tl;lڱ #N:Y йw=NI$P40:2t, @ ġ >zd :+l-$2|PB;AIͣc\c S@ hu:)'%p|,\RU2'N2ts;8t:w : :tI'PTS蘄Nkl:Aq̚8rNA|#PidtXͩQS@G:W:ή8t L1YwXًWbR =t9tJlAOc::ml s 6jܤiՀή:17Rnsd)(E3ՎN%#նбw 3b :KW:;\KLNM(ˬt@EHc :u9t:ںur.Cg1M N[O@j:́N7/}t.t6ns9; :" :9t0 PY{tN56:tV2tv9tzgЙ>{> 9n{gGu1my9Nλ-ϣӅNw :tLͭt]ܽ„YB'Abz$\¹bбdq h@'2sT|I:B3BǣC7GC9-8Wtl8xx7i9 tn;p͔BN:9:-)FG6tt741̠3fBxĬy:3$ɿàSUSHG)F\r16h3tn;AVzV^aGe^VT? +fa?GGttt x|5@g瞶)rA=BÔO#Ngб&qrAgJΎ:g_SBS i$yˠC7B+B~::dshjcA/0tX:[:GN>wʍۙ{K(mV)FG:]B@[N>Gwʍ +{K{MiE`R\ A c Йtҳ +Kt^VVbyˠ4t`©H@Mm=!t:vtBG2,^ЉIs̜NSN::wtU:6C(tЙp)@gαg_FS$Nc;Ia*HGG  бbq茝8e [:\Bsa:MV!t t0LEtpcбuxL6@g&N!ltj^5S[Hl)/F b&1025qtq Agή"e#t0I]GG.ttt\>@ǒA7 de:1::E%?y^.; `ѠK:\1a 5@gqg.^drЩAaCj::#ӧ g1#f[ 9|T|:w95407a*L=G hir16O3i9:2ܼEsQٳ:\ijЁi8:\<:'> x 5F% *`EU {+ + {6Ћ+X4dU4ϳ޿2aay1$ttem.@g@h:1qI :Ez:&Z:Ź8;'Wt6m +Б'gQW|dС0&itt:ttt gЙ8Bg͆-ū7nt2/*Ηu %)Nck &-GЙCG\ yMST򾢊+ +ŹB`ƓQ8W.z:F&:v:s.] ٵsNTlBJzoWsO5 :G44GGt1 ja5]}GàáS͠ab&茳sr̡i@?@'8@Gɢ)T|dСC aM:t +1 Π3q*Κ [:~:޸0"&>)-#yR%!t0LĤ5:Ӯ1t  239AgEVxtNz~x<11NI0%:}: :.s,YAg?@Y䴌':J +O08W +t+A +c&@gnΑ +DS:/_%Щ`\:9&B:`126=e|=t>FN&Nqi9BZ*)Ngo}@{g Sto\rqg|0qѦӱ9W :#t&MYv#@AιKBn{U@6@0ђ訇CW}: :3f_|5@k@' NDL\RjNQ*r(t!t0Lܤ3:m@Ε +܅K tv?š%OHI|"ͻ:5jG4FGt1 ja5]NQetr8tt t0L$3:tqvN9t6m*ESЩ"ȠC7BBHb:t +1 Π3q*Κ [:~޸0"&@yR%!t0L2:Ӯ1t  239AgEVxtNz~x<11NI0M':}: :.s,YAg_:iOt +::a%QqtW@M#'Љ't^zKSkmwtps0L$8:m9t:cdl:3zzl 9LN&Nqi9BZ6iNgo}@{g Sto\rqg|01Ѧӱ9W :#t&MYv#@AιKBn{U@6@0訇CW}: :3f_|5@k@' NDL\RjNQ*r(t!t0%Q8W.z:F&:v:s.%ٵsN2͡04N{::e:t:Æ3LJf@ū7n= +@?84195=^Wyp]@:NI'92NAO :i{\t!:XtVES-tu:FS3sytl t?}ҕ|CG>LJIˠ!UQBtՑk)+-x$7;3-%D'F窳ޱFgi +ijmN]: ~iĠR:&c't,Xuɳ:7C:q ɒ\v]yGTu?ȚCFQvN ΍Oѱ^j)x}tӰA}p]Q4#iնf.:QϠl@g?9\sĠ+ND\p~8*cNjrB܃Р78ӔBu; N} 茒Bgz^G7BE>{$aճywFC#\W,:Y,:\:}v[׮Z`4SqҸ  :uL1k.@gFCNx;wẊgD9&:,;p~79:u.DCt<_tу{l׮?::$:r]Iөk}j0| Y̞xu~<\Wu .!I¢L:4;;rp7is:HMD fѹp=m6ZX28A\tE?EGNڴE3`L9g w] OH/(*!ՁH×É=ޒy4W:J$'=  tsupđ{vm`b|KsI,:z[,:Jѩj܄B+͎]uz;puvu~?:6>1Y_5\2sJHd.![, QȾH$D!/!ʞ/!}KuTӜ:?0|>_2s}/?ܯ0:oCG4?qNl"F^:-=OաACك󞄄d%B7y+f32<8׃NuE pթu4ՔRRp:?|:K xWAV9uĩӶ:~"XUV5uv326> ̢ry=TޑDơ-⠙3;=5y G]ݍtg]mOct4T۽SR پ *:-Gg5C#,*!%gAêZFm]=|./C O br׈7$$$ln|PW8xL>s񹢇N΃{Qa!W|<\l,Oi +IHtTյu[Q\[D'++4u:`ACCBB̓ +SL9c#χ9-Mxek=ݝ-̌j(ݻKZBLXȵcףf-w6>~A1I]{)(ih36t<.)oDSVgxdgуa򒄄a5o33M3ghpT_[U}:𮂯_pQ#ʊr:ζ-<COE{ΪUZɠ#(iY:gt䴌9ehB  w`Lay=8s$$$+ܼ r=4VW=EC'!&=\mO:q\_GSMYAn)qQ!>GCg9:6:B";w=!:~Q1ɩd=**)khn܁A }3CBB, j8110?̩(+.FC' ?\l,Oh*Spbt֮ t] lݾC@HT\j}C:B"g¿BS6;O;w<`8$ +U9T1A "rz:Z9`NAÌx:A]9[[VW=,/oNI1A~7Q s؊%A!aw%S c<yeedª* p3 `q90skpScaܼq~WFG(ݻKZRLXpv@g#7'ΪUltVp:<:€rt]=<}^y;"*6+4uJ˱:M-]؝$Ѓ0yNBB +=p8=9`N2'Ȱw'X&yxx5h$z nFG8+47ZUU[9I10+WgG6tޕ8t Thg+qFD&$2uJ*d4v[1yGF( $fW@j#Z9<<o>NJSS]Y^R,  s`km!WGG[W9_؋S/dR'OR$--Sجhe@#f"900nț.lE#*/Ir29Q!A7عrΙ{WB/*t~PCtt T3PHxd̞:X`^Ԭh!x;===ЧO-c"Jj7X8EPSUQVR\XHz{_ù:8t4>}_ S:VP(S+3;Kؑax ttR稢^=VGԲM o&VV])o@zW_sr_j;9ca%eaWTZiV(ZOMr/m<<<ǓR#̖FNy)korA8W1a]@a_TSNl|b2NT2x O\|f1 +PD*% 78$+̉ 9n.Wm\cĆΞ۟:8X^L6v;pDZ&>uuEsamD/Κypʰq +%y9 'fNLTDXp?`53G:Cߕ_ |ĩ5}uh0vsD TTTBRO QF~hf%7FJcde2rpBn#@範7uT˙IMˀ;9Rsl!DENNvFNj2 +ǵ + s]̡su48t6t>NԡuCcG`'!1 @ )/uEa @QPDD!8EԨh%y^ ;@wm߶VGc9b2Я_烈+\9{B<>X ̑U}\ttNͯ6Z\_CsESGX^ =vV³zp@cg#7=Xm8 { gngc#ǵ+E*Qp88 23O9Cǡ:UegT1x #>G[f+MT*Wo#N5'1Cͩ)>u%QwpG+Wvh3=o 8'&'ǜߊ̩ԩX'ǎv; +{GJa`fv(8r@O;s9gcsCǣ=Ω@Qve93'T㎁IJc\eF|2N NU'dǺc$$e>1Vu{ĉi9:)v;)x{+S9>c#1ΎsSc= ;Ǔ3X;v,4:;> endobj 254 0 obj <>stream +HEA]p^:y?G?G{r̀Һ{]t2z0 k5%Vh/_T}GgoF}~4|z@`:NHi:Z4UzCɀ9{#ԧ3j\P}V#ШoJzv/5 +lR ՟ؠ>4W/pPc:}٥%ӲU곲]ꓒ?:L}N*w֨oI;R? P? Q?x R?pRpV}5_83կU_/lWbߪO-ԏR}~'p'[V߅ (ObpOm_} +n~< P~WC_s/ ߩ^ԏ _ ߦo +ߤC +_s/ ߡ^Տ _ OWoo OVK Uk UOo OT S/SOoORKQ{/QOoOPWO +z.^.?c;w9ԫ n/up/b: +zTGV~*R7QO_ۀ[u;<`zP啺(ՍlB9&!u&0WNCqrP +LUoT`zW#䌺%Խ<*9ƩGYu10MINYEr^ R/7( yG] RϑyO Qwy[ QO @POD]LP@^!\=B>Tz|.bX !h d:"Hd:"Hd"c:#c#c:$c:$c$c%hc%hc:&Hc:&Hc&(Իc:'Գc:'د^AvX. +v7juQ[9ɱ^U/`zq\ +`zo\ +v%`zn\ +Uv?|LDt΍,Sܻs'KH*ʲ={:xLK{7sayѶlг"omxZ@WnhwzGQ!=1T=-3YDxj1 Uge幱,gZ] <5[鹝[S^ύd0=v{n!W;cqLcӸx-TgGY zf{urZ)vUW\;յ%aQ\ԩUmK]\^{ԝyE\;ԕq1X=1.W'W7zʸVlPόKyθR]lQ q&ԸLRoe6ظHSk]FܸDT+UV@U/`zr,W'՛c(خA~X X +X X Xn Xn "XN *X. 2X :X:XBXJXRYRYZ\ :!SuAP7ȧ WA^!^B>S3#u>0AC>Q;u=0B=D>P3K}u;0CDWCSmu:0D=EVS[]u90F=FTccMu80GFSwsk=u70H=GRgs-u60IGQW{u50J=HPGԃ u40KHΫYEr^ SOd`zV'ԛ䬺$g4&9.ƩGIu00N=JNyUrN Ss^`zSճ:%ԹD.9&wu-0QKΨkarB TX`zP3为^&խL29nau*0T=MSirX +LUoR`zUS䨺'աX89ƪAu(0V=NCurL UcN`zSw:'ԙ`<9&u%0YO+}rD] VH`zPG:^(ՍlBynfku#0\=Q^R WOD`zR啺٩6(7$-)40=%e^`"z+>~!px#>R>~ p|+[_)ϔgE;뀂ru@P`8 a}\~аT[ hX_*DOO"֧Y[ˀre@X9c0c}~>WNZ? Y+'S֯R G-I@fyk" g}~гZ^[Z-֯֗Q)@vy~ е^~[[/*WZ0*Z?o/ۼ˧/5ƛ|/p + ޴E7w/w)ݽ=GrUZ7֋ccݖY/ :/ub`=1poz_֝CSsGiYn}Wi]{Xo +<::7xuvnl='0M&鹡:>7YF3;zE`i][Xolt:BW[̭3t|޺CYDXo:EWXO:F߶8ukp}z5@Ah̀cY7֋җf]ZϺK_^ 8ud=pD2}z+iT1y륀Z;'gkݧY:P 8u>cphD}z"֍z!֑z ֕z֙z֝lp|N]^X8@T֩`= аnyeuZDcuzb]sֻ\X*@:X'GB:i= +P.)MuNXOuzeݬ֋1hYW@ͺZorzc=гk5u^[z h][ErHZ@:]/c׳@:^CUz=YTd3]~^Z +@:`Ge=P.O u~ZoCŀCŀbu S1J눩puT m*ĩЦb@m*b@q*b@q*Цb@m*ĩЦb@m*b@q*Цb@m*ĩЦb@m*b@q*b@m*ĩЦb@m*b@q*b@m*ĩЦb@m*b@q*b@m*ĩЦb@m*ĩЦb@q*b@m*ĩЦb@m*ĩЦb@q*b@m*ĩЦb@m*ĩЦb@q*b@q*Цb@m*ĩЦb@q*b@q*Цb@m*ĩЦb@q*b@q*Цb@m*ĩЦb@m*b@q*Цb@m*ĩЦb@m*b@q*Цb@m*ĩЦb@m*b@q*b@m*ĩЦb@m*b@q*b@m*ĩЦb@m*b@q*b@m*ĩЦb@m*ĩЦb@q*b@m*ĩЦb@m*ĩЦb@q*b@m*ĩЦb@m*ĩN4 E9"AۉV̔ŀ6\ hs1 ŀ6\ s1ŀ8\ hs1 ŀ6\ hs1ŀ8\ s1ŀ6\ hs1 ŀ6\ s1ŀ6\ hs1ŀ8\ hs1 ŀ6\ s1ŀ6\ s1ŀ6\ s1ŀ6\ s1ŀ6\ hs1 ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6\ hs1ŀ6ھl (r1 ŀ6\ hs1ŀ6\ hs1ŀ1 \ Hq1ŀ6\ h{1BLŀ\ hs1ŀG1 \ p1ŀ1 \ p1ŀg1 \ Hp1l x11\ h{u1{91{}1ۘùжu1Fۜm_ƀvLƀvMŀ]ƀvNƀvOŀ_ƀLƀyMŀq]ƀaNƀYOƀIޘs1xkb6Ll 0'1`'fcZOǀx˜418a6,p| 1VLǀ\0#nq| 32B,Ȁkܸ0'Nv 8˺XhZV:Vj@D} 0s +endstream endobj 277 0 obj <>/Filter/FlateDecode/Height 975/Intent/Perceptual/Length 80855/Name/X/Subtype/Image/Type/XObject/Width 1222>>stream +H[qӸ\0.qK܍ "$UҪҪZV}3slh\3ic1c1c1c1c16!lUe1x3]"f*{~3؇2 +[ii2%c +K ,9吖H2B MXBЯlfMZhYdU 2*&a`` < +2-,d16)߰KFi|Rߒ1+GXR0@/+TSܬTPe1eYq1ƒ,+t5,JAV@՘aI"b%3;',v R_I%2)g,s$n21&hv5,aE|)^Pj͚5kѺ|dDsEAdt X)ÂffHa`` |Rik/oM9fֲ2n2ddAU`[a3 fXHXWЌf2922;ʜd)A6w 6XcX/iT5lz`XNns_aN8qST^'0 gL3 3B mZqlnccFkX1l&% K_:ugVt6O3h&ef%%ICVֱccr 6-0=%aGX$6^g ٳΝ;҅Tx*/fZ&WRJ s,dEg%ccQ6+0la%fGX$X _pK.]|AH^/4L5m&a@2;2=-esl^Xs󬦦2cdҨ -S$CRH3<0l/֕+W^&f+W`J67%aJKRv#,!fD/_qƟ?ntSyy:Xg™hi2GL'LNK,;qYbai[;1pa؜aak%{=$AH0+X |^y֭[o߾#MgJ>lZ9t$!۹c,1䰄c+%emr3l=z{i3~/K[>w/<O&f2JN2Y߁ޞ}zYn -t}֦{3̜_S0${DŽ z'O,b{ OPM=de,eF2\2N8n!O/K 2{XnXnUֱEc[csW%cUͳ-QüSrsgW4z3p'LFHL^gٳϟCzճg&f`R$M&ǥLpYb܁2ršczVf1^UWSaհ0=%tonf.ɃBdaY `/%x/^|ׯ䅼~g03Ŕdr]$ ;vtA,{+eұ˖.1Yfg1^UW]5Ú[Z= [v݆_Gd4nȱ0#e 80K]p͛o[_O7@ A3`eJ&L2';2,2=,wlթ}9Rc1>\c:0Ĭ$kX"@A#bwAT4AAl̖l5}=s/F/qf}~3y0las`f^}D ݺ-|ΈH a\hE`_uЪ\ +k Q5 ɊH2KT=dQ,QhX1c͙ǬfUSѰҰE0ÔD FK22:F IA(a0_"FҬ?z" A3LXSFѺ;/G,>.&% + ;>cKuΙnj\̫[1o*c8[07%0CaI'IK0%^$Ws˗\ri +jin˸eB2t2Qh[2d)I B'GֳRcjU0gaVЧdPphضrI&%F+c/Et^v:ƹ!#V" A3`&,c,a]r%efҲB2(؊K8/pY9KuL1}hc,0W0O2d`P0aI2vXyQ0 XH7;::nRnO8yFfMe,Kd}{3iYr!cckcnyVv:6TƌY1o"W7lB2l1 [jZ^`w슌%c" % +C_^Wu#ݭE8vvi 3)Q'L,@nNvVFn(XűիV,[eeV|K8SQѼa 9 [唌kޜ}ae*&:L~_}ǹ/#܃+F3`jƽLP&$úJ&!;Tt0?o(d(dVm"V1w7<+fذR12A<<{oaA!rJ%$%_P(ZXʪSϞPS[ &E~ H.άyF3(Q'R!^9{QslìtfVdžZ_o6b4lu7n!ön צdJna + +%$F "Gz783ja&-(ѺD%!+?VZR|`2kǂ6 `V.fIƾJbmŘʈƎ͓/^l06lN))v5hYyɳ#Qš/_j/ |]Ǐ O9d̨g ee;dU'*yYc9<,MmMrJWN:6X$c)TTF, [`0l:/`X`0)IaJfbJFKDI1$(aB0`/Ev1[ G> ҕQ#fdV&S&$uJ(!>}ei2;SJ7WMєɓTla،a LJ0%ٰT +:U}F' ;%; F0Ћzg(?4膟hB3C2M2Yx[ T:q䘾+Xfw7SU9^2FuL12±A.b60?2,,|40%%yZIv$JH!6п"!?F>$Nw&8e2]2d72kkxYV±RcI±P8J:6ud^`̰*uR7v2lK m1!&kdK 4$5¸ DH/ŋ_ _R~b +? ?aфfҲg41-q%@@ܙ(d<,Xp,ܵ#6ޓ<%tJK6ja0I0_/ T%ABtgѤfdzS&K$JƐ" +Ys<,vezZJb|lt4+yul꘾*'Ѫ{wSQg^VFKĆ0l07%K 0'OWE XOKZ0`\/TF~v;hcfLJ&*,K*d (dccYɉ1QrVR'˪$2cTcV111 [|ɰ! +)A 5 Ka L/t=6g H3i YN.dWQȬ?;59!N@s3Jb{/VbLE ixas [c4lò+(iI2PVI O޻R:ƻDE# +ЬLKIuo ^ڪcXIƏS=flcĘac3l +:l6L:%eH~)Kw0&voh| +,X +u,ʥϜ<~4,e[9hYӧt&Yɓ?8#>}Cd˪O_C\a [+ 24 dMɜ\:pIVAI3c&~{#g2A %L2)K4JK ,ssv5JgOܷgv6|Λëi0\}1c=aL6z$adђT%`d_®?({t3 $C O2)K ''~&kAMĤ%7le2aNf°`ݴ{`XiYyEz{E Q^??f2ILd4,+ʹcwSYV9ͱ-Ѫ9mWNv6`z0ւ2sɘR#gdC br!CavȰvHð;ȰL0 ))Cѐ”Q~q~;Mo0d",cY17D9zp?T?TB،ƏuhoL~&'!bhuCC[9tyhQòscJa5) 5#0H!/_uΐ3FZ25dlc ıʊ%E,+nߢs,c܀CU9όS<&we j>cȓS=B dn#1imckO ?ø%71Babaܰ"dXyEUuMm]=MI1PI~-Va +|)ip)L JK\bqjBcw;uHXkc3!&:vtXk'1yqMCפE0 &G:jڰ°HdXuayajc f6aD0`ti2F21HXrǪ*ːch%9v1"Ua^kWX`,d7c$c住kb&;!6tI  ; @  K㆕>,)Sf)IF;J`~ӴL)2\0Ȕ=}R_e%̱q1W"/SU%glf̥1Z ƨb1ytϨ'5Թ >}0}̰:%b2ԆӇ qµ w?V kÔ)i8ָ^HF&2o kxee rḺ뱬*BޱuJ&cv +ƺwҩFɦ'I=xM!Fcra+a{ KƆe *aO0uJf0`jwژIڱϟ}q]-J<ƫ2=;1ck/Yy+b`eKڔ1yL^Onm9I> &F-E†mVvƄaeȰjnNIfKIaf.^43@i Kط/|XFZj2 pUc۶11Ɛb1yxZS #֊#^Xbᘜ5gB%VZ O ;c؃bjXm]#^f)a0_Zk1dAFR/} +geQ>c*cػ 1v1cc]t12ZCScR1yO'u5+b$&-Xx +5a K5ڰ7oDJ$L0MLkf,2JxV9VTXVʄ+O ÌmČ0`163֙0V2&O^O'?Eb45"4L,l@M:yxC,:v䔅3f +6Ȱ0r $e1Gؗ &Ndd^Y8`Uv rކj֯-/--E1:Qe"'Gal(ra8)FIY91[i&=!Fdڢ̬ܼ +a8 " 녆a +Vdu} ͥHaH&9DQ6ΜUy~Ƕ!cELqƦXj)!ƤÊz*&bž+(?+#b2+'o¢R`X5ݰcLn #Þ0  1ø6dL2 :NcpݾS'O?|`ߞ] +X>X"1kĘ1y9Tl jJ>|'qII ĔMwtvsG5 XBRJeW..- ۰B~FMI 'K㲌s {4ސY)c*{ɪlo=~`lNRX^vf:1W'1cIc +cCć븦'y +1Uub.n^#[(dkJ+kj73 a0^l}`$2(sc*whm9zwnR0F1/wW1 dI++)eeqS7%e&C=+*SEG{9qp-Y dIYez`lu 냆=2 jD¾X06C3+9A]8z.w_8wɶcEM056$SDIaă2Ȟ$34 6 0+$ dr0&+֮߰4 {M^da&N7IpÂu&t1ȪUym'cM uJXXTxh1+ S#]D''+ AMgܔdM=cS + +b1Pi2[Ur]M[a4v c̰&aa&iA(Y98Hc޿GT奋c'iFmDc,2sqNTȗGc 1V >ډ)&bRhT&Ĵu LͭlȜE#j2+7/mu;a4d3lfSrX !,cd,s-cϟ=%1v|TʄQK09H_WK`L0&#!SLГF&6vt`M.[PLհS {7nfWLe,LGJVd%DU]:فۇ28-2C2fifb4aO^VF +3bdOjYL@,ťplػ 4&/ 2 od%*AUBzt_8G0v=ssv6POGsdLQǿć)6J|3062mdɒJ4PL6|,bSLГVS (5 12& N.~ad7 +cα?<|wW.]1+_F29;8`VFښꪀ1%'wPҧIcГv.3<}Be!@MVlBCɶN`/6 IL|'ʧ?=~O2v0v%RD̞0˝`H_WKd'/+#%d 7%>|bb`N1m]#ԓn>~a1Ⓞ6nVWga0  0aG8R1sWr`!c'iU$͟:P_Gkڤ *67%>|cSL L1}CaOz 3w~R +e6nٶcמFb]膆]ya3ͰOr f%eU{{wnzycu[kIr2$Ο9`POG02NY5nJ| (L1c3 kԓ^BãOLYHCl;͇C1yҕۧ=ce} Jث??{7cU%EV.X 1nNTxHô)zښdSASJćA((#*e + `ab jБ'x7nݾ{oh~51cT%O]1P_0V^zi b‚=ܜO05PWMIƸr>|#x ŨA)#Kb6p{83'/p X}mim'7a}Mþ/aIcªXcC-UūW.LOKN9;8`dP_G 4%`Lϓ>(&<"9)=7>)uђekJ565I ko޾#24l$gcdc75!6V-/.\859~nLY^.v6fƆz:QS*pSqĄIjZFp{ KLYjC-Xc&v֝}!F7a/Ɇac_|@aH3`W59ɊuwIQ,*қ +t{& ]HłXuIB}afM~p/x~x~Y 1~>v֗L tTNI + 8w7hJjJthbԂl)kzpxTlbJ:XUM}S3I7`!]F1|W%`["cӏNFkf%D^pqhjvFIAV +kJyaDc >P"(yw)&$Lb:FXOzE&g!$q0Ljas 06[Ɗ r3Ӓ#Bz;;Zh=}J^FR8`})9ٷocޔߠD\1<(qbAy110ŔTԵ{204"&>9-+X[{'Ic?ac*1ʲₜԤ+^n6i*+KK8~T{xPSC-Q@1뙘"i]v{2:.)-3 # 1aþ4]G{U @nXKS} `,?'#51.*,鲵9-5rRBME)עD؟Âi&BP=.&)qy`=_TZIXb1&!,bT u}[a3 "cc8cJ3Rc#Â|<].jQR!4%/hՔ_gB @Pn #DĥU5ȦX@HDLBrzv^aiEu]cV"b&!F7ssT 3l~E>Qc`l 2V]QZx򢉡ӧe$܇o!(bcm`' Sg(XT\RjfnAIyUmcN"b&=~ 1hbыa9F^8ceFsc]uEIa^VZr|LDHUowg{K U%MGєZrcV-R;Lu 뙘7 dAɳ'APjXhdLBJFv~qYemõ뭷b8b`Mf?ưe + vcUf%E_rslmaflpNKME餬8֔i6%c}iv6ΝXP +Ay >£Ҳ`O7ܼMB#&c Geu c3$ƆqZ_k*/.LM + tudjy)I1M+FcV-U % m9<",*!M ʋVvpD)SP\^U|1!$6Oߨ3@_O'XMeYQ~vFJBldhiEyir+5%U}4[Ȍ+(&pX IYFݽ¢)VTZY{ophSbsso)ba *I/{306>:|gvO筛-M5Ey 1!Wݝm,.?N)M1jJt#"FPl#Pu.GE@P*bAii0ŪaO3<:>y +"6# 14l3{wcꊒܬ`+^nNASlJ8Țr-jJt([daeɻ{DɃj`hd,bkswdDl"$aѨʥ gFsc]UyIANfjb\TXEC}ZMyfFԔБbb0Ŷqb:",*!!>~AU)zrdl x$0Ȱ4ޮjʊs2Rc#CAS8ZVWQ>)'%. +rޔpD)A1F 6oivvNn=~>$$|BRVAYUCG7ebjfnai>źo|SrHC \^=~8591624׃1V_SYZ@hJ3cДjKeQSZ4Э#*!(=ؖb\P1B$eO*j\0st2eQYUmc3>ň=KJİ\ɰ/x2q!ccC}=n4WWf%EhISrsRkJ*c 1nU݂bk11`ſ_@𨈘ZΛ\2zk;6&&bb}# 1z3 Ǩ0c)m7ʋ r2SASxP4)yvr5%jJt+WuAc"Ψi\wIHAYY| N!0`O>{1&ɇ}6yɣG]k*+HIbISMޔQSCM6n# +N{b3}X@8Ѱ{7^y6 u04e\TZh=)9܂5%2Mcl?W{D+Ƅ+w\hqcR)άT!"{JGi!J{i]i|׸kr']?> S]dmw=xs.AbN1"bCg3 N0cfg%'& {6Ñ4Fr,ڔ`Sc4zqqk+*[tŚlw;tyk7=23;9zUVUc}$#F?ĚڞF3cuuyUVAr2RMv*)Ѧԛ4kʁ){¦ǘd?lS~_eܾidڢuɢE1J[w cE+-lwę yyG=D2+'= b9 ?ƪc%E)r2SCѦrҔhSҚc?hS602nbRҲ]u(@1Ͷ\rѱHPfaAI8@ORi '"cUe%!cٙi)OD`iʩ/lJn]deMm&fL~Ꮳ[#LbW1Jgܤ3 M-Xkyv'^z=1APf`AYVbhOQ&{cj*KK^æHK~ 4ȟ)5ǚR]ה#ڔ1Ui.qq։fϙx٪ls.z +y(WP +%{%b(}ś0V\JOMz4eDHKS̞5m]x(+)7e;JSoKd-ܚ+g¢b@1'O5{΂W۰eǞG:rpxøĔ,(k޼N1b_~C (æLǚ2Д'abbДHSjij JiJi))7_-pkvcRQ1yACT`6{nzzG%$fd> J)F;cqƪ*M()Oכ8nj*hS"6%˜d`V/ʾpk(&TLh%+Vhsc/\ +{^ +(VQJROþ0V0VS]e,'+ڔ/MsU˗4DRڔc@16bfL4bH}/Ǭ T?;at}y@57mݹ@n }(irZfv^P +*k17֔L"4;)561u)MYFZ +=M).Ƅ TkcAMk6mݵ3\wGyP,(VT\Z^YUdŚ1|֒0Fm;^nMyúHSFRД"+kJq2&D0t1OedX'Hbjꚨb-]f\r=1b9/ŪkA*ֲ2X5`ДxSǚÑ{\8pM2&1֊Xcx;Ն> [b:w#* 3@ٶkًWox܆ESҳr_,*)c ʦF,?cHSB@SVUӚ2 m MiDjJ%)M) (&&\lcVbRSQ֝7tJKkm98t(q/_UTVy- 1ƐcהՕe%cCų'ڷklKr(֔1913U)0@/+F ʦE|#c<>16僰`_oДWܾe5+)M4%Xn];JkX_p¨1+)#D8SS=RcM4%1`B[tڅFvLF21n꥘!O=b.7b!| + +_kW:c1VGlRJSFܿ ҅)L=R] iJ194$예#7و(EFQT:H.E%{{(:ɚuffg71u]ggysF_f=p~$D٭;0ގ1u ӯcuv)% |T-)®$ʘdZBf8fS|z;TRVyUQ/~6SEQMeKeS>6eeEfSN;rؐ) qĘ_/oϮjl٪g/2v֐fcJX3"L"0uBvg"ed2dB!~ᘕe(2۔XciS^My7&eS1t̴>~zx{p*U!kP¤& ~q1mtB35ed&q`:+2e{6sڔϞ>7qiSZh,ܔ2x@vFjR?ƘyƔUXo~@YULkKT¸` 0ǫ-A/t=,#ʸdTҨcFޟb7ܯzRH/bJ4ݔհ)ѦޔKΝ9pQ NOM۳<*ڷX44X0"`_.GY ;;YFQ+Cɚ3dȚ2M1QϊbפX}kR_զ;ߔwMy66ڔ ̘:yؑ +sS8c":D;jYC1L% F_ /$E:fT̐2ɄJi cFf%T=yf(f&:2loiSޑ7emʭE`SΟ=Iƌ:d`nfȰ ަl\cdI YÆo#)a`2`Ҟ⦄[ZZ2m!cX$XXc)#l¦QڔU|S^pTwo߲qʥ bq<0'3-1ukض 1f+ױf7օLx'9$0dut4 s3FJ2VS YcU%bu[7 )ʛ3G۵m5+,;sZF d `,6Z1Ę)EL%666u&0Y0/ݽ6xZ&S% k 3qL٨cVC1 2 ҹ'ˎ>wMW/_`ΌƎ`P^vFZRƘ4*]9;:7cc*L1.`Q0*a 3LtM:;Y)$SCFL1Ym ,lʟxԉ%ٱhݪeϞ>u#ec}D܈1yU6.:@LF`Z`0(aR#0 <<<f 5 Ct  +F1P///oo&S$3F2&/d|Xj3PbQ1F)_7])ϟ>Y~}mްf҅sg}1e8b,WbJon].sl +@: +`(I5LMۑ.@0h`ӳg^J?-zɔd.d8-ېҰ8S Ƭ$bKMMyԉܺiK̝9mqG 2P`,ߗ3ޡ=J'.2&DNȂfK0X$40BH.___???Mn4Ќ,CP2dT8d:옙:Vȇ墳)Y/U6=)Ϟ8^r[֯^x +'~6z c|{t竒11i0>%EVt F  E0J?gIֵk2,ٰl)m:+uX}?4#0bF7X7cڔإg*+J߽cKѺUϟ3cZdlXdXhPJ)Id23/K̔0;FDNH` 0h_ڇ% Ӑ0ː2X K: +ϚYcƪQb2fnS>zxέ_u'K۽}Ƶ-?{T`lX 0[^PΞ-w*dd4CL %iooJXgF$60B#"""3Af`QѺTA&9Fւ;&JM3VP̒|Rׯ}y'ʎ>o׶֮\hS'  dQ@uLr9!e2fM8`` % I(a2a`/ 슊 DGGE!gZdIu K3+%l Ƭ&b^3ٔnwo򅳧N>wM֬\*06KN +V%c]ԎdD% j#K F C@}ccigqqb %#Bޕ-Y)F_C19mgO[7cKسskV,]8oX~nVFZrB|ߨ +Ѱ!S(5"0I0=hIj$#F$ +CP~ IIIɘ g b,$ TTߥJm3Y6*ޘٔXG߹u믮^:{v0 %FGXgwR WOe&f0a2ar `1t/+ JMMKKIW45H3,f@"AƖ%2c¬T11e[4`Sq{wn^F,/=Z_061?%_lL$ ` ꘗGWh1ȘdHv\0F=93ؒ# A#/+##33+++[8@d,f@A %2:1>b7 ؔسܻk_^xcGޱEa1`ЀI q:M (%̴%"an)%*!_WvvNNnn^^@)rssrIthfDIF !i sk$t1U@X}8#?bF1?T՝q|fnD{TEz;k +T5hb41kXc5n۝shd3rWwܻK֍kW.]8w1fl0֡2 1ӪǪc{?fܕ3d4-ك21Sm_LF U6'l0%(q_ xixGeDKI&L,K1᳚cošꌽާ+6ܻCݼ~ g;yCc۴e5!~>+yU"2+c22|Ɉ2%U߄ى!i$LF'/CBBCCpkА`,uƔ (D9ϓAFMdǤϦo)W%1qb^)I/6;ؔo^zߝ80֣2V ScAyU8!Ҭb7I8f+#ĴM3{`B00 al$CxGrIW0\Q&-0#(2'Dž,gRT+Eݟ?\3`gv)cڄبРU^+ìdǰ+mmL #e f0E#5!Ø)SA, a#)´0 xEGSlllLLt4<G +X2$CB~1 +I{OW/oJf 3XHMJ U 9rf%;FÒ!2Xƚ#!.I"l Đ;"3& tI`HLLHhYQ&$C)-] [0rLcYicʪ7+fM >wG0vʥ `81vsK +%crUsR8] K 'p++XFf|/R0D6nBd"l:&sl1_<,%dB2Ans( FfgJBED2wSa$,YMz¢b:7-/7(dd<,c49+"ǬGX7 r؟^Θ<~)MK0vY}>,+.U6!r,0ޑ0`iĊ0{I+"8¸ ~A/ظqMsccCH#K %CdHD 嬤0~͘X`flX9]1K]_R21~mJؿ;|/>ɮ;䪬,+.HM6Ь4: AƐ-P$cʦOfFhEJA Äh3 +"Y0 Btm֮=u_y{>NrC-XA^Nf:} s[Ȝd$(#fB3pf<^R4dec3h6M܌_h`.جns<8$0_%$lePphx5z KNIKF C`쪨2ߕ )ɤ̌4U8,1Y9mc*G(^~I{nЌ9hK1' +^.3d~*KmL\o_~RddS5&?n8#h׸3s1w:aV0I_) `_{WUUuuMMmm>f?#'TW3e)c'C%dY,d1gbV{}iS&r* 2Ř R̙1)6hN|tHGۇ͍uXz+L7/UȼqG%ʦL< M$h*%)1ӕ_LoAX8 !a6Ed~! C `h^ԫӤ"ƆFHHJ&m.V RûBW/QulƴeUo*O~0cXH,ŜMO/sgO|ı-MYmYc_#BP d u@lh6k&3.;Aꨵ1'ؒSa00[ZZ>dZ9ᦹ3PIJl%ۤa/꘾*|c$+?70fmJsswp>c cXX:2c1UȰ,T2HF`1CMyLLJAa$lCrJZFfvPL5_ī0n/ 0ed +ݻ鎩Rձgl|NKd ^lbʹn3M8ƾo1K1#uϮ]r򬹎cD!㲌ƴJFH,[͖.- ./ FǮ[`ݨVc箲=ڐ$aR”`L]===#EO9fhfJ2 z)d2,ߕlK:V<YӧL?w`5Gƞ԰Oh=&Yb)[]fJsYXA^n6 Y,6fm% 'e ,0 4-<* ~)"E0DۆdMU J/u3gΜ߳=9ed Ӳ<]pLUTY$u,"4x%V"Ϛ>U{ӑ cO>36dU\.bA~U:vZcqlKqQ +Yvf@iI( %fAA|BP%qG&g۾t=$v"Lv!$_Wo9伤OM/I#fX(ه-(dJ-Ŝiɶ1Qڪ&cgw{Q1ŘkRaȠs*/~҇:vJ}V3+ٶE2.4LKV2,:luddDDx8~ `vX +MUo8Ha礀/W$WUnPF3XUrJձ̴ jU\7`aC6R2fd;w̩J8֮9ނ?dsdi) ̖wbbM e(o! u[Z;vF:+&|OkL,eJ2@G43kP3Ui0(ac j' c+Zc)䁌`훲*:&xrL-5U,d{~}EUuq8kXbK${Anl((JQiE)^A@E@m&vlX ,|߷f%}7@,48%)d5~IQ#x !(F ~1 + ŰpYHe$K2Xs j&Ȱ!pU\d93cCcc _/c*V(Yݔfs9JJbWd/1p1J<E:fMKINB2 +!B2lF ^F? ;Zzz(p&v ;# WLpݣЉFd2YpXcYYmUjRblX[`)0ZU|\)2b{#c7 +]|gұ̌t+ˤĄx e$T22 1߼Y ul%6:*Ve`&_dl!cM֯^JJ+)#tV}mV^,wC $&YYک \^8`B4>$ayDؙFъd_®9#H26 Kr |gu̚23nʘ72֥c6Z4kҰ^7)?^3XYCŎ1d̶Yy쯓yXȎdqRUɀ2 14BLrL1?*Yi-ddXʰ̠g, + s<fG,"ZiQ S ^3)w꘨c9aMm|V/_pS&9{@ߞ:oۺe&ꦬ^ ʘ)+b{Kkޢ2deXP3 Aӂg&/`B0*aڐi@S{SB4t:v%؉ܜYT6ZdY'3b}ztԮM)]iS~Xy9QL4JY)cEW2d(t2 -@3Lc|Q#`X€=f=cCR%LW( Tc31*OS +-`U˖|7wIF2_]:l*2\1s3&܅cZ!#`ZjѼ3 8;O;ROKL.e:v*c~֮\xS'ullSVMY_241s0nV2ldd8/ePΒg9$`B0(a@m;žf#*׻wde98UyddqXltT؎@kV~hS&9l>=MRP*1SS11{{g/KT2 )fz ^^H!;w+2&I0=`c#cUYpʥ =05+.7kG ԿwmSzծ+cʙe b*))1Y$d\2Z@Yf4%tub~1`T4!ahKI?{tÊu=c؞]۷nY|wsgM4n!l/6kfsƘ9tXc `$ce3%] +~ `ThG[/)%N/AwLcE +c91K̞]!۷ljsfL8v0o)ts5jeOf+1s[cė%MKd(,#3}4`EL0žs^V`))I⫲c ;_<L3Sm\vQDhTEq_qAqCEEPAAED}G (*qkBs{Јz{7mজhmafw ѦXOq#)5D=j똤c'2, X5s~A`%썐0>^@1ce%yI q1g##BoJ[) F׎2$ Q죏1yǤ!c$!f3 + E&& /IY&vSX1b,B̙G|tߺ n93M473lJTƴ@+)cǟ$똄cL!@~X2LeLƿ_,``L |ޔ+M9}c G :d0,c}2(Ŕ:F;Fޑc\ȘJ$ÔA(ҢAQo#``C-Ɏ/ Z".]<u2X`~vS.;v)]ƾ#,c"eL!)"߽cĐJ%c(Aca`i`pEbDb {+"L_r c81>c5UE9i qFFR{-ׯqXf`Ό-@1Lu!eL!)$j KN#ÕZeH&LZ# 50#C+0A "L^0d\8u .cD]RU^Rp!̩\4o VL xe/z1rCSJ$~R c$(XFaF  X00 !cc^cO9*K +3RcOM7MNkW/^0gI֖f&e2F&"CSN]xђq(Caи_~Qт#aL0\Ǹmޝ[7t 7+=ؔQhS۵nJPϞ>ex~.cIӄٟ +8af4g78Q%WI#LP=ciƮV_(-LCڔ^]]68Zd\q{~._>!)*t ZFkƊ >!LQBp1ֈ~ +mT)ztʘ2;eʘ*c2#eL!),p' Z0ÜC+)a$g1uS؃wol~JeYI!ޔ`S2m3[l$X/PȤԀyǤ c$PFc ~~Knua⻸qV%8abehSxP~Pƶn*cAKtF&CS`2@2DL&CX Sa;Lnc chS_(-2%bltT(c~>v2,,cCvn-R4(D1EFcb8aX$S]&Z|ƚ#Ц,/)JKN9s*<*c{@s1SѨ XOPXp#),D1Fb~ !KXj&7u +auXk˳'͍Ѧl +6eiQ~NfjR|la2uY[tywPƀb]ɤTnbchhʰe\$co޼~lʚ+U堌e˘#(c ̘:b7te LdR*CB^nJTn2VX]ƎaJ{O`en:faC&%UȤT|b _Ē3?sTIM6e㣇2v[ƎzܶyK2f1`$:hR&R!iVcvØ`S2FmJPe,УGi2yl'XBRW[LJQL"L))Ake n;npإ3N?kfgU/3cLF'ȤԌ42t3JbM {2 XltTDhCxoݸ~͊Ф4369OʯȤԄ46 R?0dW@\QZXر@};=\6]io7)MƌA&F(Q R2Ɣ砌5Se.(cר2V\x16:2<$8wnm[׭^d!cAդLJ(Q4`cԦdXa^Vzr…sO=w`vMNk.7v!zI NJrB4X`Se jTd2vlAwpۼqbΤzRLJ%(IEi|H07gݻsܬ計Çt߲qKΥ'Ĥ)FʘBdŋ2>SƊ3R.Ŝ9v,gNWऴ!RB#QDԔ1jR2V[]U^R{62<$({mW/^ЎIG2)""ڔ2&n\(/+=9¹'C9t`֍ᤜ &2"[͖7,+ϡ'c>LIمLJ(Fȗ֖ݹPXyIanfZR|ltTxH0BnJT PƮTIMO05W 1J*E~]Q "BR\r-3DQTPr19rְf-k~gg?{?{v1{k$%Rx:{JwܾurEiIQɣ9]%%e1HJ 錽-PR@IYN'~X$)$@ 3F[9cmpR򀗔jQRr4NRZI$$%r8)c'e )3eIAPRVrCIII,`1 $|l$eqi:)7oL$eJJ&LRQ$@{?c޽I'FqI$L()mdIJ8cDBrRnkEgLu2X椄3F +`1$Dbt&"$%1RI&{RIi* +tR$%hLD!j߄1W̓1)* gDbQt3)ϞJhb1)# @]&&)KqR$e\B*)|<]qRRNJA")R$)W,_(I bY$)2%eATR:rHR$ +@R7) +NIJnNvtRji +%%1!-)_Mʃ\2R()MPRj:cX J4),'HJ S|Ƙ3F&`10>()FҋNJctDgLi1!5)uKpRPI0`ᤄ3F`14$'e?)&AS|<]l,PgXLѣ$eDXh0V8)5G,?c# @7)2:2|VH`xk S#tՆTVRr@cr +X IIOnRIpޜqR9Z3f1И|ClR"u%E'RI>eՊe"Ohj`'[3֧Zl񢈹BMΘxk)gL)Ac +X &)3IIY 'ePR^\YVrٕ)}ݚ ͙4ʌwԄϘ`1D'SVRT_<}۷dMnYlTDXh0:cܹgLeƈ,IyҒGܰn% gs(u EM$Ԕ_M _btEg+ܿwӒb=c#giʯ3gb.>)G'%:c[f]M'ؚ>eK#Θ}pS*oʾxLD"d1l%eswnߺ^{>c{vmۜBgL_WKS>c)M bIwoqRRg 'eKc=7j.]<ԉ#eؚ>e:cXg̞wtFigߔƾiOcPrX IwƚV{уymJO]X s<\Xd7l1i `1LX{NN=hnDIׯ^*m=c^n-LhiR5"@&bW~R>uj+Jg,wbyg1):XiL@&1AR673v:cΉhOrwv@gt!)U))ʤ1,lI~F]MBKg,*",4$05&ՔCTYxLMJZc茵gg],>c[0oS'Mpwqo4%HcksM,BXs}1gl>cI36wVH?/7g{)GQM9t}|d>@*"I;1dvkAgRg mDgletBM7&!ƨ34W1 T.(`1T8goPRrXmޘزŋ"g?5ՔFz:Z)TUјF`yR] g۰nMbҘPSxxhQHc 55OFc;T|lu0`1X>c{Fgu֮Z|I4jʙӧMt6Gci1)pX NR2guϞ>~Hg>c9;6M9jJG;[+s#C=]mMuHcyQIUe~BGDsug+@,I;{;vh۷dOY2jP)ܜXja}hL1*Ⱥ.e{>cwOmi}=ݜY[#՘PUXLe[/@.g7{?cXEiIљ>/{ $&DM9} NHcc F3S%Pd7W/YhIJ)gJUO=G) + ?q14T%,׊d.tWX ᤤ[3xZmuEYɹ3ٙ)=59nʰ?/wJc\ RRTW%c-(=tWﮑb&ug 5eKSwygRiqQٯ*< /cs," PL( + +&,$sB,9+0iu +3kDtuag?t 8E|o}NW_}_M>i\hpА_oϾ{tD9ɌYլQ*0&R)(ūrșyɊ0B1K_E}~/aS>ynn6 N8/l5+覜:1,$xA<݀McuLrLU +S4a*VZf/PLĒSP{3\ne^rt)SL?;.*bʄG?pe̙cUիªJcE?LKo2EGb2/cOQM6HarѼY#&3zİ@X];+VJ6+c|!S/]:r9ɾDŽb"2A.cO޿{lSlSOZt¹3c"'3j@?p!5Wv-*+#جT8VGES+x)l*^ȘjہL(&bY~+\?w;&ޔgҏ>oέ׬H\`ΌȩDž +_X&cuk[դc +s,FZ3m +jvrb"e,kRG2Kޔwlٰn㢧M4$Wfm떔UY1 +Y U`Qk?XvtGEÛ2mCSvm߼~e ͊2!,$xAJc6 UIu ꩧM8J"*t$3 YQ#)ci{ӓGxSf<~Hھ;mJNZlyb"&O2c̥cmc͛XU1.d\4*NҘKeI/s1G{ )snyЁ;l\zEsfLGҩ};VN-ȪDutWBVJkF n) M e oL)O8?e֮^`ΌI12*zvԡsk*YCA"9!$^Im4RUVJ9KYҜL2ȌPLW>ASo )ӏI۷w׶׮Z?g,{[n]:wJR5_9g%ޕxXbdɤy F⥠QUȠ184 3-dƚB1eLڔMym,)c۳sۦI%,?{F̘bwn]]:oV%c0+kìBVYL 74 +P?T 4++J\(dR!sX~Lڔa޳MCNέW/]8wRܺ)YXa˳o^]]تDuJ.d0,2N2ڎ|fHSI3RXVbؖ*13ܦ2'owo̸~N=t uV.[144g>zUJ$YA!F +H&#h..Ue*Zw 4bDdBfƱvE(&bh1My77;+eX +fl e,&2|Ęw~ntU:fJ1\ȠɒѩWFQK@Uf`Q&W2 _ȴ3H M#elSRʺq?qԉ#ic[M 5bA<ҩcdVRcFF%O=Tk Wu:!4fYE#QȸBF䘑PL*c|6K)ɹy*0~3]blΌ?/Ͼ}z:g}s1RddU"b9D1vpՄԢR?gԲʬrNKZaruL(&bh1MI{;f.0vqDM8nÇ޻'clC}̦18&AF%FABϸ%٪ |GIcчydԅ̜cEїF(&b7|6'Ʈ\pI`l/c,!15  8gc0+[$5EBF: +\\bx1z4 c&=K2E!r R(&bh1D=} e̸~"0vH>sƏ !ձ~{@u9h9f CJ&dI'ɨPJ#n iX32d]2ȔLvq8uL(&bߔyqეUˁYqё'ª uJX+p +Mc duv53MZ]vQX֐,68'հfe6lq%c YY"}Ib"ަČMgO=XfψAW%c}Q&; kjK>-GuQL..b5ز4ő>Ꭸ5^p'#@ +Y, D M#lʼ7_EbV֍k/? OٽccxU _/O<+uŎsn6(03ԫ] vQ@f(v,i7\@3jdhZVD c9:f DY1M-f9e,cclK,?gflqcF:?Jc:o idB^{\QCwYKEZCpQl˒ddhZBVKcuU%26%ثOOیs +֬\`hXPF89ťS1Ț(=SZ%]D. Ғ `F^UA4jd,ar@uL(&bnJXG"2cǁ=;mް1FVelԴPBG Cǫ?vgw׮.hXJaZPH;j=Shj Y8Kp^:;de1`VPƄb"gM }}{xg,1v 1ecrҪxUEGFL4>,tȠaC}c+z°$ڑæ4mFd j4m:2LgI4i5uńU **@dMDDqC4cbM5&im?4i9Us}sgoyGǿ##dF#}rtdѠ\d}d~5.d<,_yE89f43b?)>O3mJb솖1Gc-77_[[]YVZL2k9 3b"BCرprX2l,G gی..a(d''F e`$dCqXwvL;+[Ǟ5MOC1#v'1_f3vْ}{Z[nn_ZJc)Ictv,4ч% +% ͒Q'N=B$"weS cVk|uv&Ϡ[dz̎QuL/< cbF(V6/)gN;I{۞];l[SC؂dp,M0Ѱ) ʸLu3ŨK5v8C#+5gl4ʻV :Ȭ98fY:2f3دi}맛;жw׎M6Uby!ձřiV +¦M °4MƲpws%X2jGr3pq ]r2eruuuC%O\㫫+yFaCŰCf.dҡGT\lXߔ`ucxyk }(۠L 2,Uzʎu:}Z ŌUYg>cbCҼu ukjWQ+Zf1 K.dMK/"ōASh|%ǃQch"?Н/Ӡ0swZL42upLW1C1#b]`3ř'=|}*֋:VZL2gٱё! D[Lz3]j /]] d@&q&M& <1d4-4,EӮJdP̈Neԉ?ioۻ rukk+WЬ[͎&M=3,2|:e0$LP8g\fbPu| $H3L*%S >l( +ұץc1YǴ1cP̈E)%~y{"?;uؑChUhnBulMͪ +pl13iYNô$%Myhtͨ.a VLEBCCqn-$fCd2LK^<,cؕocuL*m1C1#GV{ؑ~͌}zCڹ؆*Jɱ\X% +,LT2GX{go%|\TvI.XaaaH>t/aa@ CA" r#aivRSǴ9eUv94bF.ƾ>::* +e2LKThXjۧ7Yc/Jbw +c) Ō_4uص+ 1^:eUZD!D Ɉ0@ӆ.d%vIbcg"Df#]i1Р@Z +24,U{{aVjXV1f(f n2c{ʪ:ֆ:cFVטaB&!K=$EC;փg`6ËQ݌V"9\}*11!P#̈́eLIF I҅ٱiVX,V1f(f)ztYskCY *.E![!KMNJF1e܎"h!ӵpfK5wnRRRrrrJJJ*%M:>99 !4NeBa:6wJQ4cک'P̈=kc7]ʯyU*ul>ؖM XUEيbQ$d)$Y"2Sz q"٬(vK.i/ajgdd̛7o>e>6##=e1lQ0.22waCُI3d)4.Yh.d1_ձQ# B>ozV%mtT<1TW%ձΝip]:Ըմ,dy܎-"ΐpA.e3ZFv\lVIIIii +d> +D$úLKd\T|&xy}$fZJ0u0zl Ōm:eڪ:Jc[w47ѰlUUd%eba,}y1.e3 +vIV,+++//TCG\R~_f22L2k)ul ձRW%{զ33by"c޹#muUrxAӧN?zۻugٯ*3 Q*$A *J٤ "JA)!( $1 8$!$"P0vTarI'9{k;+cT,K@9fU2 (z=NT݂\z3t%vA.fll bb<lCIPd͝3 +ٴShXڎYaU +c͉&a1INmɘc5RǾ8f‚ݹ;exyY&ѴdE:zG\V\z3:(vA.*666...>>c$> BQ\EѴBai96dYZ[E0ָ~ԌLr3&u^;VcgϨYyB+).*ܙE˒ KIޚ`IFmG[2aC`Vvm۴kV34؏̘ZvPfñ}{KxXŲdiؖ,J,#z=Mjތe˕FIG]SSSR$/dѸF +ñQ#hVRHu'1aV%=2Z`Q̤an|W%ձTԬc]] WffVVJ6GVDfs%cVӲr86I^Y9bK/0R1X3f3icgZ:ر#Up!WZ"l.[2/ڑzȳDßteە"rrrrssw!]4`(cɨ1d]v*1ڕӧMqcF2E#XiZ3ՏMi3irYǔc_(>#ǎBe +m@Y53]lvw)X.*///??)tЀ݋NƐn|aZ*d˗cs̚1)&6VUcvcdVaQ̤窌X؉hXVUR!d\YSo;yiv r]ڮl+WrVEEEŔ=H#|EE ˨ص4. X.d,7wL'{uC'?ڥs`(f18Yr?ð%G;xd%]lE\W/:B4LQ+ ۚ@2F;]`w1+LF5嗰*ݺt~?„_c7+nnƌb&cVvi)d +CɊP#3r7#/]l%l@> nU/2ٵmi\,ǖEG-r ԱƼ2gקgݺ^;cF1f۱Z!dPS8#ϭ˱Ub,Ȫ +!I?YlZ %;jŲ%1+ߝ:6ik5|/ zfS}zx[GzSmŒ4F`L1cks$C'C;)wiD.UIBi' iB2ؚU˗Fϛ3N8W쀧z18MϘQ$DrUi1Ǭw̆L72HV Qʕ(2RbE!k2%v\(_H3w-I ە˅ekW\x?whUxX?=2mN5(f2g,`s;vISL i$vScEs7fx]\R#'+gLAHF +ȧeKOŮцuYbԱgVas&`c7?cF1IUc~} Ǥِmy0(l#A+gԔY"W=-.g~O"CFӒ  K8كY)ul9f`U +c/>͘1)cXoJI%c:f;v;q RU2[jU(JڌRp /8uT--).,T%lڰ^1kUQÇ2c ƚ6i7-zSh3AUxVrL K2dɴ(l1#VᨚʮviF9+9\{vJ!*2LKZ%4,vcI q[<-^!VeucmZYi5 +Mi3 bDZم\t"X帒Ku]v`?:-Wblt_ƺ?ʌӾ6eޔakS^otb&!?ju],X2MYzy2h?h..;Yq )BƎѮOE<guİe ӲsZDu,3ʸᘱ!cVf&# 8ޔ}ӵKN¦ j)8q䅌L.a3Z>OjŨػHl5$ OK]a؉\fU$ vn'5}1}{_un|QRaICIF,=F3yHSһh^pi{#Lvw2fV:v2?YI,c[6p:Zcjv3+KKd27b,%dlfliS&9Mgin2r`}{dݔ+c䓏cbzt7evR-cҚce Vf +뮨u-cRa @yI&hGF] +r -嘬UfVeѕKc QCwlݼqÚK}<̘6zSjS26%.cY IFcBҠUvU22αc03V0ve,9!6rА֯YkS]m[f7ڔMUgIpSbwA 9Ty&E\ZFA8veS1^Ғb"%.;n8 3vSh`7e);Re @(uLD2BȖ {ވëQcy92%ط{@u-1sڔIM٫uAet((DI'U\:J;g%WČURe#R ۹msڕK}<̘:ޖؔzZ݅e( +~"oJx/dc\bHS#vlݴqÚK|̛=ʼnٔƲMSGG7Y$^"@1D4Bީ=5{O[&(ddأSyYGScl +Xz=f3r,)u5XWSe @E2dw/D!{#scOkЌbr2LIܷg@u-ƛmJ)Q362A "d}fZ1nV:"؍Ғ+1cǏNK9wmMlJG V#2S[̦r L e⪩+͖(d{F1vr3'O8c&9 mJ[)G6ب=]-nMɔ,cju_8J\ǚ_ (nݼq1vܙc驉qQ +oJ'{qf&#B,cQe @ԉK.Qƚ)ƪ0vs 2LI܇7eڔ> r8jCӻW[(cn/H]u]-쪤+^|҅sNK>ޔm[1_%R@1}DqVW0c/Iƪ*J?sDCIxS2rR_y8M05Fel@_uW^@1M#ɥi1Q3^UҒ˘cGSbMq)'9؎k>zIb4*)j0cwc7J]xtAnV&)W-[9gTW';qf#deL[e @~O>] +(cnݼq gOr@hSeq5[ƌSe @r(c4c 0cWVyYI)O2ݔW/_pi26T})2A m6c% 1y26f(TX}&2A m9B8ưcrƚ76!W?6ڔ׈M67Y/c%S@1mGь20V[n]g7e^v摃 1غݪe2f%V:21P ic7$cuOk2?7衴(Tƶ2泀/c&1b_@1Gc5ԣM0VyB)OHOI܇XzTƼ=eP_}T&%( "/$c'MYy8-)>:"<4U,cZ(cuff mʆghSV65)Ϟ9_<x?첉RwUzAPz]Q"w* MPޛ]"U] +fݘsnW{syO^ω#c |0†1X1"Goarڧ%0P\8&3c?mAݱʌ}DЧ|E|ʩajFaŘ:˜<1R ` ,-5cO ߹9܈0vd%Lv1]J +ư㣮1+AQ>?,#St6]9X:l,M )[C`LHR2c V mp}f/O06F`ERvY۸aLO8V0aV cO06alX ciƼ)@b*fQ/%0+Ay)_16;51p1qz9 R0+V}ac L>"0Ƃhf")!II.1X1>%7t JX1_*4pIKA[; a{7a?˜?1;[ 1MJ +0W>>qcbD8ưO97;MXc F"9;ضH_cFaϬ [SR0w1V00q&1)qQRV.%E?<c4#UW dJ ؏cHO[]EYQ^VZBctqRŠA )1 +a)c)9wX^VZR|tx1sc ck)'V S.`+HI=a~+˜1) Q1NGVClEc0/+5)>*` cƮ^tdeùEz:;ضH_[CUYQ^NZBc hb{xcu5OWNKv0fmnbI`LR]Jc+xcbD~'1 t ]0vpnơ@_8,MUd$Dy cbD־2g=cXY񑼬`?/۷Xhnܰ^1A{''Ghi0V]qhANFJb́[m,M U0&,$0Vb%0.ӹG8z;ۚ^:wDYqa^VjR\Tx=cVf:8Ƥ%c/7dcc}-/()*NOI v'0fabIIa(~)q}R nj2`[:Fܻ}cc"Â|=]:ضHO[CEYQ^NZB1+AcX16;=claXUyIQ~vZrBtD>]v&:$A{<3IW.=YYzpnơ1Yic%0]Jc V HÊ1b oh{x憺ʋg%Gysܹ} %3` Z.%c^S16alXs2Rcx8jcaj]J +~` [1>.^JX1"u_c]mMjΝ:QV\w˜ cإIDHV >06ϟ=y<=9>2|PwGKc g+J +Sb"B]vXja/*t)` ܱbv)qrnf(؍֦kΝ,=Vz0.2,aǶ͖fFz*ʊbk0A>CU%Ei nƬ͍ t4Х\'#)ǘ" hY6-e؃{o t^zٓGfJ `0fjcLJBZ1>pAc'06.憺ʊe%Gyݳs+sc} U19iI1cBb V #cq cC=-ƪ+-HI9~&%uRkKI`A3+ARR17ƞNjkV{ܩeŅyIqQaA~̌5T$ĈK0ώ1X1ob=/Х|<=9>2|P_w{Kc g+J +ӓb"B]wZ[jaGǘ +nb V HW+R.ԣчol%0VYz07Ȱ@_;m45VWQVAR060+憺Kg%GG{1fnl'4x&n2=M)." "{{{ذt݃Uu`2~|)/n}+Ke^*ƘvWl?` :^1 +$1M v6Uf$Ąy9Zjk(J 3chN̥ :{ mR1G3C}]ʋӒ"C|ܝ̌ t4UE0Ƹ8XC+vKy| :h/ƈ; cK cS=k+K s2RÃ<]m,L0ԕd$E +]dc!.%1rNcbDb O[n-jkn[]^dgevkrRBxYKy8` :¾m1R,-xxvjl%9Qa.6wn_RS*0L`$1+A3Fg|) K.`ogksC]UYQ^fjBLD)Ƙ'; 1|)1cEe?[;[[y +alfrl^MEI~vzR\Th˼\ :cRRХ$1D`lj|d073%!:<@W[]YAFR EN61bNRŠA}D/xKI`lcG3C}]mcYiI!>vVfcrR"BcRg:pcba{1F7m#{0.@Ok+K s2Â|=]l,Ln_RWF#.9t)O+v :܏1Rn-/bMOv57ܭ./JMvs2}5 EY)1a!K<c0Ν$` NW*ƶ> +ɱv丨@_k;cjJW.rs1cB; Hƨ.V_?lm*+LM rs452PQ$1Bb1bرa V %cMck+񥜙noiWSQlomfl$'-.10+ءX0+Aҟ@Oæ܌ ?OWG 1ueIѫ|9X.KI`;Mge;k$&FښVe%Fx;Yݾy㚦\<cba{1F7m#Х\_YZxp?؃c9QaA.6wn_RS 1.%# a V 覃cg|) Kӹ鉑NĘ`o7'[KS1 EY)1a1NvcR` ~W*ƶ0clfrl^MEIAvzR\ThC=-5%yi +y8Xw1b1+AБtcKIA:֦̔`?/WG[K#]muI1|)w0:K +Atuv/%1cM*^=hfrtXyq~vZRldh1˜8cRg:p"V (Kcw0b@Ok+K s2RÂ<]l,LƔe$D1Ƹ9XKI`\cS'ǭwco7֖1Ʀ'FښVe&F{;Y޾y㚆%.v cNcbDO`Х@^gcc*J +rғ}=\ҿ$/-!.En6fcL AG3R"Kr`ogksC]UYQnfjBLD%1YI1c,$'bq` V *KIeck+_!L w4ޫ(NO p676TSA`Y3Gc V $WM t6Uf$Dy:Zj++H]r/叛1X1h1'66֖_zP_W[KȐowg;+3crR"BcD;M1X1#Vƶ#S=ܯ,-H tqsK(7y)1291c V rc%1F\ʍEޮ憻eEyY1!nNvo޸(+%&,0+At ƾR1oV^noyp ;=9.*4ڜ˼T1!~At$qcKIArc/MO v6Uf$Ąy9Zjk(J 3chNۥ z:cal1|)g&GՔg%E;[h*I`qq2Vb V ?ե_UyǓM6a(-df_,)cXA]pZ b~ɼ8W>@ogkc]Uyq~vZR\dhƘxYKI`\1\g3e $Fۛ+K s3RÃ\m,L th]PQ?F^ʃ1+Aۋ1bv00+3?hm}T^lgef{O%1NXcbpc_KI` _եYt)'Fښ+J +r2‚|=]l̍1ԕe$D1x8XIK07` 7co"08alrlaYQ^fjbLD჻k*J _tmc/bѯ^J +$V v5UUg'Ez[ݿ}󪚒x6;K +A uv/%1R[{Pw{3XianfJBLxƘ?Y|)Od:N1X1ͥ: S#ʋӒb#C|ܝ̌iTSA#.)t)+v$ F1|0161:\_]YZ`casG뚺y^3ccbĈ`cKHbllxa(/+-16"$PcLUQNJ\ʥ |n6R1X1^+-̫OƇzjg%F;YӾ$'-Nb]J1f1f/%ؗ/Rbruiag}]mc%9aA6c +2Bc\$<*AFoTm~$.pOGKCòĘo7';KSCݻk*I _tmc+=` K1Ft)I`x:=12TWUQRbomnwͫjRncm;vV 5^Jb(cTyPw;Ԅ`/7G[Kc*bTKy$Q]JX1bh.^ocl~Ջ'S#ʋӒ"C|<̌k#)I`pb1X1b~ϔOޮ./bMu7WWfGy:XѺ #)&$ ة1l41t)?rea9@OȐow';+SC{74UEХ<~ 31+A]ڻbx^J1|)Wf_x:=1:T_]QR`cnLbLY^FB+1|) ر;$AF{)blyq pOGKCòĘ`o7'[KSwo]PUFdI0+Aa#yc#mMuU%IqQ>.Fzo߼$/-!*x9^.v3xH|):cbb+ϔ-t) ./̽yPw{sCMeianfJBtx1YI1a~16R"Atl/ƈ:ok+3RN v6>*/JK qw23ҽ}CSMINZ\cN1+AܾK#.,P_W{s}ueiANFJ|tXk +2By8Xcb`cK8G`llxaYQ^VjblD!1UE9)q+.Q1Ƃ0bc V }^J +{`oW[S]UEIANzr\TX7+H +]c'O ;vV :{Q6×rrlaaYanfjBLDk(J cqsZ_Jzc V ?ƺ촤@g{k3#=15%yi pb1X1bh1g֧͍coWHu7WWf$Dy:XѺ +)&$c V :cĊ`l al;t)W~}TaO6IfA3/VzHォ{{UDz fgT b_[YR`cnlxe-5eyIы +r!];ƴK +AzۿxKI`1飙ѡ6Ę`o7'[KS1 EY)q!1nNv|)Od9N1X1ݥ6{ yt)gƇz:ZTd'Ex[j)KK`#c` 1/xCY[^jkj*+LI ru4smuYI1scg0N1cbG/4m} . +ɱv촤wg{+3#1MU%9iKy !AĐ1ڥK/«O'F{;[ޯ,-H tu01y 1^nc'O ;b A1>V񥜙no~P_]^dgez:rRc|<cE;R2cb .cM t U'Gz8Xci)H^p ƾr)2cbx>Q?nm-jkj*+LMrs4s EY)qt)9Ky4` b`1Fƶ޿?o,Ϳ|xvjla^MEI~vzR\dh41.t)XY1X1.%cĥ./ztnzbdc07#%!:<cL[]EAVR aLLAG` c[K163968?+-162$Jr◄ pcl~1X1a.%]JccϟM v>_[YZ`calxe-ueyI|)w1.cƥ 3)"m0G3C}]ʊRc"Bݜ,M"h*J0/i,Lbvĥ<[@OGK㽚丨@_{kscC}15%yi 1~^.R#W  }n|016=1:PWUVhkir+* +Rb"B9`b*` a.Х@^gccʋӒ"C|ܝ̌ t5U%Х[_]"065>2~meIANzr|TXkԔe$E/^8+q/;cbc3Omt) Q֖_xhfrtA]UYQ^fjBLD)1 EY)q!1nNR"A ƈ6{7WѥhiWSQlomnd$/-1E^S,'AۡK#.%euyclzbt073%!:<έWUd%D rs0cbF/4m} ."ɱȐwg;+3cJr 0Ɔ0bA 鿇0FTt)1鉑ևk+K s2Â|=]l,L o^ #)v<0V/%A{f?al1|)g&GWe&F{9Y޽}㪎8'ъ>R2cb'0406;5><~MEIAvzr\TX1Ƙ gy8KI`\1b V Zgu;7ec}]mM uUeE 1^nwn](+%&"tNGc V vcĊala_ѥ\_YpwGK㽚촤g{k3#}=]M5%9i Qa1.vcl,LA_J|) KIY]^@rnzbd07#%>:<cL[]YAFcLcc}828L @i!3b.HKPR1eRM/6iOμ}+ h0CbWc}]mMuYiI>VfFښ"W.pcR+A:1ꥤKIblmepwGKCMeiANFJ|tXΝ[Ud%ń]|a?b z^JX1DKg1ƞ?y8=12ي0VVdgij1$'-."ϋ0r_ʳLNb V :Fs)00clal]ʙɱ%9qQa.n(H +aq! '#` :b7z4165>2X[UVhkijprRaK0+Ah0CRn-jC+/NO p63Sw<1&1X13Ft)7|4٩ၞ܌ ?/WG ;*J`c&1xZ{+ P1>V𥜞jk./JK vw23PSdgAaK} Pck+sccc%9aA.6c* +bB׮\|_Jc_:cbc_}l$0Dbl|d(/351&"7ԔEѥdc!/ b{F{8飙ѡ>%qQ.Fzn++HcgEa pG/%Rbr}ei'S=c) 1~^n&crRcl$/` : v@\ʍ촤wg{+3#=mM uey Q|x8Y1b1+A]:1ꥤKIbl c٩œ ?OW };(J Kw1W.%AG$f0IثONO v+JK vw25ESSb _ʳL{)a :ͥ<[{Pw{s@_Oksc}-1IQ!1.VfR#W> `e;KcS#UeEy 1^nN޾$'%."{zc V h01t)?rma)P_@g{k3#{Z7Օe$DХz#W1+A]:bx^J1|)W_>{<;5>vVfFښj"c<,;pR~3` 0"ɱ҂ _OW c};(J _r7+9b$Ǝ0cb-ƾDF«ONO v6Ue&D{9YSEcc!/%IZADbX=m#Gucmyq]ʙɱ%qQa.zn(H +aq #é? cbבK#.<@OgkcmUYanfjBLxo*I ^`c 0+Aq`lĥX]^ 061:T_]^loefD`LY^FBT*%*ƘW0` K;1ꥤKNt4TfGy:Xܹu]UQVJLXc<} +a ؉ᅯbu{cM*𥜞E./JK vw25PSdg9Obg߆1X1O`lmeqalfrl '=9>*,XcLEAVRLڕ8XKI`\AG/x>Q?nmC{Dbl|d(/351&"7ԔEy/pxADbX=m#kˋs/>joPQbomnwO릺5>1vƘ1X1_JcR,ͣK9;5>8J +Hw%aHs,\nwF}7-??ץ}I]YAFRLX /;?~^1#^JX1:c;y) a=}tfrt a8?;-).24cLSUQNJ\DHa4'Yb V :Fs)10clal]٩ၞ܌ ?OWG [:Wԕe$D1xƈKy]c cbپ{Z[Yjk./JK vw23}e EY)BgyNa` 3}bl=q)WHM w#Ud$Gz8ؘc)KK^841_Ati^J +|8{#wʊ2Sc"ݜl-M t/i(J`%1ta ` ;KIec+K/񥜙non(NO + p67sMU%9iq1nN6#}R0` ڻC`luyaclj|da073%!&<cL]YAFRTX ;)|) q)`` 'Z}3aEc}]mMYiI>VfFo\('%..%7y)1X1n+MK s?Gk,-H tu0ֿsUKMY^F';c,̌tA _J1R-/?`o'XYQ^VjblD!ƘE1^.VcRcb ƾP1񞸔+K/1f&džۛj*J +rғ}=\͍o^$/-!r9>nN .}1ꥤKIblc{#wʊr3Sb"m-M t/(HK߶0W/%AFKIac/>?39:E`8?;=).24˜8cRdab< hh.nܳ'fƇz:Zk+K s3RÃ\m,L tƔe$D1xYKI`\A>R6?l{0jmeqclzbt8?+-162$k5Te/ + `;1v hh0e cR'/cnc%9aA.6tj)KKKy41f=1+A]ڽbxv_J1|)ז?yxozbd(/351&"ҔĘ1.VcR Z1QAt@1V^@non()NO + p67sM5%9iq1>nN-11?1X1h?'1@`lj|dn]UYanfJBLx%ueI1aA3\쬧<܌AtPg#e]Jck+/_<}tfrt8?;-)624̈y)Ǝb V :cĊmcla-K sRNt4VdGy:Xҹ,/#!1N^̌ǏrAt`\-q)ז1Ʀ'F{ښˋc#BݝL o߸vYCEQVJ좐Y^.V` V *6r}e%ɱƚ@_OksccjJΟbalgžAt`z))R`'Fz;[Ue&D{9Zj_PQ(ȿ cLЊ1ԥ 3߯1FA{G3C}c 5IqQ>fFwn^$'-.1vwb'x)a :C`luyaalvj|xn]eianFJBtxƘ .vVR#Wg0+A!g:,XU-5eyi Qc 031X1ҷc'|) K8.鉑֦Ęo7';KSC1 YI11^.VcR"a{~cb&}!1F؟c+K/_ L w77Td'Ez[߹yȅ9ٶ0xRcbo1Ft)I./l[WUVhkib}I]YAFRLX /;)b$ƾ)1X1uv.%1R[{P_WXyq~vZR\dhƘq)1Ǝb V :Fs)10clal]٩ၞ_OQy_܈͌Db4QzMP{{ޗ@Pzn(+D&6vWG<QclckXM[ʊr3Sb"ܜl-M?PSucL.%X 9cԥ$bls}pwGkS}MEI~vzR\dh2Bw[^nR1R>/%1 +125^.̽lC1VYZhcaŘ(8ىd2bRÖrzbtOˋc#Cݝ )KKb1v-%KγX Obla뭍%,&Fz:ۚj+K r2‚|=]l̍ t5Ud%ńݹ}1l)Y"Y4hbA|O,c㤡vcUeEy1nNx)IbG1vEj1`10n)Rn.-L t6Td'Ex[< #)*-%/7Ul)Yʿ8Ehsm-cK95Njoi*+LI ru0yHKCUQNJLX61Nvb)Qc8b01 +ϚˋҒb#C|ܝ̌QKKb1v-%KG0b&1>e.U"Fz;ۚj+K s2RÂ|=]l, t5Ud%ńݹ}1l)Y")b0-vc{(vϿoo'HC}(ƞ>./JMvs45~$'-."χcL,%X 81/"Z_]Zhmn()NO + p67AK #)*/%7Ul)/TGy#nk h#-1|)1frth- ef%_JuRR h#c ]IR .eS]u9~)oe|RrK+FK AcK0FI"t)Scv)YlRbmQDc94ac h4V>]WХ.%b4T䤫.O_AjbcWK.-zZj* +2`c/%v)W*FAq)?~Z}=],[KzRJᗒ]J¥D}ϥ X߼Kjť\&K)'-NLإ^q)A1/wt)Gu)MK,/#!*`efM.b;[Rbm01clKd +rs67>zXEAVRLH`?/7' #4Td# [cRN LKJ {ᄅ1uUE9)q|{9YvRSRD]JP {/eJq-s~g.vV&t)))Hw"ň.%(A&ΥCoGo$E{rs23PS<WtRbmY_oK9_ʖJRd&Dx;[k= #)*$q=-ͺ1A]ʏإ/`?uU-JKNyBi t*J cq0EGCEINA{)pG^#:ۚ+<,w+Ƶ+C^G(H +!Ÿ9XqŨ0c1As)bSb#C_xT_];Y׮F^p :H1EYI1!ľ{ii(A1/%~)Gz{ښk*<,)̻qz!xt019(+%&)Ɖ) h"V40X{KCMeY).;hcijy䐒A~l,(TK@1~US cRNbrblxZLO:ZaK0aQؚc  Zp)bSboF_zXWₜԤ^nNvVfzZj"p!vRSRA_JLb#CHgMu-JKN rw67F)Hc Wl?6>:WN^Vz򵫑.vw?a~\_aIQ!}<K(AVR.({??73+61:<jonx0VkW.=p⸁RLQVRLH`?/#9_/ bmI+ csH?bc/w4THu9ϓ6&:UeĄqؘ좣!(_ʟ(AR~ػ?Rl)XW}3%1.*+։. 73-)!&bp6vMfڱcZIlc[[MiFH V1UL؈Lྣ, Ⱦ_@p9O83=o?*2TLcIiSKD=狝}>ཥޝV/󿵬*WtPQJՊtQ.?x]Tj~C8݊kϹ~$bwtˆy7_M Z~gdY6)"*{C{wٲaز{U؋b:gT @/{hȘ݊KMJP+OX߲ 3iz6WfsE-Y0ӶbH+VZq%59!Ɗs6Eب+}Yk{GXmRQtQ bEFn  + _!*VlH/*1b7+_Ub^3]L(*6pCtVDbQa0nRaz~~-+ԨTضb[7[5۬b.jŞS*Q1ƪbW C֋-W+:T_ dשe3R/;}]aۍUŔ1F,{mUbqJ$*XɏRR1=ڭjQfpb~~2NJ*'[DT ,*FȆ ǭ?bFȍ 7*@nSA8 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*6}V*JŀEZWY$C*@jT ܨ=M#cz(O&wQUl+R.Qm*֠VLcYe x`XkzP*kbtT+ݺbťzŚM#c{`> k+VZ\`]Ɗs`֛W,1%~,NJ:8%{JKKI4ެذ.zŦy[nbٹbbub-3UETNT\T,7;3NŖpWeİؘqzf+UT,JbYEU5u -7ƌpFfR-͍ u5UEYJ.jlbpF7bk/*vBbmŬW{Xrⅳbv)[kQ ƌM4Tl򕫌;|RTbE%jƘ1B8#{7bbMjJ򕊥*;ubV._bޭVbzSdd刊UVU׊5Sǘ1C(L!bbk,ʸW,BTlV1A*1S؊Uk7nV,Vص9%e7DƘ1S8XsS؍הŪ۶ucU+ԊpAY~{ wVlZ1/%jłFD;V,XX]C^1mi#e16-b)PV0OXRBQ}ۂՊ.R+6I({ 0Tбgb.]-*VZ^YUS3f +g~q-bʺRQ̫/%Ǟ9y쐡bW^>+CBõU@2f-k S#f:(h^XxhHpP` +_o/ϙSzb ||m {1b)bYE%R1C􎙕 SQ?0=bʒ,QQ%h]ς'Y1%c*6d#EƎ>se~kԊ*v..1%-=#+'PrRjcL͘1-d&~vCFLbT*VwNNbk,9}b#:Sg$3qSUDno(]tvE@"( +J.UE:ʡ f5cyauIT?\~*$D8SQ;VWTVY]?4:61͚Ǔ~8[2a+W yPoOg[S}ueYQ^vVZR\Tx5{E>G1`=DhbFvNĴBJ}kc3q(#Huߔakj{A)Vtu45E)Њ jE(34urdE&f-,kl~78l|rMJMdlH$?Ȱ!$~Р620ffjbldX ԐRLVJ6~>JV#PS&X1Șk7s +J@GO2IWxSR!)#H\>pD;1'_u̧Ou4b%97&DbL u55N}*&) X:xFħdܸ_r^mC·xRΠIb6oߠQ!c[F",1a`o^{b?AAsC;%odDz8Zb +kAb'(Ō-l=|B"3/.[s1K)_Qޱ ȐdH$7E]7?aW'/NO2Ѡ||nyq!>Ύ6Ɣb'؊ +loa+&g! IP9mcsgwWӳnUV7vtI96))(22w$KZkto)hĨ= MՕeEyғF_qwv176>w8[1?Au*vSR/[;\r [XZQU Og,ؔưcD"qcdžq=ɚe׃̴+~n/bJU[ъ}Ql0V츌Ŷoݲgç+(RLRLJNAEMCSᒻ_pxT\b*=)3d`h_w e,쟔g$9ntK #6ǚB>jGXUE)) aA /XS +R~@?C1! e/Y9zFD_MN)(1))Qd@ŒnD"qMFW E~Ħ&A'W ';+=jtDh}sUOJbD@7lܴ߳QIy%UL-m]<|C._'eQ~Z;{0c#Oǘl(~H$ 8:<&MN0Ǟ`z:[+VVD+C}<\m-MΟUWU60 1t $Ao444ZuG !vr1 +rz|TSLP[Ier|LDHG;O@ULGG5žBA1CF13K-(5ѪKIXw߀~edl;9%d QhMƖC١;!-CCĖOݓ u):7< , Abߪ7_f<7ax)ӳʪpuV('ƶ>yvt$dރe ;]F{ ={rxpAlRӅS(?;e0`5W+_QL3"ZX\ܽ|R%e1&)#tH-Zy{t {; {NR*CnLbYiIqx(}\6VD1#PLRo`dʚO.'Q)9knIe#&Jt)2 ){5hA֐C_!`(ΰh%Dl|tD&t73S,'#%16JOr(Vx( 9_9Mŀ1F1.*fbfɳc/042&>9-+Nc+|+k){h򊆆F6;9Fa[k+XO6ީ./)JK Ζgifq1MΝM12t9zx),x6RG&+O)fSN/.1PgGGǠzyNCCaM=CaaKs3J11Rb!~,PqtŐ1Rr Q1r)Rz E1[X\M݋)ӳ0ǖͭCS3# p!lgk [!6;=T bݢ6Ņ8nE |oxࡴ'362㰇R ežbD1 +10&WǖVVmlwoo1<0 Ǯ_{{ 6S b- u%3R`Ex%QL1bK(70b&XpXdL|RZfNAQiE͝Fd_:4|oT9A[\Z^Y]Cɶwvf> -8vÝ-lmueyi67<$ATd%D<=&@RL}(Ϯ0rKiҎ\J0£cӳr * c"qOtP&'M/,> ollng*;444ZncӡkD s0lP#*ˊ rғba&s(z vfi(ƌ1Kɳ88cLc,?e^!XK{w`hxDMNGɀ啕UFCCcWV0$+៌)&d Pr)ع3*Kie÷cQRՌ54uC`!d P6gLihh2lű틋 6CMv57KM16V;_2v4spveXh~ʴ̜|X]CSkqL&A'&Yl>dF˃MCgɉq$lD.c 65s2OFST)bߨS_1K cg#w1v/08,RFcb 8&"S( lrjjj -9J?11)dCR0L"!X_[]XdXpubN3C}q(%;KIƘc.nSc1qҊ*xM-^lH62)1444ZRt(<! a&xUp'ĸ@Iw72Ŭc;ή؟\Jv^O2WPTR^Y]K_)FQ2L6<,g Fpl;~xX`H$1 /E,<$U+|vCb\/cLB>o0$<0[pknm"H2L:0h$2 r;^ +~!` 0QG[k3VSU^Z| 7; " %ANKPQO/%Gc>5oa(2_XTRVQ{%wz{3]-:T~Z[aUUde&' b?ok'~?9_:gSRj1KX 08VY]S5d@K,ϺhM4M`(X3VWS]_녫x$֠F%"FQ P!O%"ZD+iժi;{r/Rop7999>*{'S,8(KP,~R'+sUy;M2:={m\YǞAr޾{oce{߿ +m !kµY×/tw{N|uUAL+~P&Nʃ9cufl8sA2~uj"8=xC {n$e^~Ϳ[c3\^<ׯ;L [6;u$}MIbu:reɊ'e8jSZ _.sl>X[$^nn;8?WO;=K = +{h}* [!v}nfjb +I؏b5+(Vpٛ2dlhdlbW:vg= "63X̞xKMXn}xx/!=\ wwkrrbld(Dޓ[O-K2*;1V[/7Xo06ñ[w0_5 eOCX9ag[dl`cIc'd P&uC3GI2ʸ@ 0G ߰|AĶ7ŜbIƾMa,@f$`0f41W:v&E KABU,60v0X@E e gRGX'cy8hT00!,0 1؁(bKcIt2Yd"PfLkce,ϊ^& +aa:+Xž*ӳݕ2d2X̄3 c,c/ `: acRۿ_")(c{cc=fYQ+RˀI̐X+fS0cC!W#V=2UiJ㘅H2`012@,8.~ `F0KX`XN k2Xƾ9fJ+@,S3Wc,y^ `N0%1\sCKܔI*1Y (er522{A`0120 bۻ'c,Xcd*(T3(c,y8$ `*XHXaۆbs,t̃L%3)f1j/ +f 5cvyYȌdBbv1ƲW@%,aa"ysw "d2rHce%AqP 0$bTc1+=D2L,s12XQ!g3#nxKw@f%2,j/f+d"g̟cֱ8d"Rf0yc) ƇF8aְ(B<| dJZ4 @cec~ f 3,bXR,c2L)9μce,#*`a;X|cT2C1<*TajXPRKsL!3fac,n%bo n؎ V12O2KYYXScY(A31?1X fIce +Qvt%  sE,KrtQ6JC,ؖhcEAyy-leD=C,X2_b1Ʋ\ &l K2,Aec,mmB 04c,˥B˧1d5XYEt$c̯&ڰ e*lg!d1^17>#a%JFl 1X,lcl튷1^mcݖ1c1c1c1c,O!6 +endstream endobj 253 0 obj <> endobj 278 0 obj <> endobj 279 0 obj [0.0 0.0 0.0] endobj 280 0 obj <>/ProcSet[/PDF/ImageB]/XObject<>>>/Subtype/Form>>stream +q +/GS0 gs +/Perceptual ri +293.2800117 0 0 234.0000093 -41.6259766 -58.2177827 cm +/Im0 Do +Q + +endstream endobj 281 0 obj <> endobj 282 0 obj <>/Filter/FlateDecode/Height 975/Intent/Perceptual/Length 80855/Name/X/Subtype/Image/Type/XObject/Width 1222>>stream +H[qӸ\0.qK܍ "$UҪҪZV}3slh\3ic1c1c1c1c16!lUe1x3]"f*{~3؇2 +[ii2%c +K ,9吖H2B MXBЯlfMZhYdU 2*&a`` < +2-,d16)߰KFi|Rߒ1+GXR0@/+TSܬTPe1eYq1ƒ,+t5,JAV@՘aI"b%3;',v R_I%2)g,s$n21&hv5,aE|)^Pj͚5kѺ|dDsEAdt X)ÂffHa`` |Rik/oM9fֲ2n2ddAU`[a3 fXHXWЌf2922;ʜd)A6w 6XcX/iT5lz`XNns_aN8qST^'0 gL3 3B mZqlnccFkX1l&% K_:ugVt6O3h&ef%%ICVֱccr 6-0=%aGX$6^g ٳΝ;҅Tx*/fZ&WRJ s,dEg%ccQ6+0la%fGX$X _pK.]|AH^/4L5m&a@2;2=-esl^Xs󬦦2cdҨ -S$CRH3<0l/֕+W^&f+W`J67%aJKRv#,!fD/_qƟ?ntSyy:Xg™hi2GL'LNK,;qYbai[;1pa؜aak%{=$AH0+X |^y֭[o߾#MgJ>lZ9t$!۹c,1䰄c+%emr3l=z{i3~/K[>w/<O&f2JN2Y߁ޞ}zYn -t}֦{3̜_S0${DŽ z'O,b{ OPM=de,eF2\2N8n!O/K 2{XnXnUֱEc[csW%cUͳ-QüSrsgW4z3p'LFHL^gٳϟCzճg&f`R$M&ǥLpYb܁2ršczVf1^UWSaհ0=%tonf.ɃBdaY `/%x/^|ׯ䅼~g03Ŕdr]$ ;vtA,{+eұ˖.1Yfg1^UW]5Ú[Z= [v݆_Gd4nȱ0#e 80K]p͛o[_O7@ A3`eJ&L2';2,2=,wlթ}9Rc1>\c:0Ĭ$kX"@A#bwAT4AAl̖l5}=s/F/qf}~3y0las`f^}D ݺ-|ΈH a\hE`_uЪ\ +k Q5 ɊH2KT=dQ,QhX1c͙ǬfUSѰҰE0ÔD FK22:F IA(a0_"FҬ?z" A3LXSFѺ;/G,>.&% + ;>cKuΙnj\̫[1o*c8[07%0CaI'IK0%^$Ws˗\ri +jin˸eB2t2Qh[2d)I B'GֳRcjU0gaVЧdPphضrI&%F+c/Et^v:ƹ!#V" A3`&,c,a]r%efҲB2(؊K8/pY9KuL1}hc,0W0O2d`P0aI2vXyQ0 XH7;::nRnO8yFfMe,Kd}{3iYr!cckcnyVv:6TƌY1o"W7lB2l1 [jZ^`w슌%c" % +C_^Wu#ݭE8vvi 3)Q'L,@nNvVFn(XűիV,[eeV|K8SQѼa 9 [唌kޜ}ae*&:L~_}ǹ/#܃+F3`jƽLP&$úJ&!;Tt0?o(d(dVm"V1w7<+fذR12A<<{oaA!rJ%$%_P(ZXʪSϞPS[ &E~ H.άyF3(Q'R!^9{QslìtfVdžZ_o6b4lu7n!ön צdJna + +%$F "Gz783ja&-(ѺD%!+?VZR|`2kǂ6 `V.fIƾJbmŘʈƎ͓/^l06lN))v5hYyɳ#Qš/_j/ |]Ǐ O9d̨g ee;dU'*yYc9<,MmMrJWN:6X$c)TTF, [`0l:/`X`0)IaJfbJFKDI1$(aB0`/Ev1[ G> ҕQ#fdV&S&$uJ(!>}ei2;SJ7WMєɓTla،a LJ0%ٰT +:U}F' ;%; F0Ћzg(?4膟hB3C2M2Yx[ T:q䘾+Xfw7SU9^2FuL12±A.b60?2,,|40%%yZIv$JH!6п"!?F>$Nw&8e2]2d72kkxYV±RcI±P8J:6ud^`̰*uR7v2lK m1!&kdK 4$5¸ DH/ŋ_ _R~b +? ?aфfҲg41-q%@@ܙ(d<,Xp,ܵ#6ޓ<%tJK6ja0I0_/ T%ABtgѤfdzS&K$JƐ" +Ys<,vezZJb|lt4+yul꘾*'Ѫ{wSQg^VFKĆ0l07%K 0'OWE XOKZ0`\/TF~v;hcfLJ&*,K*d (dccYɉ1QrVR'˪$2cTcV111 [|ɰ! +)A 5 Ka L/t=6g H3i YN.dWQȬ?;59!N@s3Jb{/VbLE ixas [c4lò+(iI2PVI O޻R:ƻDE# +ЬLKIuo ^ڪcXIƏS=flcĘac3l +:l6L:%eH~)Kw0&voh| +,X +u,ʥϜ<~4,e[9hYӧt&Yɓ?8#>}Cd˪O_C\a [+ 24 dMɜ\:pIVAI3c&~{#g2A %L2)K4JK ,ssv5JgOܷgv6|Λëi0\}1c=aL6z$adђT%`d_®?({t3 $C O2)K ''~&kAMĤ%7le2aNf°`ݴ{`XiYyEz{E Q^??f2ILd4,+ʹcwSYV9ͱ-Ѫ9mWNv6`z0ւ2sɘR#gdC br!CavȰvHð;ȰL0 ))Cѐ”Q~q~;Mo0d",cY17D9zp?T?TB،ƏuhoL~&'!bhuCC[9tyhQòscJa5) 5#0H!/_uΐ3FZ25dlc ıʊ%E,+nߢs,c܀CU9όS<&we j>cȓS=B dn#1imckO ?ø%71Babaܰ"dXyEUuMm]=MI1PI~-Va +|)ip)L JK\bqjBcw;uHXkc3!&:vtXk'1yqMCפE0 &G:jڰ°HdXuayajc f6aD0`ti2F21HXrǪ*ːch%9v1"Ua^kWX`,d7c$c住kb&;!6tI  ; @  K㆕>,)Sf)IF;J`~ӴL)2\0Ȕ=}R_e%̱q1W"/SU%glf̥1Z ƨb1ytϨ'5Թ >}0}̰:%b2ԆӇ qµ w?V kÔ)i8ָ^HF&2o kxee rḺ뱬*BޱuJ&cv +ƺwҩFɦ'I=xM!Fcra+a{ KƆe *aO0uJf0`jwژIڱϟ}q]-J<ƫ2=;1ck/Yy+b`eKڔ1yL^Onm9I> &F-E†mVvƄaeȰjnNIfKIaf.^43@i Kط/|XFZj2 pUc۶11Ɛb1yxZS #֊#^Xbᘜ5gB%VZ O ;c؃bjXm]#^f)a0_Zk1dAFR/} +geQ>c*cػ 1v1cc]t12ZCScR1yO'u5+b$&-Xx +5a K5ڰ7oDJ$L0MLkf,2JxV9VTXVʄ+O ÌmČ0`163֙0V2&O^O'?Eb45"4L,l@M:yxC,:v䔅3f +6Ȱ0r $e1Gؗ &Ndd^Y8`Uv rކj֯-/--E1:Qe"'Gal(ra8)FIY91[i&=!Fdڢ̬ܼ +a8 " 녆a +Vdu} ͥHaH&9DQ6ΜUy~Ƕ!cELqƦXj)!ƤÊz*&bž+(?+#b2+'o¢R`X5ݰcLn #Þ0  1ø6dL2 :NcpݾS'O?|`ߞ] +X>X"1kĘ1y9Tl jJ>|'qII ĔMwtvsG5 XBRJeW..- ۰B~FMI 'K㲌s {4ސY)c*{ɪlo=~`lNRX^vf:1W'1cIc +cCć븦'y +1Uub.n^#[(dkJ+kj73 a0^l}`$2(sc*whm9zwnR0F1/wW1 dI++)eeqS7%e&C=+*SEG{9qp-Y dIYez`lu 냆=2 jD¾X06C3+9A]8z.w_8wɶcEM056$SDIaă2Ȟ$34 6 0+$ dr0&+֮߰4 {M^da&N7IpÂu&t1ȪUym'cM uJXXTxh1+ S#]D''+ AMgܔdM=cS + +b1Pi2[Ur]M[a4v c̰&aa&iA(Y98Hc޿GT奋c'iFmDc,2sqNTȗGc 1V >ډ)&bRhT&Ĵu LͭlȜE#j2+7/mu;a4d3lfSrX !,cd,s-cϟ=%1v|TʄQK09H_WK`L0&#!SLГF&6vt`M.[PLհS {7nfWLe,LGJVd%DU]:فۇ28-2C2fifb4aO^VF +3bdOjYL@,ťplػ 4&/ 2 od%*AUBzt_8G0v=ssv6POGsdLQǿć)6J|3062mdɒJ4PL6|,bSLГVS (5 12& N.~ad7 +cα?<|wW.]1+_F29;8`VFښꪀ1%'wPҧIcГv.3<}Be!@MVlBCɶN`/6 IL|'ʧ?=~O2v0v%RD̞0˝`H_WKd'/+#%d 7%>|bb`N1m]#ԓn>~a1Ⓞ6nVWga0  0aG8R1sWr`!c'iU$͟:P_Gkڤ *67%>|cSL L1}CaOz 3w~R +e6nٶcמFb]膆]ya3ͰOr f%eU{{wnzycu[kIr2$Ο9`POG02NY5nJ| (L1c3 kԓ^BãOLYHCl;͇C1yҕۧ=ce} Jث??{7cU%EV.X 1nNTxHô)zښdSASJćA((#*e + `ab jБ'x7nݾ{oh~51cT%O]1P_0V^zi b‚=ܜO05PWMIƸr>|#x ŨA)#Kb6p{83'/p X}mim'7a}Mþ/aIcªXcC-UūW.LOKN9;8`dP_G 4%`Lϓ>(&<"9)=7>)uђekJ565I ko޾#24l$gcdc75!6V-/.\859~nLY^.v6fƆz:QS*pSqĄIjZFp{ KLYjC-Xc&v֝}!F7a/Ɇac_|@aH3`W59ɊuwIQ,*қ +t{& ]HłXuIB}afM~p/x~x~Y 1~>v֗L tTNI + 8w7hJjJthbԂl)kzpxTlbJ:XUM}S3I7`!]F1|W%`["cӏNFkf%D^pqhjvFIAV +kJyaDc >P"(yw)&$Lb:FXOzE&g!$q0Ljas 06[Ɗ r3Ӓ#Bz;;Zh=}J^FR8`})9ٷocޔߠD\1<(qbAy110ŔTԵ{204"&>9-+X[{'Ic?ac*1ʲₜԤ+^n6i*+KK8~T{xPSC-Q@1뙘"i]v{2:.)-3 # 1aþ4]G{U @nXKS} `,?'#51.*,鲵9-5rRBME)עD؟Âi&BP=.&)qy`=_TZIXb1&!,bT u}[a3 "cc8cJ3Rc#Â|<].jQR!4%/hՔ_gB @Pn #DĥU5ȦX@HDLBrzv^aiEu]cV"b&!F7ssT 3l~E>Qc`l 2V]QZx򢉡ӧe$܇o!(bcm`' Sg(XT\RjfnAIyUmcN"b&=~ 1hbыa9F^8ceFsc]uEIa^VZr|LDHUowg{K U%MGєZrcV-R;Lu 뙘7 dAɳ'APjXhdLBJFv~qYemõ뭷b8b`Mf?ưe + vcUf%E_rslmaflpNKME餬8֔i6%c}iv6ΝXP +Ay >£Ҳ`O7ܼMB#&c Geu c3$ƆqZ_k*/.LM + tudjy)I1M+FcV-U % m9<",*!M ʋVvpD)SP\^U|1!$6Oߨ3@_O'XMeYQ~vFJBldhiEyir+5%U}4[Ȍ+(&pX IYFݽ¢)VTZY{ophSbsso)ba *I/{306>:|gvO筛-M5Ey 1!Wݝm,.?N)M1jJt#"FPl#Pu.GE@P*bAii0ŪaO3<:>y +"6# 14l3{wcꊒܬ`+^nNASlJ8Țr-jJt([daeɻ{DɃj`hd,bkswdDl"$aѨʥ gFsc]UyIANfjb\TXEC}ZMyfFԔБbb0Ŷqb:",*!!>~AU)zrdl x$0Ȱ4ޮjʊs2Rc#CAS8ZVWQ>)'%. +rޔpD)A1F 6oivvNn=~>$$|BRVAYUCG7ebjfnai>źo|SrHC \^=~8591624׃1V_SYZ@hJ3cДjKeQSZ4Э#*!(=ؖb\P1B$eO*j\0st2eQYUmc3>ň=KJİ\ɰ/x2q!ccC}=n4WWf%EhISrsRkJ*c 1nU݂bk11`ſ_@𨈘ZΛ\2zk;6&&bb}# 1z3 Ǩ0c)m7ʋ r2SASxP4)yvr5%jJt+WuAc"Ψi\wIHAYY| N!0`O>{1&ɇ}6yɣG]k*+HIbISMޔQSCM6n# +N{b3}X@8Ѱ{7^y6 u04e\TZh=)9܂5%2Mcl?W{D+Ƅ+w\hqcR)άT!"{JGi!J{i]i|׸kr']?> S]dmw=xs.AbN1"bCg3 N0cfg%'& {6Ñ4Fr,ڔ`Sc4zqqk+*[tŚlw;tyk7=23;9zUVUc}$#F?ĚڞF3cuuyUVAr2RMv*)Ѧԛ4kʁ){¦ǘd?lS~_eܾidڢuɢE1J[w cE+-lwę yyG=D2+'= b9 ?ƪc%E)r2SCѦrҔhSҚc?hS602nbRҲ]u(@1Ͷ\rѱHPfaAI8@ORi '"cUe%!cٙi)OD`iʩ/lJn]deMm&fL~Ꮳ[#LbW1Jgܤ3 M-Xkyv'^z=1APf`AYVbhOQ&{cj*KK^æHK~ 4ȟ)5ǚR]ה#ڔ1Ui.qq։fϙx٪ls.z +y(WP +%{%b(}ś0V\JOMz4eDHKS̞5m]x(+)7e;JSoKd-ܚ+g¢b@1'O5{΂W۰eǞG:rpxøĔ,(k޼N1b_~C (æLǚ2Д'abbДHSjij JiJi))7_-pkvcRQ1yACT`6{nzzG%$fd> J)F;cqƪ*M()Oכ8nj*hS"6%˜d`V/ʾpk(&TLh%+Vhsc/\ +{^ +(VQJROþ0V0VS]e,'+ڔ/MsU˗4DRڔc@16bfL4bH}/Ǭ T?;at}y@57mݹ@n }(irZfv^P +*k17֔L"4;)561u)MYFZ +=M).Ƅ TkcAMk6mݵ3\wGyP,(VT\Z^YUdŚ1|֒0Fm;^nMyúHSFRД"+kJq2&D0t1OedX'Hbjꚨb-]f\r=1b9/ŪkA*ֲ2X5`ДxSǚÑ{\8pM2&1֊Xcx;Ն> [b:w#* 3@ٶkًWox܆ESҳr_,*)c ʦF,?cHSB@SVUӚ2 m MiDjJ%)M) (&&\lcVbRSQ֝7tJKkm98t(q/_UTVy- 1ƐcהՕe%cCų'ڷklKr(֔1913U)0@/+F ʦE|#c<>16僰`_oДWܾe5+)M4%Xn];JkX_p¨1+)#D8SS=RcM4%1`B[tڅFvLF21n꥘!O=b.7b!| + +_kW:c1VGlRJSFܿ ҅)L=R] iJ194$예#7و(EFQT:H.E%{{(:ɚuffg71u]ggysF_f=p~$D٭;0ގ1u ӯcuv)% |T-)®$ʘdZBf8fS|z;TRVyUQ/~6SEQMeKeS>6eeEfSN;rؐ) qĘ_/oϮjl٪g/2v֐fcJX3"L"0uBvg"ed2dB!~ᘕe(2۔XciS^My7&eS1t̴>~zx{p*U!kP¤& ~q1mtB35ed&q`:+2e{6sڔϞ>7qiSZh,ܔ2x@vFjR?ƘyƔUXo~@YULkKT¸` 0ǫ-A/t=,#ʸdTҨcFޟb7ܯzRH/bJ4ݔհ)ѦޔKΝ9pQ NOM۳<*ڷX44X0"`_.GY ;;YFQ+Cɚ3dȚ2M1QϊbפX}kR_զ;ߔwMy66ڔ ̘:yؑ +sS8c":D;jYC1L% F_ /$E:fT̐2ɄJi cFf%T=yf(f&:2loiSޑ7emʭE`SΟ=Iƌ:d`nfȰ ަl\cdI YÆo#)a`2`Ҟ⦄[ZZ2m!cX$XXc)#l¦QڔU|S^pTwo߲qʥ bq<0'3-1ukض 1f+ױf7օLx'9$0dut4 s3FJ2VS YcU%bu[7 )ʛ3G۵m5+,;sZF d `,6Z1Ę)EL%666u&0Y0/ݽ6xZ&S% k 3qL٨cVC1 2 ҹ'ˎ>wMW/_`ΌƎ`P^vFZRƘ4*]9;:7cc*L1.`Q0*a 3LtM:;Y)$SCFL1Ym ,lʟxԉ%ٱhݪeϞ>u#ec}D܈1yU6.:@LF`Z`0(aR#0 <<<f 5 Ct  +F1P///oo&S$3F2&/d|Xj3PbQ1F)_7])ϟ>Y~}mްf҅sg}1e8b,WbJon].sl +@: +`(I5LMۑ.@0h`ӳg^J?-zɔd.d8-ېҰ8S Ƭ$bKMMyԉܺiK̝9mqG 2P`,ߗ3ޡ=J'.2&DNȂfK0X$40BH.___???Mn4Ќ,CP2dT8d:옙:Vȇ墳)Y/U6=)Ϟ8^r[֯^x +'~6z c|{t竒11i0>%EVt F  E0J?gIֵk2,ٰl)m:+uX}?4#0bF7X7cڔإg*+J߽cKѺUϟ3cZdlXdXhPJ)Id23/K̔0;FDNH` 0h_ڇ% Ӑ0ː2X K: +ϚYcƪQb2fnS>zxέ_u'K۽}Ƶ-?{T`lX 0[^PΞ-w*dd4CL %iooJXgF$60B#"""3Af`QѺTA&9Fւ;&JM3VP̒|Rׯ}y'ʎ>o׶֮\hS'  dQ@uLr9!e2fM8`` % I(a2a`/ 슊 DGGE!gZdIu K3+%l Ƭ&b^3ٔnwo򅳧N>wM֬\*06KN +V%c]ԎdD% j#K F C@}ccigqqb %#Bޕ-Y)F_C19mgO[7cKسskV,]8oX~nVFZrB|ߨ +Ѱ!S(5"0I0=hIj$#F$ +CP~ IIIɘ g b,$ TTߥJm3Y6*ޘٔXG߹u믮^:{v0 %FGXgwR WOe&f0a2ar `1t/+ JMMKKIW45H3,f@"AƖ%2c¬T11e[4`Sq{wn^F,/=Z_061?%_lL$ ` ꘗGWh1ȘdHv\0F=93ؒ# A#/+##33+++[8@d,f@A %2:1>b7 ؔسܻk_^xcGޱEa1`ЀI q:M (%̴%"an)%*!_WvvNNnn^^@)rssrIthfDIF !i sk$t1U@X}8#?bF1?T՝q|fnD{TEz;k +T5hb41kXc5n۝shd3rWwܻK֍kW.]8w1fl0֡2 1ӪǪc{?fܕ3d4-ك21Sm_LF U6'l0%(q_ xixGeDKI&L,K1᳚cošꌽާ+6ܻCݼ~ g;yCc۴e5!~>+yU"2+c22|Ɉ2%U߄ى!i$LF'/CBBCCpkА`,uƔ (D9ϓAFMdǤϦo)W%1qb^)I/6;ؔo^zߝ80֣2V ScAyU8!Ҭb7I8f+#ĴM3{`B00 al$CxGrIW0\Q&-0#(2'Dž,gRT+Eݟ?\3`gv)cڄبРU^+ìdǰ+mmL #e f0E#5!Ø)SA, a#)´0 xEGSlllLLt4<G +X2$CB~1 +I{OW/oJf 3XHMJ U 9rf%;FÒ!2Xƚ#!.I"l Đ;"3& tI`HLLHhYQ&$C)-] [0rLcYicʪ7+fM >wG0vʥ `81vsK +%crUsR8] K 'p++XFf|/R0D6nBd"l:&sl1_<,%dB2Ans( FfgJBED2wSa$,YMz¢b:7-/7(dd<,c49+"ǬGX7 r؟^Θ<~)MK0vY}>,+.U6!r,0ޑ0`iĊ0{I+"8¸ ~A/ظqMsccCH#K %CdHD 嬤0~͘X`flX9]1K]_R21~mJؿ;|/>ɮ;䪬,+.HM6Ь4: AƐ-P$cʦOfFhEJA Äh3 +"Y0 Btm֮=u_y{>NrC-XA^Nf:} s[Ȝd$(#fB3pf<^R4dec3h6M܌_h`.جns<8$0_%$lePphx5z KNIKF C`쪨2ߕ )ɤ̌4U8,1Y9mc*G(^~I{nЌ9hK1' +^.3d~*KmL\o_~RddS5&?n8#h׸3s1w:aV0I_) `_{WUUuuMMmm>f?#'TW3e)c'C%dY,d1gbV{}iS&r* 2Ř R̙1)6hN|tHGۇ͍uXz+L7/UȼqG%ʦL< M$h*%)1ӕ_LoAX8 !a6Ed~! C `h^ԫӤ"ƆFHHJ&m.V RûBW/QulƴeUo*O~0cXH,ŜMO/sgO|ı-MYmYc_#BP d u@lh6k&3.;Aꨵ1'ؒSa00[ZZ>dZ9ᦹ3PIJl%ۤa/꘾*|c$+?70fmJsswp>c cXX:2c1UȰ,T2HF`1CMyLLJAa$lCrJZFfvPL5_ī0n/ 0ed +ݻ鎩Rձgl|NKd ^lbʹn3M8ƾo1K1#uϮ]r򬹎cD!㲌ƴJFH,[͖.- ./ FǮ[`ݨVc箲=ڐ$aR”`L]===#EO9fhfJ2 z)d2,ߕlK:V<YӧL?w`5Gƞ԰Oh=&Yb)[]fJsYXA^n6 Y,6fm% 'e ,0 4-<* ~)"E0DۆdMU J/u3gΜ߳=9ed Ӳ<]pLUTY$u,"4x%V"Ϛ>U{ӑ cO>36dU\.bA~U:vZcqlKqQ +Yvf@iI( %fAA|BP%qG&g۾t=$v"Lv!$_Wo9伤OM/I#fX(ه-(dJ-Ŝiɶ1Qڪ&cgw{Q1ŘkRaȠs*/~҇:vJ}V3+ٶE2.4LKV2,:luddDDx8~ `vX +MUo8Ha礀/W$WUnPF3XUrJձ̴ jU\7`aC6R2fd;w̩J8֮9ނ?dsdi) ̖wbbM e(o! u[Z;vF:+&|OkL,eJ2@G43kP3Ui0(ac j' c+Zc)䁌`훲*:&xrL-5U,d{~}EUuq8kXbK${Anl((JQiE)^A@E@m&vlX ,|߷f%}7@,48%)d5~IQ#x !(F ~1 + ŰpYHe$K2Xs j&Ȱ!pU\d93cCcc _/c*V(Yݔfs9JJbWd/1p1J<E:fMKINB2 +!B2lF ^F? ;Zzz(p&v ;# WLpݣЉFd2YpXcYYmUjRblX[`)0ZU|\)2b{#c7 +]|gұ̌t+ˤĄx e$T22 1߼Y ul%6:*Ve`&_dl!cM֯^JJ+)#tV}mV^,wC $&YYک \^8`B4>$ayDؙFъd_®9#H26 Kr |gu̚23nʘ72֥c6Z4kҰ^7)?^3XYCŎ1d̶Yy쯓yXȎdqRUɀ2 14BLrL1?*Yi-ddXʰ̠g, + s<fG,"ZiQ S ^3)w꘨c9aMm|V/_pS&9{@ߞ:oۺe&ꦬ^ ʘ)+b{Kkޢ2deXP3 Aӂg&/`B0*aڐi@S{SB4t:v%؉ܜYT6ZdY'3b}ztԮM)]iS~Xy9QL4JY)cEW2d(t2 -@3Lc|Q#`X€=f=cCR%LW( Tc31*OS +-`U˖|7wIF2_]:l*2\1s3&܅cZ!#`ZjѼ3 8;O;ROKL.e:v*c~֮\xS'ullSVMY_241s0nV2ldd8/ePΒg9$`B0(a@m;žf#*׻wde98UyddqXltT؎@kV~hS&9l>=MRP*1SS11{{g/KT2 )fz ^^H!;w+2&I0=`c#cUYpʥ =05+.7kG ԿwmSzծ+cʙe b*))1Y$d\2Z@Yf4%tub~1`T4!ahKI?{tÊu=c؞]۷nY|wsgM4n!l/6kfsƘ9tXc `$ce3%] +~ `ThG[/)%N/AwLcE +c91K̞]!۷ljsfL8v0o)ts5jeOf+1s[cė%MKd(,#3}4`EL0žs^V`))I⫲c ;_<L3Sm\vQDhTEq_qAqCEEPAAED}G (*qkBs{Јz{7mজhmafw ѦXOq#)5D=j똤c'2, X5s~A`%썐0>^@1ce%yI q1g##BoJ[) F׎2$ Q죏1yǤ!c$!f3 + E&& /IY&vSX1b,B̙G|tߺ n93M473lJTƴ@+)cǟ$똄cL!@~X2LeLƿ_,``L |ޔ+M9}c G :d0,c}2(Ŕ:F;Fޑc\ȘJ$ÔA(ҢAQo#``C-Ɏ/ Z".]<u2X`~vS.;v)]ƾ#,c"eL!)"߽cĐJ%c(Aca`i`pEbDb {+"L_r c81>c5UE9i qFFR{-ׯqXf`Ό-@1Lu!eL!)$j KN#ÕZeH&LZ# 50#C+0A "L^0d\8u .cD]RU^Rp!̩\4o VL xe/z1rCSJ$~R c$(XFaF  X00 !cc^cO9*K +3RcOM7MNkW/^0gI֖f&e2F&"CSN]xђq(Caи_~Qт#aL0\Ǹmޝ[7t 7+=ؔQhS۵nJPϞ>ex~.cIӄٟ +8af4g78Q%WI#LP=ciƮV_(-LCڔ^]]68Zd\q{~._>!)*t ZFkƊ >!LQBp1ֈ~ +mT)ztʘ2;eʘ*c2#eL!),p' Z0ÜC+)a$g1uS؃wol~JeYI!ޔ`S2m3[l$X/PȤԀyǤ c$PFc ~~Knua⻸qV%8abehSxP~Pƶn*cAKtF&CS`2@2DL&CX Sa;Lnc chS_(-2%bltT(c~>v2,,cCvn-R4(D1EFcb8aX$S]&Z|ƚ#Ц,/)JKN9s*<*c{@s1SѨ XOPXp#),D1Fb~ !KXj&7u +auXk˳'͍Ѧl +6eiQ~NfjR|la2uY[tywPƀb]ɤTnbchhʰe\$co޼~lʚ+U堌e˘#(c ̘:b7te LdR*CB^nJTn2VX]ƎaJ{O`en:faC&%UȤT|b _Ē3?sTIM6e㣇2v[ƎzܶyK2f1`$:hR&R!iVcvØ`S2FmJPe,УGi2yl'XBRW[LJQL"L))Ake n;npإ3N?kfgU/3cLF'ȤԌ42t3JbM {2 XltTDhCxoݸ~͊Ф4369OʯȤԄ46 R?0dW@\QZXر@};=\6]io7)MƌA&F(Q R2Ɣ砌5Se.(cר2V\x16:2<$8wnm[׭^d!cAդLJ(Q4`cԦdXa^Vzr…sO=w`vMNk.7v!zI NJrB4X`Se jTd2vlAwpۼqbΤzRLJ%(IEi|H07gݻsܬ計Çt߲qKΥ'Ĥ)FʘBdŋ2>SƊ3R.Ŝ9v,gNWऴ!RB#QDԔ1jR2V[]U^R{62<$({mW/^ЎIG2)""ڔ2&n\(/+=9¹'C9t`֍ᤜ &2"[͖7,+ϡ'c>LIمLJ(Fȗ֖ݹPXyIanfZR|ltTxH0BnJT PƮTIMO05W 1J*E~]Q "BR\r-3DQTPr19rְf-k~gg?{?{v1{k$%Rx:{JwܾurEiIQɣ9]%%e1HJ 錽-PR@IYN'~X$)$@ 3F[9cmpR򀗔jQRr4NRZI$$%r8)c'e )3eIAPRVrCIII,`1 $|l$eqi:)7oL$eJJ&LRQ$@{?c޽I'FqI$L()mdIJ8cDBrRnkEgLu2X椄3F +`1$Dbt&"$%1RI&{RIi* +tR$%hLD!j߄1W̓1)* gDbQt3)ϞJhb1)# @]&&)KqR$e\B*)|<]qRRNJA")R$)W,_(I bY$)2%eATR:rHR$ +@R7) +NIJnNvtRji +%%1!-)_Mʃ\2R()MPRj:cX J4),'HJ S|Ƙ3F&`10>()FҋNJctDgLi1!5)uKpRPI0`ᤄ3F`14$'e?)&AS|<]l,PgXLѣ$eDXh0V8)5G,?c# @7)2:2|VH`xk S#tՆTVRr@cr +X IIOnRIpޜqR9Z3f1И|ClR"u%E'RI>eՊe"Ohj`'[3֧Zl񢈹BMΘxk)gL)Ac +X &)3IIY 'ePR^\YVrٕ)}ݚ ͙4ʌwԄϘ`1D'SVRT_<}۷dMnYlTDXh0:cܹgLeƈ,IyҒGܰn% gs(u EM$Ԕ_M _btEg+ܿwӒb=c#giʯ3gb.>)G'%:c[f]M'ؚ>eK#Θ}pS*oʾxLD"d1l%eswnߺ^{>c{vmۜBgL_WKS>c)M bIwoqRRg 'eKc=7j.]<ԉ#eؚ>e:cXg̞wtFigߔƾiOcPrX IwƚV{уymJO]X s<\Xd7l1i `1LX{NN=hnDIׯ^*m=c^n-LhiR5"@&bW~R>uj+Jg,wbyg1):XiL@&1AR673v:cΉhOrwv@gt!)U))ʤ1,lI~F]MBKg,*",4$05&ՔCTYxLMJZc茵gg],>c[0oS'Mpwqo4%HcksM,BXs}1gl>cI36wVH?/7g{)GQM9t}|d>@*"I;1dvkAgRg mDgletBM7&!ƨ34W1 T.(`1T8goPRrXmޘزŋ"g?5ՔFz:Z)TUјF`yR] g۰nMbҘPSxxhQHc 55OFc;T|lu0`1X>c{Fgu֮Z|I4jʙӧMt6Gci1)pX NR2guϞ>~Hg>c9;6M9jJG;[+s#C=]mMuHcyQIUe~BGDsug+@,I;{;vh۷dOY2jP)ܜXja}hL1*Ⱥ.e{>cwOmi}=ݜY[#՘PUXLe[/@.g7{?cXEiIљ>/{ $&DM9} NHcc F3S%Pd7W/YhIJ)gJUO=G) + ?q14T%,׊d.tWX ᤤ[3xZmuEYɹ3ٙ)=59nʰ?/wJc\ RRTW%c-(=tWﮑb&ug 5eKSwygRiqQٯ*< /cs," PL( + +&,$sB,9+0iu +3kDtuag?t 8E|o}NW_}_M>i\hpА_oϾ{tD9ɌYլQ*0&R)(ūrșyɊ0B1K_E}~/aS>ynn6 N8/l5+覜:1,$xA<݀McuLrLU +S4a*VZf/PLĒSP{3\ne^rt)SL?;.*bʄG?pe̙cUիªJcE?LKo2EGb2/cOQM6HarѼY#&3zİ@X];+VJ6+c|!S/]:r9ɾDŽb"2A.cO޿{lSlSOZt¹3c"'3j@?p!5Wv-*+#جT8VGES+x)l*^ȘjہL(&bY~+\?w;&ޔgҏ>oέ׬H\`ΌȩDž +_X&cuk[դc +s,FZ3m +jvrb"e,kRG2Kޔwlٰn㢧M4$Wfm떔UY1 +Y U`Qk?XvtGEÛ2mCSvm߼~e ͊2!,$xAJc6 UIu ꩧM8J"*t$3 YQ#)ci{ӓGxSf<~Hھ;mJNZlyb"&O2c̥cmc͛XU1.d\4*NҘKeI/s1G{ )snyЁ;l\zEsfLGҩ};VN-ȪDutWBVJkF n) M e oL)O8?e֮^`ΌI12*zvԡsk*YCA"9!$^Im4RUVJ9KYҜL2ȌPLW>ASo )ӏI۷w׶׮Z?g,{[n]:wJR5_9g%ޕxXbdɤy F⥠QUȠ184 3-dƚB1eLڔMym,)c۳sۦI%,?{F̘bwn]]:oV%c0+kìBVYL 74 +P?T 4++J\(dR!sX~Lڔa޳MCNέW/]8wRܺ)YXa˳o^]]تDuJ.d0,2N2ڎ|fHSI3RXVbؖ*13ܦ2'owo̸~N=t uV.[144g>zUJ$YA!F +H&#h..Ue*Zw 4bDdBfƱvE(&bh1My77;+eX +fl e,&2|Ęw~ntU:fJ1\ȠɒѩWFQK@Uf`Q&W2 _ȴ3H M#elSRʺq?qԉ#ic[M 5bA<ҩcdVRcFF%O=Tk Wu:!4fYE#QȸBF䘑PL*c|6K)ɹy*0~3]blΌ?/Ͼ}z:g}s1RddU"b9D1vpՄԢR?gԲʬrNKZaruL(&bh1MI{;f.0vqDM8nÇ޻'clC}̦18&AF%FABϸ%٪ |GIcчydԅ̜cEїF(&b7|6'Ʈ\pI`l/c,!15  8gc0+[$5EBF: +\\bx1z4 c&=K2E!r R(&bh1D=} e̸~"0vH>sƏ !ձ~{@u9h9f CJ&dI'ɨPJ#n iX32d]2ȔLvq8uL(&bߔyqეUˁYqё'ª uJX+p +Mc duv53MZ]vQX֐,68'հfe6lq%c YY"}Ib"ަČMgO=XfψAW%c}Q&; kjK>-GuQL..b5ز4ő>Ꭸ5^p'#@ +Y, D M#lʼ7_EbV֍k/? OٽccxU _/O<+uŎsn6(03ԫ] vQ@f(v,i7\@3jdhZVD c9:f DY1M-f9e,cclK,?gflqcF:?Jc:o idB^{\QCwYKEZCpQl˒ddhZBVKcuU%26%ثOOیs +֬\`hXPF89ťS1Ț(=SZ%]D. Ғ `F^UA4jd,ar@uL(&bnJXG"2cǁ=;mް1FVelԴPBG Cǫ?vgw׮.hXJaZPH;j=Shj Y8Kp^:;de1`VPƄb"gM }}{xg,1v 1ecrҪxUEGFL4>,tȠaC}c+z°$ڑæ4mFd j4m:2LgI4i5uńU **@dMDDqC4cbM5&im?4i9Us}sgoyGǿ##dF#}rtdѠ\d}d~5.d<,_yE89f43b?)>O3mJb솖1Gc-77_[[]YVZL2k9 3b"BCرprX2l,G gی..a(d''F e`$dCqXwvL;+[Ǟ5MOC1#v'1_f3vْ}{Z[nn_ZJc)Ictv,4ч% +% ͒Q'N=B$"weS cVk|uv&Ϡ[dz̎QuL/< cbF(V6/)gN;I{۞];l[SC؂dp,M0Ѱ) ʸLu3ŨK5v8C#+5gl4ʻV :Ȭ98fY:2f3دi}맛;жw׎M6Uby!ձřiV +¦M °4MƲpws%X2jGr3pq ]r2eruuuC%O\㫫+yFaCŰCf.dҡGT\lXߔ`ucxyk }(۠L 2,Uzʎu:}Z ŌUYg>cbCҼu ukjWQ+Zf1 K.dMK/"ōASh|%ǃQch"?Н/Ӡ0swZL42upLW1C1#b]`3ř'=|}*֋:VZL2gٱё! D[Lz3]j /]] d@&q&M& <1d4-4,EӮJdP̈Neԉ?ioۻ rukk+WЬ[͎&M=3,2|:e0$LP8g\fbPu| $H3L*%S >l( +ұץc1YǴ1cP̈E)%~y{"?;uؑChUhnBulMͪ +pl13iYNô$%Myhtͨ.a VLEBCCqn-$fCd2LK^<,cؕocuL*m1C1#GV{ؑ~͌}zCڹ؆*Jɱ\X% +,LT2GX{go%|\TvI.XaaaH>t/aa@ CA" r#aivRSǴ9eUv94bF.ƾ>::* +e2LKThXjۧ7Yc/Jbw +c) Ō_4uص+ 1^:eUZD!D Ɉ0@ӆ.d%vIbcg"Df#]i1Р@Z +24,U{{aVjXV1f(f n2c{ʪ:ֆ:cFVטaB&!K=$EC;փg`6ËQ݌V"9\}*11!P#̈́eLIF I҅ٱiVX,V1f(f)ztYskCY *.E![!KMNJF1e܎"h!ӵpfK5wnRRRrrrJJJ*%M:>99 !4NeBa:6wJQ4cک'P̈=kc7]ʯyU*ul>ؖM XUEيbQ$d)$Y"2Sz q"٬(vK.i/ajgdd̛7o>e>6##=e1lQ0.22waCُI3d)4.Yh.d1_ձQ# B>ozV%mtT<1TW%ձΝip]:Ըմ,dy܎-"ΐpA.e3ZFv\lVIIIii +d> +D$úLKd\T|&xy}$fZJ0u0zl Ōm:eڪ:Jc[w47ѰlUUd%eba,}y1.e3 +vIV,+++//TCG\R~_f22L2k)ul ձRW%{զ33by"c޹#muUrxAӧN?zۻugٯ*3 Q*$A *J٤ "JA)!( $1 8$!$"P0vTarI'9{k;+cT,K@9fU2 (z=NT݂\z3t%vA.fll bb<lCIPd͝3 +ٴShXڎYaU +c͉&a1INmɘc5RǾ8f‚ݹ;exyY&ѴdE:zG\V\z3:(vA.*666...>>c$> BQ\EѴBai96dYZ[E0ָ~ԌLr3&u^;VcgϨYyB+).*ܙE˒ KIޚ`IFmG[2aC`Vvm۴kV34؏̘ZvPfñ}{KxXŲdiؖ,J,#z=Mjތe˕FIG]SSSR$/dѸF +ñQ#hVRHu'1aV%=2Z`Q̤an|W%ձTԬc]] WffVVJ6GVDfs%cVӲr86I^Y9bK/0R1X3f3icgZ:ر#Up!WZ"l.[2/ڑzȳDßteە"rrrrssw!]4`(cɨ1d]v*1ڕӧMqcF2E#XiZ3ՏMi3irYǔc_(>#ǎBe +m@Y53]lvw)X.*///??)tЀ݋NƐn|aZ*d˗cs̚1)&6VUcvcdVaQ̤窌X؉hXVUR!d\YSo;yiv r]ڮl+WrVEEEŔ=H#|EE ˨ص4. X.d,7wL'{uC'?ڥs`(f18Yr?ð%G;xd%]lE\W/:B4LQ+ ۚ@2F;]`w1+LF5嗰*ݺt~?„_c7+nnƌb&cVvi)d +CɊP#3r7#/]l%l@> nU/2ٵmi\,ǖEG-r ԱƼ2gקgݺ^;cF1f۱Z!dPS8#ϭ˱Ub,Ȫ +!I?YlZ %;jŲ%1+ߝ:6ik5|/ zfS}zx[GzSmŒ4F`L1cks$C'C;)wiD.UIBi' iB2ؚU˗Fϛ3N8W쀧z18MϘQ$DrUi1Ǭw̆L72HV Qʕ(2RbE!k2%v\(_H3w-I ە˅ekW\x?whUxX?=2mN5(f2g,`s;vISL i$vScEs7fx]\R#'+gLAHF +ȧeKOŮцuYbԱgVas&`c7?cF1IUc~} Ǥِmy0(l#A+gԔY"W=-.g~O"CFӒ  K8كY)ul9f`U +c/>͘1)cXoJI%c:f;v;q RU2[jU(JڌRp /8uT--).,T%lڰ^1kUQÇ2c ƚ6i7-zSh3AUxVrL K2dɴ(l1#VᨚʮviF9+9\{vJ!*2LKZ%4,vcI q[<-^!VeucmZYi5 +Mi3 bDZم\t"X帒Ku]v`?:-Wblt_ƺ?ʌӾ6eޔakS^otb&!?ju],X2MYzy2h?h..;Yq )BƎѮOE<guİe ӲsZDu,3ʸᘱ!cVf&# 8ޔ}ӵKN¦ j)8q䅌L.a3Z>OjŨػHl5$ OK]a؉\fU$ vn'5}1}{_un|QRaICIF,=F3yHSһh^pi{#Lvw2fV:v2?YI,c[6p:Zcjv3+KKd27b,%dlfliS&9Mgin2r`}{dݔ+c䓏cbzt7evR-cҚce Vf +뮨u-cRa @yI&hGF] +r -嘬UfVeѕKc QCwlݼqÚK}<̘6zSjS26%.cY IFcBҠUvU22αc03V0ve,9!6rА֯YkS]m[f7ڔMUgIpSbwA 9Ty&E\ZFA8veS1^Ғb"%.;n8 3vSh`7e);Re @(uLD2BȖ {ވëQcy92%ط{@u-1sڔIM٫uAet((DI'U\:J;g%WČURe#R ۹msڕK}<̘:ޖؔzZ݅e( +~"oJx/dc\bHS#vlݴqÚK|̛=ʼnٔƲMSGG7Y$^"@1D4Bީ=5{O[&(ddأSyYGScl +Xz=f3r,)u5XWSe @E2dw/D!{#scOkЌbr2LIܷg@u-ƛmJ)Q362A "d}fZ1nV:"؍Ғ+1cǏNK9wmMlJG V#2S[̦r L e⪩+͖(d{F1vr3'O8c&9 mJ[)G6ب=]-nMɔ,cju_8J\ǚ_ (nݼq1vܙc驉qQ +oJ'{qf&#B,cQe @ԉK.Qƚ)ƪ0vs 2LI܇7eڔ> r8jCӻW[(cn/H]u]-쪤+^|҅sNK>ޔm[1_%R@1}DqVW0c/Iƪ*J?sDCIxS2rR_y8M05Fel@_uW^@1M#ɥi1Q3^UҒ˘cGSbMq)'9؎k>zIb4*)j0cwc7J]xtAnV&)W-[9gTW';qf#deL[e @~O>] +(cnݼq gOr@hSeq5[ƌSe @r(c4c 0cWVyYI)O2ݔW/_pi26T})2A m6c% 1y26f(TX}&2A m9B8ưcrƚ76!W?6ڔ׈M67Y/c%S@1mGь20V[n]g7e^v摃 1غݪe2f%V:21P ic7$cuOk2?7衴(Tƶ2泀/c&1b_@1Gc5ԣM0VyB)OHOI܇XzTƼ=eP_}T&%( "/$c'MYy8-)>:"<4U,cZ(cuff mʆghSV65)Ϟ9_<x?첉RwUzAPz]Q"w* MPޛ]"U] +fݘsnW{syO^ω#c |0†1X1"Goarڧ%0P\8&3c?mAݱʌ}DЧ|E|ʩajFaŘ:˜<1R ` ,-5cO ߹9܈0vd%Lv1]J +ư㣮1+AQ>?,#St6]9X:l,M )[C`LHR2c V mp}f/O06F`ERvY۸aLO8V0aV cO06alX ciƼ)@b*fQ/%0+Ay)_16;51p1qz9 R0+V}ac L>"0Ƃhf")!II.1X1>%7t JX1_*4pIKA[; a{7a?˜?1;[ 1MJ +0W>>qcbD8ưO97;MXc F"9;ضH_cFaϬ [SR0w1V00q&1)qQRV.%E?<c4#UW dJ ؏cHO[]EYQ^VZBctqRŠA )1 +a)c)9wX^VZR|tx1sc ck)'V S.`+HI=a~+˜1) Q1NGVClEc0/+5)>*` cƮ^tdeùEz:;ضH_[CUYQ^NZBc hb{xcu5OWNKv0fmnbI`LR]Jc+xcbD~'1 t ]0vpnơ@_8,MUd$Dy cbD־2g=cXY񑼬`?/۷Xhnܰ^1A{''Ghi0V]qhANFJb́[m,M U0&,$0Vb%0.ӹG8z;ۚ^:wDYqa^VjR\Tx=cVf:8Ƥ%c/7dcc}-/()*NOI v'0fabIIa(~)q}R nj2`[:Fܻ}cc"Â|=]:ضHO[CEYQ^NZB1+AcX16;=claXUyIQ~vZrBtD>]v&:$A{<3IW.=YYzpnơ1Yic%0]Jc V HÊ1b oh{x憺ʋg%Gysܹ} %3` Z.%c^S16alXs2Rcx8jcaj]J +~` [1>.^JX1"u_c]mMjΝ:QV\w˜ cإIDHV >06ϟ=y<=9>2|PwGKc g+J +Sb"B]vXja/*t)` ܱbv)qrnf(؍֦kΝ,=Vz0.2,aǶ͖fFz*ʊbk0A>CU%Ei nƬ͍ t4Х\'#)ǘ" hY6-e؃{o t^zٓGfJ `0fjcLJBZ1>pAc'06.憺ʊe%Gyݳs+sc} U19iI1cBb V #cq cC=-ƪ+-HI9~&%uRkKI`A3+ARR17ƞNjkV{ܩeŅyIqQaA~̌5T$ĈK0ώ1X1ob=/Х|<=9>2|P_w{Kc g+J +ӓb"B]wZ[jaGǘ +nb V HW+R.ԣчol%0VYz07Ȱ@_;m45VWQVAR060+憺Kg%GG{1fnl'4x&n2=M)." "{{{ذt݃Uu`2~|)/n}+Ke^*ƘvWl?` :^1 +$1M v6Uf$Ąy9Zjk(J 3chN̥ :{ mR1G3C}]ʋӒ"C|ܝ̌ t4UE0Ƹ8XC+vKy| :h/ƈ; cK cS=k+K s2RÃ<]m,L0ԕd$E +]dc!.%1rNcbDb O[n-jkn[]^dgevkrRBxYKy8` :¾m1R,-xxvjl%9Qa.6wn_RS*0L`$1+A3Fg|) K.`ogksC]UYQ^fjBLD)Ƙ'; 1|)1cEe?[;[[y +alfrl^MEI~vzR\Th˼\ :cRRХ$1D`lj|d073%!:<@W[]YAFR EN61bNRŠA}D/xKI`lcG3C}]mcYiI!>vVfcrR"BcRg:pcba{1F7m#{0.@Ok+K s2Â|=]l,Ln_RWF#.9t)O+v :܏1Rn-/bMOv57ܭ./JMvs2}5 EY)1a!K<c0Ν$` NW*ƶ> +ɱv丨@_k;cjJW.rs1cB; Hƨ.V_?lm*+LM rs452PQ$1Bb1bرa V %cMck+񥜙noiWSQlomfl$'-.10+ءX0+Aҟ@Oæ܌ ?OWG 1ueIѫ|9X.KI`;Mge;k$&FښVe%Fx;Yݾy㚦\<cba{1F7m#Х\_YZxp?؃c9QaA.6wn_RS 1.%# a V 覃cg|) Kӹ鉑NĘ`o7'[KS1 EY)1a1NvcR` ~W*ƶ0clfrl^MEIAvzR\ThC=-5%yi +y8Xw1b1+AБtcKIA:֦̔`?/WG[K#]muI1|)w0:K +Atuv/%1cM*^=hfrtXyq~vZRldh1˜8cRg:p"V (Kcw0b@Ok+K s2RÂ<]l,LƔe$D1Ƹ9XKI`\cS'ǭwco7֖1Ʀ'FښVe&F{;Y޾y㚆%.v cNcbDO`Х@^gcc*J +rғ}=\ҿ$/-!.En6fcL AG3R"Kr`ogksC]UYQnfjBLD%1YI1c,$'bq` V *KIeck+_!L w4ޫ(NO p676TSA`Y3Gc V $WM t6Uf$Dy:Zj++H]r/叛1X1h1'66֖_zP_W[KȐowg;+3crR"BcD;M1X1#Vƶ#S=ܯ,-H tqsK(7y)1291c V rc%1F\ʍEޮ憻eEyY1!nNvo޸(+%&,0+At ƾR1oV^noyp ;=9.*4ڜ˼T1!~At$qcKIArc/MO v6Uf$Ąy9Zjk(J 3chNۥ z:cal1|)g&GՔg%E;[h*I`qq2Vb V ?ե_UyǓM6a(-df_,)cXA]pZ b~ɼ8W>@ogkc]Uyq~vZR\dhƘxYKI`\1\g3e $Fۛ+K s3RÃ\m,L th]PQ?F^ʃ1+Aۋ1bv00+3?hm}T^lgef{O%1NXcbpc_KI` _եYt)'Fښ+J +r2‚|=]l̍1ԕe$D1x8XIK07` 7co"08alrlaYQ^fjbLD჻k*J _tmc/bѯ^J +$V v5UUg'Ez[ݿ}󪚒x6;K +A uv/%1R[{Pw{3XianfJBLxƘ?Y|)Od:N1X1ͥ: S#ʋӒb#C|ܝ̌iTSA#.)t)+v$ F1|0161:\_]YZ`casG뚺y^3ccbĈ`cKHbllxa(/+-16"$PcLUQNJ\ʥ |n6R1X1^+-̫OƇzjg%F;YӾ$'-Nb]J1f1f/%ؗ/Rbruiag}]mc%9aA6c +2Bc\$<*AFoTm~$.pOGKCòĘo7';KSCݻk*I _tmc+=` K1Ft)I`x:=12TWUQRbomnwͫjRncm;vV 5^Jb(cTyPw;Ԅ`/7G[Kc*bTKy$Q]JX1bh.^ocl~Ջ'S#ʋӒ"C|<̌k#)I`pb1X1b~ϔOޮ./bMu7WWfGy:XѺ #)&$ ة1l41t)?rea9@OȐow';+SC{74UEХ<~ 31+A]ڻbx^J1|)Wf_x:=1:T_]QR`cnLbLY^FB+1|) ر;$AF{)blyq pOGKCòĘ`o7'[KSwo]PUFdI0+Aa#yc#mMuU%IqQ>.Fzo߼$/-!*x9^.v3xH|):cbb+ϔ-t) ./̽yPw{sCMeianfJBtx1YI1a~16R"Atl/ƈ:ok+3RN v6>*/JK qw23ҽ}CSMINZ\cN1+AܾK#.,P_W{s}ueiANFJ|tXk +2By8Xcb`cK8G`llxaYQ^VjblD!1UE9)q+.Q1Ƃ0bc V }^J +{`oW[S]UEIANzr\TX7+H +]c'O ;vV :{Q6×rrlaaYanfjBLDk(J cqsZ_Jzc V ?ƺ촤@g{k3#=15%yi pb1X1bh1g֧͍coWHu7WWf$Dy:XѺ +)&$c V :cĊ`l al;t)W~}TaO6IfA3/VzHォ{{UDz fgT b_[YR`cnlxe-5eyIы +r!];ƴK +AzۿxKI`1飙ѡ6Ę`o7'[KS1 EY)q!1nNv|)Od9N1X1ݥ6{ yt)gƇz:ZTd'Ex[j)KK`#c` 1/xCY[^jkj*+LI ru4smuYI1scg0N1cbG/4m} . +ɱv촤wg{+3#1MU%9iKy !AĐ1ڥK/«O'F{;[ޯ,-H tu01y 1^nc'O ;b A1>V񥜙no~P_]^dgez:rRc|<cE;R2cb .cM t U'Gz8Xci)H^p ƾr)2cbx>Q?nm-jkj*+LMrs4s EY)qt)9Ky4` b`1Fƶ޿?o,Ϳ|xvjla^MEI~vzR\dh41.t)XY1X1.%cĥ./ztnzbdc07#%!:<cL[]EAVR aLLAG` c[K163968?+-162$Jr◄ pcl~1X1a.%]JccϟM v>_[YZ`calxe-ueyI|)w1.cƥ 3)"m0G3C}]ʊRc"Bݜ,M"h*J0/i,Lbvĥ<[@OGK㽚丨@_{kscC}15%yi 1~^.R#W  }n|016=1:PWUVhkir+* +Rb"B9`b*` a.Х@^gccʋӒ"C|ܝ̌ t5U%Х[_]"065>2~meIANzr|TXkԔe$E/^8+q/;cbc3Omt) Q֖_xhfrtA]UYQ^fjBLD)1 EY)q!1nNR"A ƈ6{7WѥhiWSQlomnd$/-1E^S,'AۡK#.%euyclzbt073%!:<έWUd%D rs0cbF/4m} ."ɱȐwg;+3cJr 0Ɔ0bA 鿇0FTt)1鉑ևk+K s2Â|=]l,L o^ #)v<0V/%A{f?al1|)g&GWe&F{9Y޽}㪎8'ъ>R2cb'0406;5><~MEIAvzr\TX1Ƙ gy8KI`\1b V Zgu;7ec}]mM uUeE 1^nwn](+%&"tNGc V vcĊala_ѥ\_YpwGK㽚촤g{k3#}=]M5%9i Qa1.vcl,LA_J|) KIY]^@rnzbd07#%>:<cL[]YAFcLcc}828L @i!3b.HKPR1eRM/6iOμ}+ h0CbWc}]mMuYiI>VfFښ"W.pcR+A:1ꥤKIblmepwGKCMeiANFJ|tXΝ[Ud%ń]|a?b z^JX1DKg1ƞ?y8=12ي0VVdgij1$'-."ϋ0r_ʳLNb V :Fs)00clal]ʙɱ%9qQa.n(H +aq! '#` :b7z4165>2X[UVhkijprRaK0+Ah0CRn-jC+/NO p63Sw<1&1X13Ft)7|4٩ၞ܌ ?/WG ;*J`c&1xZ{+ P1>V𥜞jk./JK vw23PSdgAaK} Pck+sccc%9aA.6c* +bB׮\|_Jc_:cbc_}l$0Dbl|d(/351&"7ԔEѥdc!/ b{F{8飙ѡ>%qQ.Fzn++HcgEa pG/%Rbr}ei'S=c) 1~^n&crRcl$/` : v@\ʍ촤wg{+3#=mM uey Q|x8Y1b1+A]:1ꥤKIbl c٩œ ?OW };(J Kw1W.%AG$f0IثONO v+JK vw25ESSb _ʳL{)a :ͥ<[{Pw{s@_Oksc}-1IQ!1.VfR#W> `e;KcS#UeEy 1^nN޾$'%."{zc V h01t)?rma)P_@g{k3#{Z7Օe$DХz#W1+A]:bx^J1|)W_>{<;5>vVfFښj"c<,;pR~3` 0"ɱ҂ _OW c};(J _r7+9b$Ǝ0cb-ƾDF«ONO v6Ue&D{9YSEcc!/%IZADbX=m#Gucmyq]ʙɱ%qQa.zn(H +aq #é? cbבK#.<@OgkcmUYanfjBLxo*I ^`c 0+Aq`lĥX]^ 061:T_]^loefD`LY^FBT*%*ƘW0` K;1ꥤKNt4TfGy:Xܹu]UQVJLXc<} +a ؉ᅯbu{cM*𥜞E./JK vw25PSdg9Obg߆1X1O`lmeqalfrl '=9>*,XcLEAVRLڕ8XKI`\AG/x>Q?nmC{Dbl|d(/351&"7ԔEy/pxADbX=m#kˋs/>joPQbomnwO릺5>1vƘ1X1_JcR,ͣK9;5>8J +Hw%aHs,\nwF}7-??ץ}I]YAFRLX /;?~^1#^JX1:c;y) a=}tfrt a8?;-).24cLSUQNJ\DHa4'Yb V :Fs)10clal]٩ၞ܌ ?OWG [:Wԕe$D1xƈKy]c cbپ{Z[Yjk./JK vw23}e EY)BgyNa` 3}bl=q)WHM w#Ud$Gz8ؘc)KK^841_Ati^J +|8{#wʊ2Sc"ݜl-M t/i(J`%1ta ` ;KIec+K/񥜙non(NO + p67sMU%9iq1nN6#}R0` ڻC`luyaclj|da073%!&<cL]YAFRTX ;)|) q)`` 'Z}3aEc}]mMYiI>VfFo\('%..%7y)1X1n+MK s?Gk,-H tu0ֿsUKMY^F';c,̌tA _J1R-/?`o'XYQ^VjblD!ƘE1^.VcRcb ƾP1񞸔+K/1f&džۛj*J +rғ}=\͍o^$/-!r9>nN .}1ꥤKIblc{#wʊr3Sb"m-M t/(HK߶0W/%AFKIac/>?39:E`8?;=).24˜8cRdab< hh.nܳ'fƇz:Zk+K s3RÃ\m,L tƔe$D1xYKI`\A>R6?l{0jmeqclzbt8?+-162$k5Te/ + `;1v hh0e cR'/cnc%9aA.6tj)KKKy41f=1+A]ڽbxv_J1|)ז?yxozbd(/351&"ҔĘ1.VcR Z1QAt@1V^@non()NO + p67sM5%9iq1>nN-11?1X1h?'1@`lj|dn]UYanfJBLx%ueI1aA3\쬧<܌AtPg#e]Jck+/_<}tfrt8?;-)624̈y)Ǝb V :cĊmcla-K sRNt4VdGy:Xҹ,/#!1N^̌ǏrAt`\-q)ז1Ʀ'F{ښˋc#BݝL o߸vYCEQVJ좐Y^.V` V *6r}e%ɱƚ@_OksccjJΟbalgžAt`z))R`'Fz;[Ue&D{9Zj_PQ(ȿ cLЊ1ԥ 3߯1FA{G3C}c 5IqQ>fFwn^$'-.1vwb'x)a :C`luyaalvj|xn]eianFJBtxƘ .vVR#Wg0+A!g:,XU-5eyi Qc 031X1ҷc'|) K8.鉑֦Ęo7';KSC1 YI11^.VcR"a{~cb&}!1F؟c+K/_ L w77Td'Ez[߹yȅ9ٶ0xRcbo1Ft)I./l[WUVhkib}I]YAFRLX /;)b$ƾ)1X1uv.%1R[{P_WXyq~vZR\dhƘq)1Ǝb V :Fs)10clal]٩ၞ_OQy_܈͌Db4QzMP{{ޗ@Pzn(+D&6vWG<QclckXM[ʊr3Sb"ܜl-M?PSucL.%X 9cԥ$bls}pwGkS}MEI~vzR\dh2Bw[^nR1R>/%1 +125^.̽lC1VYZhcaŘ(8ىd2bRÖrzbtOˋc#Cݝ )KKb1v-%KγX Obla뭍%,&Fz:ۚj+K r2‚|=]l̍ t5Ud%ńݹ}1l)Y"Y4hbA|O,c㤡vcUeEy1nNx)IbG1vEj1`10n)Rn.-L t6Td'Ex[< #)*-%/7Ul)Yʿ8Ehsm-cK95Njoi*+LI ru0yHKCUQNJLX61Nvb)Qc8b01 +ϚˋҒb#C|ܝ̌QKKb1v-%KG0b&1>e.U"Fz;ۚj+K s2RÂ|=]l, t5Ud%ńݹ}1l)Y")b0-vc{(vϿoo'HC}(ƞ>./JMvs45~$'-."χcL,%X 81/"Z_]Zhmn()NO + p67AK #)*/%7Ul)/TGy#nk h#-1|)1frth- ef%_JuRR h#c ]IR .eS]u9~)oe|RrK+FK AcK0FI"t)Scv)YlRbmQDc94ac h4V>]WХ.%b4T䤫.O_AjbcWK.-zZj* +2`c/%v)W*FAq)?~Z}=],[KzRJᗒ]J¥D}ϥ X߼Kjť\&K)'-NLإ^q)A1/wt)Gu)MK,/#!*`efM.b;[Rbm01clKd +rs67>zXEAVRLH`?/7' #4Td# [cRN LKJ {ᄅ1uUE9)q|{9YvRSRD]JP {/eJq-s~g.vV&t)))Hw"ň.%(A&ΥCoGo$E{rs23PS<WtRbmY_oK9_ʖJRd&Dx;[k= #)*$q=-ͺ1A]ʏإ/`?uU-JKNyBi t*J cq0EGCEINA{)pG^#:ۚ+<,w+Ƶ+C^G(H +!Ÿ9XqŨ0c1As)bSb#C_xT_];Y׮F^p :H1EYI1!ľ{ii(A1/%~)Gz{ښk*<,)̻qz!xt019(+%&)Ɖ) h"V40X{KCMeY).;hcijy䐒A~l,(TK@1~US cRNbrblxZLO:ZaK0aQؚc  Zp)bSboF_zXWₜԤ^nNvVfzZj"p!vRSRA_JLb#CHgMu-JKN rw67F)Hc Wl?6>:WN^Vz򵫑.vw?a~\_aIQ!}<K(AVR.({??73+61:<jonx0VkW.=p⸁RLQVRLH`?/#9_/ bmI+ csH?bc/w4THu9ϓ6&:UeĄqؘ좣!(_ʟ(AR~ػ?Rl)XW}3%1.*+։. 73-)!&bp6vMfڱcZIlc[[MiFH V1UL؈Lྣ, Ⱦ_@p9O83=o?*2TLcIiSKD=狝}>ཥޝV/󿵬*WtPQJՊtQ.?x]Tj~C8݊kϹ~$bwtˆy7_M Z~gdY6)"*{C{wٲaز{U؋b:gT @/{hȘ݊KMJP+OX߲ 3iz6WfsE-Y0ӶbH+VZq%59!Ɗs6Eب+}Yk{GXmRQtQ bEFn  + _!*VlH/*1b7+_Ub^3]L(*6pCtVDbQa0nRaz~~-+ԨTضb[7[5۬b.jŞS*Q1ƪbW C֋-W+:T_ dשe3R/;}]aۍUŔ1F,{mUbqJ$*XɏRR1=ڭjQfpb~~2NJ*'[DT ,*FȆ ǭ?bFȍ 7*@nSA8 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*@nT ܨQ1rbFȍ 7*6}V*JŀEZWY$C*@jT ܨ=M#cz(O&wQUl+R.Qm*֠VLcYe x`XkzP*kbtT+ݺbťzŚM#c{`> k+VZ\`]Ɗs`֛W,1%~,NJ:8%{JKKI4ެذ.zŦy[nbٹbbub-3UETNT\T,7;3NŖpWeİؘqzf+UT,JbYEU5u -7ƌpFfR-͍ u5UEYJ.jlbpF7bk/*vBbmŬW{Xrⅳbv)[kQ ƌM4Tl򕫌;|RTbE%jƘ1B8#{7bbMjJ򕊥*;ubV._bޭVbzSdd刊UVU׊5Sǘ1C(L!bbk,ʸW,BTlV1A*1S؊Uk7nV,Vص9%e7DƘ1S8XsS؍הŪ۶ucU+ԊpAY~{ wVlZ1/%jłFD;V,XX]C^1mi#e16-b)PV0OXRBQ}ۂՊ.R+6I({ 0Tбgb.]-*VZ^YUS3f +g~q-bʺRQ̫/%Ǟ9y쐡bW^>+CBõU@2f-k S#f:(h^XxhHpP` +_o/ϙSzb ||m {1b)bYE%R1C􎙕 SQ?0=bʒ,QQ%h]ς'Y1%c*6d#EƎ>se~kԊ*v..1%-=#+'PrRjcL͘1-d&~vCFLbT*VwNNbk,9}b#:Sg$3qSUDno(]tvE@"( +J.UE:ʡ f5cyauIT?\~*$D8SQ;VWTVY]?4:61͚Ǔ~8[2a+W yPoOg[S}ueYQ^vVZR\Tx5{E>G1`=DhbFvNĴBJ}kc3q(#Huߔakj{A)Vtu45E)Њ jE(34urdE&f-,kl~78l|rMJMdlH$?Ȱ!$~Р620ffjbldX ԐRLVJ6~>JV#PS&X1Șk7s +J@GO2IWxSR!)#H\>pD;1'_u̧Ou4b%97&DbL u55N}*&) X:xFħdܸ_r^mC·xRΠIb6oߠQ!c[F",1a`o^{b?AAsC;%odDz8Zb +kAb'(Ō-l=|B"3/.[s1K)_Qޱ ȐdH$7E]7?aW'/NO2Ѡ||nyq!>Ύ6Ɣb'؊ +loa+&g! IP9mcsgwWӳnUV7vtI96))(22w$KZkto)hĨ= MՕeEyғF_qwv176>w8[1?Au*vSR/[;\r [XZQU Og,ؔưcD"qcdžq=ɚe׃̴+~n/bJU[ъ}Ql0V츌Ŷoݲgç+(RLRLJNAEMCSᒻ_pxT\b*=)3d`h_w e,쟔g$9ntK #6ǚB>jGXUE)) aA /XS +R~@?C1! e/Y9zFD_MN)(1))Qd@ŒnD"qMFW E~Ħ&A'W ';+=jtDh}sUOJbD@7lܴ߳QIy%UL-m]<|C._'eQ~Z;{0c#Oǘl(~H$ 8:<&MN0Ǟ`z:[+VVD+C}<\m-MΟUWU60 1t $Ao444ZuG !vr1 +rz|TSLP[Ier|LDHG;O@ULGG5žBA1CF13K-(5ѪKIXw߀~edl;9%d QhMƖC١;!-CCĖOݓ u):7< , Abߪ7_f<7ax)ӳʪpuV('ƶ>yvt$dރe ;]F{ ={rxpAlRӅS(?;e0`5W+_QL3"ZX\ܽ|R%e1&)#tH-Zy{t {; {NR*CnLbYiIqx(}\6VD1#PLRo`dʚO.'Q)9knIe#&Jt)2 ){5hA֐C_!`(ΰh%Dl|tD&t73S,'#%16JOr(Vx( 9_9Mŀ1F1.*fbfɳc/042&>9-+Nc+|+k){h򊆆F6;9Fa[k+XO6ީ./)JK Ζgifq1MΝM12t9zx),x6RG&+O)fSN/.1PgGGǠzyNCCaM=CaaKs3J11Rb!~,PqtŐ1Rr Q1r)Rz E1[X\M݋)ӳ0ǖͭCS3# p!lgk [!6;=T bݢ6Ņ8nE |oxࡴ'362㰇R ežbD1 +10&WǖVVmlwoo1<0 Ǯ_{{ 6S b- u%3R`Ex%QL1bK(70b&XpXdL|RZfNAQiE͝Fd_:4|oT9A[\Z^Y]Cɶwvf> -8vÝ-lmueyi67<$ATd%D<=&@RL}(Ϯ0rKiҎ\J0£cӳr * c"qOtP&'M/,> ollng*;444ZncӡkD s0lP#*ˊ rғba&s(z vfi(ƌ1Kɳ88cLc,?e^!XK{w`hxDMNGɀ啕UFCCcWV0$+៌)&d Pr)ع3*Kie÷cQRՌ54uC`!d P6gLihh2lű틋 6CMv57KM16V;_2v4spveXh~ʴ̜|X]CSkqL&A'&Yl>dF˃MCgɉq$lD.c 65s2OFST)bߨS_1K cg#w1v/08,RFcb 8&"S( lrjjj -9J?11)dCR0L"!X_[]XdXpubN3C}q(%;KIƘc.nSc1qҊ*xM-^lH62)1444ZRt(<! a&xUp'ĸ@Iw72Ŭc;ή؟\Jv^O2WPTR^Y]K_)FQ2L6<,g Fpl;~xX`H$1 /E,<$U+|vCb\/cLB>o0$<0[pknm"H2L:0h$2 r;^ +~!` 0QG[k3VSU^Z| 7; " %ANKPQO/%Gc>5oa(2_XTRVQ{%wz{3]-:T~Z[aUUde&' b?ok'~?9_:gSRj1KX 08VY]S5d@K,ϺhM4M`(X3VWS]_녫x$֠F%"FQ P!O%"ZD+iժi;{r/Rop7999>*{'S,8(KP,~R'+sUy;M2:={m\YǞAr޾{oce{߿ +m !kµY×/tw{N|uUAL+~P&Nʃ9cufl8sA2~uj"8=xC {n$e^~Ϳ[c3\^<ׯ;L [6;u$}MIbu:reɊ'e8jSZ _.sl>X[$^nn;8?WO;=K = +{h}* [!v}nfjb +I؏b5+(Vpٛ2dlhdlbW:vg= "63X̞xKMXn}xx/!=\ wwkrrbld(Dޓ[O-K2*;1V[/7Xo06ñ[w0_5 eOCX9ag[dl`cIc'd P&uC3GI2ʸ@ 0G ߰|AĶ7ŜbIƾMa,@f$`0f41W:v&E KABU,60v0X@E e gRGX'cy8hT00!,0 1؁(bKcIt2Yd"PfLkce,ϊ^& +aa:+Xž*ӳݕ2d2X̄3 c,c/ `: acRۿ_")(c{cc=fYQ+RˀI̐X+fS0cC!W#V=2UiJ㘅H2`012@,8.~ `F0KX`XN k2Xƾ9fJ+@,S3Wc,y^ `N0%1\sCKܔI*1Y (er522{A`0120 bۻ'c,Xcd*(T3(c,y8$ `*XHXaۆbs,t̃L%3)f1j/ +f 5cvyYȌdBbv1ƲW@%,aa"ysw "d2rHce%AqP 0$bTc1+=D2L,s12XQ!g3#nxKw@f%2,j/f+d"g̟cֱ8d"Rf0yc) ƇF8aְ(B<| dJZ4 @cec~ f 3,bXR,c2L)9μce,#*`a;X|cT2C1<*TajXPRKsL!3fac,n%bo n؎ V12O2KYYXScY(A31?1X fIce +Qvt%  sE,KrtQ6JC,ؖhcEAyy-leD=C,X2_b1Ʋ\ &l K2,Aec,mmB 04c,˥B˧1d5XYEt$c̯&ڰ e*lg!d1^17>#a%JFl 1X,lcl튷1^mcݖ1c1c1c1c,O!6 +endstream endobj 233 0 obj <> endobj 234 0 obj <> endobj 285 0 obj [/View/Design] endobj 286 0 obj <>>> endobj 283 0 obj [/View/Design] endobj 284 0 obj <>>> endobj 241 0 obj <> endobj 242 0 obj <> endobj 238 0 obj <> endobj 287 0 obj <> endobj 288 0 obj <>stream +%!PS-Adobe-3.0 +%%Creator: Adobe Illustrator(R) 16.0 +%%AI8_CreatorVersion: 16.0.0 +%%For: (Jiawei) () +%%Title: (382657-PCPO4C-650.ai) +%%CreationDate: 12/3/2019 10:40 PM +%%Canvassize: 16383 +%%BoundingBox: -114 -640 349 -2 +%%HiResBoundingBox: -113.6196 -639.3623 348.0723 -2.48096 +%%DocumentProcessColors: Cyan Magenta Yellow Black +%AI5_FileFormat 12.0 +%AI12_BuildNumber: 682 +%AI3_ColorUsage: Color +%AI7_ImageSettings: 0 +%%RGBProcessColor: 0 0 0 ([Registro]) +%AI3_Cropmarks: -71.9937 -581.1445 328.0059 0.001953 +%AI3_TemplateBox: 250.5 -250.5 250.5 -250.5 +%AI3_TileBox: -177.9941 -686.5713 434.0059 105.4287 +%AI3_DocumentPreview: None +%AI5_ArtSize: 14400 14400 +%AI5_RulerUnits: 6 +%AI9_ColorModel: 1 +%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 +%AI5_TargetResolution: 800 +%AI5_NumLayers: 2 +%AI9_OpenToView: -645 267 1 1819 896 18 0 0 51 124 0 0 0 1 1 0 1 1 0 1 +%AI5_OpenViewLayers: 77 +%%PageOrigin:-55 -647 +%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 +%AI9_Flatten: 1 +%AI12_CMSettings: 00.MS +%%EndComments + +endstream endobj 289 0 obj <>stream +%%BoundingBox: -114 -640 349 -2 +%%HiResBoundingBox: -113.6196 -639.3623 348.0723 -2.48096 +%AI7_Thumbnail: 96 128 8 +%%BeginData: 7516 Hex Bytes +%0000330000660000990000CC0033000033330033660033990033CC0033FF +%0066000066330066660066990066CC0066FF009900009933009966009999 +%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 +%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 +%3333663333993333CC3333FF3366003366333366663366993366CC3366FF +%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 +%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 +%6600666600996600CC6600FF6633006633336633666633996633CC6633FF +%6666006666336666666666996666CC6666FF669900669933669966669999 +%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 +%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF +%9933009933339933669933999933CC9933FF996600996633996666996699 +%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 +%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF +%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 +%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 +%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF +%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC +%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 +%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 +%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 +%000011111111220000002200000022222222440000004400000044444444 +%550000005500000055555555770000007700000077777777880000008800 +%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB +%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF +%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF +%524C45FD2CFFCFCDCDCDCECDCECDCDCDCFFD53FFCECDC8CFCFFD05FFCFCF +%CECDC9FD50FFCDCECFFD0CFFCECCFD4DFFCFC7CFFD0FFFCFC7CFFD4BFFCC +%FD13FFCDCFFD49FFC7FD15FFCCCFFD47FFCDCFFFCFCFFD0FFFC9CFFFCFCD +%FD46FFC9CDCAC1BAC1C1CFFD0AFFCAC8C0C1C0CFFFCECEFD45FFCECFC8C0 +%C1C1C1C0CEFD08FFC9C1BAC1C1C7C7FFFFCDFD45FFCDCFC0C7C0C1C0C1BA +%C8CFFFC9CFFFFFC1C1BAC1C0C7C0C0C9FFCDCFFD43FFCECECAC6C0C7C0C7 +%C1C1BAC8C9C1BAC9C8C1C0C7C0C7C0C7C0CFFFCFCEFD43FFCECFFFC9C8C6 +%C7C0C7C0C7C0C1C0C1C0C1C0C6C0C7C0C7C7CEFFFFCFCEFD43FFC9C3C3C4 +%C3C3BBC2BBC1BBC1BBBBBBC1BBC1BBC1BBC2BCC3C3C4C3C3C8FD43FFC8B0 +%B0B0B5B0B5B0B6B0B6B0B6B0B6B0B6B0B6B0B6B0B5B0B5B0B0FCC8FD43FF +%C8B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B5C1FD +%43FFC9B5B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0 +%C8FD43FFCEBBB5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6 +%B5B5C9FD43FFCFBBB6B5B6B0B6B5B6B0B6B5B6B0B6B5B6B0B6B5B6B0B6B5 +%B6B0B6B4CEFD44FFC8B0B6B5B6B5B6B5B6B5B6B5B6B0B6B5B6B5B6B5B6B5 +%B6B5B6B0C2CFFD44FFC992686F6869686F6869449998C198996869686F68 +%69686F6868A6FD46FF9F69696F696F696F696999C7C0C79969696F696F69 +%6F696998FD47FFCF6E696969686F69694499C0C1C0994569686F68696869 +%6ECEFD48FFCE6E69696F6993696998C7C0C79869696F696F696968C8FD4A +%FFC868696969686F6999C0C7C099446F6869446968C7CFFD4BFFCE926969 +%93696999C7C0C7996F696F69696EC8FD4EFFCF9F6E68696999C0C7C69944 +%69686E98CEFD51FFCEC2926F98C6C0C7986F6EC1C9FD55FFCFA6C8C8C8A5 +%C8C8CFCFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFC +%FFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFC +%FFFDFCFFFDC2FFCFCECECFCFFD5BFFCDC6C7C6C7C7CFFD59FFC8CCC7CCC7 +%CCC7CEFD42FFCACACAFD13FFCDC6CCC7C7C7CCC6C8A8FD3DFFBDB6B0B6B0 +%B5B6C3CAFD10FFC8CCC7CCC7CCC7CCC6CDFD3BFFC4B5B5B5B6B5B6B5B5B0 +%B6BDFD0FFFCDC6C7C6C7C7C7C6C7C6CEA9FD38FFC3B0B5B0B6B0B5B0B6B0 +%B5B0B6FD0FFFC8CCC7CCC7CCC7CCC7CCC7FD38FFCAB0B6B5B6B5B6B5B6B5 +%B6B5B6B6FD0FFFCDC6C7C6CCC7C7C6CCC7C7C7FD07FFC9CEC9CFCFFD2BFF +%FD04B5B0B6B5B5B0B6B5B5B0BCFD0FFFC8CCC7CCC7CCC7CCC7CCC7CCC7CE +%CFFFCFCEC7CCC6CCC7CCC9FD29FFC3B5B5B6B5B6B5B6B5B6B5B6B5B5B6FD +%0FFFC8C6C7C7C7C6C7C7C7C6C7C7C7C6C7C7C7C6C7C6C7C6C7C6C7A6FD28 +%FFBCB0B5B0B6B0B5B0B6B0B5B0B6B0BCFD0FFFC8CCC7CCC7CCC7CCC7CCC7 +%CCC7CCC7CCC7CCC7CCC7CCC7CCC7CCCFFD26FFCAB5B6B5B6B5B6B5B6B5B6 +%B5B6B5B6B6FD0FFFCDC6CCC7C7C7CCC7C7C6CCC7C7C6CCC7C7C6CCC7C7C6 +%CCC7C7C6CEA9FD25FFBCB5B5B5B0B6B5B5B0B6B5B5B0B6B0BCFD0FFFC8C7 +%C6FD04C7CCC7CCC7CCC7CCC7CCC7CCC7CCC7CCC7CCC7CCC7FD25FFCAB5B5 +%B6B5B6B5B6B5B6B5B6B5B6B5B6B6FD0FFFC8C0C0C0C1C0C1C0C7C0C7C6C7 +%C7C7C6C7C7C7C6C7C7C7C6C7C6C7A7FD23FFCAB6B0B5B0B6B0B5B0B6B0B5 +%B0B6B0B5B0BCFD0FFFC7C1C0C7C0C7C0C7C0C1C0C7C7CCC7CCC7CCC7CCC7 +%CCC7CCC7CCC6CDFD14FFCACACACBFD0AFFC4B6B5B6B5B6B5B6B5B6B5B6B5 +%B6B5B6B5B6B6FD0FFFC8C0C1C0C1C0C1C0C1C0C1C0C7C7C7C6CCC7C7C6CC +%C7C7C6CCC7C7C6CDCAFD0FFFCAC3B5B6B0B5B0B6BCCACAFFFFFFCACABCB5 +%B0B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0BCFD0FFFC1C7C0C7C0C7C0C7C0 +%C7C0C7C0C7C7CCC7CCC7CCC7CCC7CCC7CCC7CCC6CDC9CFCFCFCECEC8CECF +%FD05FFC3B6B0B6B5B6B5B6B0B5B5B6BCBDBCB6B0B6B5B6B5B6B5B6B5B6B5 +%B6B5B6B5B6B5B6B5B5B6FD0FFFC8C0C1C0C1C0C1C0C1C0C1C0C1C0C1C6C7 +%C6C7C7C7C6C7C7C7C6C7C7C7C6C7C6C7C6C7C6C7C6C7C8FFAFFFC3B5B0B6 +%B0B5B0B6B0B5B0B6B0B5B0B5B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5 +%B0B6B0BCFD0FFFC1C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C7CCC7CCC7CCC7 +%CCC7CCC7CCC7CCC7CCC7CCC7CCC7CCC7CCC8FFCAB6B5B6B5B6B5B6B5B6B5 +%B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B6FD0F +%FFC8C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C7C6C7C7C7C6CCC7C7C6CCC7C7 +%C6CCC7C7C6CCC7C7C6CCC7C7A7BCB0B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6 +%B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B0BCFD0FFFC7C0C0C7C0 +%C7C0C7C0C7C0C7C0C7C0C7C0C7C7CCC7CCC7CCC7CCC7CCC7CCC7CCC7CCC7 +%CCC7CCC7CCCCC2B0B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5 +%B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B6FD0FFFC8C0C1C0C1C0C1C0C1C0C1 +%C0C1C0C1C0C1C0C7C6C7C7C7C6C7C7C7C6CCC7C7C6C7C7C7C6C7C7C7C6C7 +%B5B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5 +%B0B6B0B5B0B6B0B5B0BCFD0FFFC7C1C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0 +%C7C0C7C7CCC7CCC7CCC7CCC7C7C7CCC7CCC7CCC7CCC7CCBBB6B5B6B5B6B5 +%B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5 +%B6B5B6B6FD0FFFC8C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0FD05C7 +%C6C7C0C1C0C1C0FD04C7CCC7CCC1B6B0B5B0B6B5B5B0B6B5B5B0B6B5B5B0 +%B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0BCFD0FFFC1C7 +%C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C1C0C7C0C7C0C7C0C1C0C7C0C1 +%C0C7C7CCC7CCC7BCB0B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6 +%B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B5B6FD0FFFC8C0C1C0C1C0C1C0 +%C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C7C6C7C6 +%C7B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0 +%B5B0B6B0B5B0B6B0B5B0B6B0BCFD0FFFC1C7C0C7C0C7C0C7C0C7C0C7C0C7 +%C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C7CCBBB6B5B6B5B6 +%B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6 +%B5B6B5B6B5B6B6FD0FFFC8C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0 +%C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C7C1B6B5B5B0B6B5B5B0B6B5B5B0 +%B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B0 +%BCFD0FFFC7C0C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7 +%C0C7C0C7C0C7C0C7C0C7C7BCB0B6B5B6B5B6B5B6B5B6B5B6B0B6B5B6B5B6 +%B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B5B6B6FD0FFFC8C0 +%C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0 +%C1C0C1C0C1B0B5B0B6B0B5B0B6B0B5B0B5BBBBBAC1BBB5B0B6B0B5B0B6B0 +%B5B0B6B0B5B0B6B0B5B0B6B0B5B0B6B0B5B0BCFD0FFFC8C1C0C7C0C7C0C7 +%C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C7C0C1 +%B5B6B5B6B5B6B5B6B5C1C0C7C0C7C0C7C0BBB5B6B5B6B5B6B5B6B5B6B5B6 +%B5B6B5B6B5B6B5B6B5B6B5B6BCFD0FFFCEC0C0C0C1C0C1C0C1C0C1C0C1C0 +%C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1C0C1B5B6B5B6B0 +%BBBBC1C0C7C0C1C0C1C0C1C0BBB0B5B0B6B5B5B0B6B5B5B0B6B5B5B0B6B5 +%B5B0B6B5B5B0C4FD10FFC9FD27C0C1BAC0C0C6FD0BC0BBB0B5B0B5B0B5B0 +%B5B0B5B0B5B0B5B0B5B0B5B0B5B5C3FD12FFCFC8C9C8C9C8C9C8C9C8C9C8 +%C9C8C9C8C9C8C9C8C9C8C9C8C9C8C9C8C9C8C9C8C9C8C9C8C9C8C9C8C9C8 +%C9C8C9C8C9C8C9C8C9C8C9C8C9C2C3C3C3BDC3C3C3BDC3C3C3BDC3C3C3BD +%FD04C3CAFDFCFFFDFCFFFDFCFFFDFCFFFD97FFFF +%%EndData + +endstream endobj 290 0 obj <>stream +޽ŷEo;QFBbg HzFg^t^HE9@祇{/t@z|go +䥧s&#,o.$lol[zo%/=11y[ |IV.%y=KS,/}3h +ې.Bz<I_ f-=oӕ;a I|)=PB#[ҷuE6v$}QzIiKO~s+OiKAzJsttCzz6JOl]SmKOfNS =NIO`T`S0uT:r&&=`ؑPs`Y +htlOzZ'KKON@# +`C tV.I'tR:4Ig0$Qzz%iI@@? Y:K=@s̑tq=' 0t^z]:JO3U: I1CV:nH.J$vD Wz^ؒtXS!@gI&"`s +J(E&#@@ztB&,H+0 `Z +L]ztӒ6f!TG I-0y9`v҉ LRzHG/0 # t;)1 /=OB:q' H1m1Eґ lOzht*[(GJ'4jN$=1]: HG5JO ]l`1VNJ7P'J7`0tKݖNq_iYs*= +D:`H':̝+P&0G?@Et\H7xtgK=yt~Jw"C6`#&̗t@|~tw0wQ:'ҭ=J?A_ +nZ@;zyav SJWt#@IFtAIwHt *]X+]3;Ht:!ݹt}Hl(]"=;'jM W[`B\V@K[u$].}:[:&mH ht6KC`{uZ$ݞmmGz@+sƑ +1 䥻rƗ!nؑtt?$qv*]I &݌0bN HHwLF@@ `b%f-݃0I3ntUJ7LX줻o&/][`Fҭ7-0#Ht + L]`Z.t0E"ӕt)JLWm.]j`Zҽ660FYHWt L^`F&/e0;ntIJT$kf-]y`b5<01tHwdL@ #]`m51;I ةtO @R +j҅ƗK"_ /]`LVt-1[iZ!]`>HW$ضt @[+l[EE 'A"ۓht]mHK.6gZ']`ҽ3mN%6JW'ؒt @K l.5RKwWF&-3.Sp"~VK)8t @ۥ+l(,bKwt@Xҝ2ݐWt @gKt=2]ZJAc҅ Vc']`(=CNJ/}1]``E yt`a:/]_^>HW3T' ytM`[`z%])ib`Y1aj(} @Kz(]SGt3@?K#S>T`.q~#GL]Unޥ0yK~~\ +/]/;/BPVۓ#g8Gҏؒt|I׽NJ?4^6y~ݐ~J#RkTWɰ;H̵tl`D.Ig2̯tC8Sf*ү̣tU҅qҧˌ_4#H K'BErG+_CtMKOJO +[.H~Uoҵ']9WOKS7ٿ?zPESzo`~9̈RHkͲIqtW. Ct`t{]#$@7+6Kr Eht`sZ*]ؒtmlCyvIWf'?@2ۖn!-51IKWcƗ% ,]ةtG 1" JHW`&#W@@01f-]{t L^I\"f,-Ӓ4`J0E2 ԥ[Nt`]'LE0#&/]]t .TIJUM(LFC`t+ +;$Qؑt! ,ݐUtO +cJP=))]Bht[ +HO"ݙ'-nN`{ҕvI @[Tتt]*lI`RF6TQͥ%U`R @U8t+l(]$t +KWH: ݴnHty3ҭ+tI{U҅.IwJ01V"ݓa`(]t UI6t=ҝ,Xk0t3 KWB:,0ҕnK̵t--+]tK J@ 0H7̣t'ҍ-(]to I>#0wҥ^I̗to.s$]t I=z(0/J7̋t}.s!]t @knut.=.tY҅K7Ys>KW9/[@{^z+] ~J7B y|tq`^;_z(]#IW6Hoҕ 9n~te`_z%]/^I5N?5 ntM``z"]G.H4Q ' 9nt5`Na ]_^K2Wҥ nt`a-]kvnK1]#E yt Ɣ`` 5S@t*ICI.JFn +l$tY0qkKw0雴Us H_#X% ö/$-}i`t H_J6l.}K`t /D#}-`t -I?%֑nG鷾O~`69~&<;W֗=/ϙ~`}NJ+ J7DEfE]/5l(,mIG]ItOe{ ~D2]~[_ݡ//l"2v7IJMtOM[f+n2-7.ItLGf'6iHFү'lIq&) +אJ%ƙ{G_IZ'JV{gf*jדI KbtImү!lC}f/]~s K=KSA-&&h&&*77KHT ү6~`>B5gv)JmW~噅[KwlUMa~}.j6~AJ(rN{j֗~/``ZoL@fJ_&/Nd;k[K&,BĤ빖~=Ĥ_%t=Ɣ:LF= Ks$a׈JA0y.O&)}ؑSn{+`a*t7 Sd#H?Fmcү LWӃc{ Bdo +HSI_G$줻VK?hdswf-݃N@/(H n"3җ _ I7I鳇IZ֗~/ ,ݒZחu_ +htc> 3>HcJ"|Z +Ь~uMĤz+}Y~ҭ/}Jj}{ҧs'}{t۾ Jy~%}yU: Z@We@ 0l$0o&8u=Q@~+A6Mz֟#G =E9@?'~O.2Vz>K=~sѿ/=V@J?X @?*̋ҏHz 7 % JaI/#$`=~0H?FS@!̯VZz1ms-y tX6cJ?7ZcLT A'0^tOC%A"'V~\*UAVz[tFAH/ !uݐ~J;H?"`CAۥڠ88Dzy^'l.?hc6T[^!Q[^!Q["N["Nې^$Kiې^$Kiۓ%HQۖ^'E9ۖ^'E9HoZ!q7 +~KƔ^*䥟0^!,}{;^-$ؑj!)}N 1v*]I<0CF H/2ҧLFz>r`2;^3ZIf-}$7 3>l`қJ60aeOav' LXz0;&/o17HHf!}TW>c`Z[K00-ԥaҧ LQz0]+{ӕ=LQhK%}ԥӒ>W`H*0 Tb' +Hz 1yf'qCLX8J"&)}LW>K`ۈI$0kmĤH/$&#}@@z!1S2; H!IL@ZbĤ;>? )ؑIĎK/'Ɨ>9 ,_~bLc1 hb3Z!GHo)-}`@[ۖ>0EҋI"EO hbGKzW Z'ت9^WlU6Jo,$}H@7[>$KͥOhbs+DxJ-6>ҫI jʼnhbC.P`H/0֗> Oc#!XGHH1J5Z$X%}@72cE$I/3VO2cE$I3tOz1>+*}@'WU Jo5515Z(k 5Z(k 5Z(k 5Z(k 5:Z.k 5:Z(k 5Z(k 5:Z(k 5:Z(k 5:Z.k 5:Z.k 5:Z(k l6:Z(k 5:Z(k 5:ZI5l6:Z(k 5:jk `5:Z(k 5.Nfk 5:jk `5hJ; k `ڦְZ(k ӰZ(k fְ&n6; k `fְ&ZY45 Zfk fӰ&"ְv"Ӱv"ְƓ^i >c(} @Ǥc#!XGHH/06>ҫMhbs(ؒ!^WlCI/*-}`@+WcJ^NTNb2ҧZz1If'ӕ=LWtiIof$}$7 >o`2;KOGz"G{Z]]i;%IL4MQcD:Rw*iJG@" Dأ15Ieʛo?kݾs9g?ފ(R*n*rQEQEQEQ%rA-)((()wOPߛ(((_ +oRQEQEQEQ 8׫((((uru>R犢(((RJM((((Jʮ ]((((eW((((5VEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ}((((((((((R'+EQESEQ dմ(J-?VEԦъ(5FbEQ>>AW@QE'(J9pR(JXV8.@(kTЊ{j\KI*hEQ'5>ڸ.NQv(˥9_K4Kfr/()I̅OR Z(J^.|~VNRs\Hɟ4mh(u9[y>gb.&r(s3/Sg8.Ȋ(5bĜrJʑr?U2٦N:ϊE|/VN994k@cI']3AqEQb쫘#/VA! Sǎ]ϊT5sgK"%XiEGN +Z(JQ̅ŜrZ I:-Pс Z(JeSZdŜe@ʑ}$,H+&EQ"sa1^NX9P5<_%^ %h(L"sṞ]\N[94K/"t蔡]oEQMM"slZ+9tW"t,CϊT&56s/'lWs?:8:Pt9.(J}d"sR̉,^Z,؟ mm5m%):6t (gϊ}9br e+d7|3"H:RtقJQCQ3"H9_vZf)['; ki4;脡3~VBȜ#攗VaoGtMѡ#C'tUϊ<5eF9eC+ENG0 8?rfI;Gж\N`|.8EQ29'2geeˤeked1Q%OgѤ A't?E9f#se,=2eded1؀l8rsV톢(LМaȜ!fcZLVf)Eǐ 3l5[$MvN:!ϳY(ʁ#KE͜2hscx/CbedId [c,joi8r4+:)d7Pl3FL1g{JfýN;'I5{,-0t\j|.LEQ +EԜaf>Ef2Rb2,Nf#3YD ;Cbl5i,͎N(:-ϟgճ(j6s]-fi-p2)u m88O'$j4$ G'M }T.@'LY(JМmȜ)f1(/Eˡ!eR2X4 }?'&SYҁIdh6BG +`>zVeSs̜l3eJˢeoeHL>6ڽp^.΅m~ ?ͮ&OҐs(ڤ n7ΊJRs}dv] b"cVˡ!e(|ŗ.5\f<|?&UaiH:pQ4hoh/h8=T-8tzVe?͑?9itdC,9IFde/eV2h +ÕW^y:q+14D M6&Em24Z$h8lY(Jm5sQm%fN +l2kYRE$M  +}\c-MG&C\A3YQ 76 w4;0s"2smP!0vy!--LVf)02h}?$aiX$M69(ڤhgh1'䊃4(8`\ˊTYnNYl[fXcX/#--LV)C$drqVZڀ%}?e~lM&M&GKfCc ZM4Ia~#3>p0 Efz5Мa(23\e1~YiYXu2L66n׮]{tLA$ei4Ei8hJdh !X'mN97$>ggEQEbsfSfNDftcy÷zPs35<䪙\̥z%2[e#eV2L*=z1c |Q5D͚MG-:t| agq,znCQf[7LjFj! g3s"f2ae29B&O0aĉM}A6x,m$-69?hk贠9@sްzv72݆(DQ7۶ lh՜2s22Gb2eeXJJIƓ'O2ea}?a~ SFF&JYѱ#sFzVVsf[iF)3wĜ3yҲQMRɓ!d3fΜ9p31;3?L'&GG1Eh4uTp~FPo$|pSA6E)Jq7mvم洙%2.C:f+,/S!ZdT(sz(J.R#t4\l̡ 6_GE˓'O1IRf'I ,XhXd5|?a~͢KI$C-N hscF gn=6@Q"3,m+4f3(482S[\e,Z6YV&)'Ȥ[o/^İX?͏&WCFӰ4$ G#GK ͂CtڶnՒ h/5< >gYzΨ5<+Rlc뚡fRgQ3S"3u1'Ĝ2ueXe#eV2L.^| +JJ_ѷ3G5k6Qz9iTt#A[4端˨~SNvFa=g ϊ$U8cٹ3)6cC N>C5lv/] `1l<,Z6YV6Rd=z5 S|fMKIѬh6dIШ8ޭ+10>KAs΍dYQI7sew}駝Գ65(J.̥ ]ߌ :4(6zg}+j@lfn92;u,00ʐ2 #wܹ0؝ } ?c~] OMS ͂F (81޵ 4qϡis#wE##8a`ͨ48678]3۵əZfOV:fN^̱a@&++[)CcG { f@O'4,-669y&64%htN{Qy3,opѨaɠK (J9 +\8:q3f4mx>uF5#4wܥ[wgÆȌ. XA`f/S\FZVP2}̰8DϱI԰H8ZEjZ454a[ƥ|>ōHg6E|g.~sO|EP3=z+f1[f̳nM?N)1ˈH2Y 'OO@OIliq(zz 4hϣF: >SL=AȠgEQdgWj\ vn|W^ݤi3V38PLeGsb+ smw[/#-$dgy|y.|L?b~]MhϘz;rA3=ӱ{c]NQ,<(e"3LEC= f4$6jg9 ϊd g~7s^ /cs:tjq%Aw]mw(tg)5p>hK.CѢUv;w޳S ͓L6c62S3fe)-[+YcHu⧞7 }k4Y$-&E#DAKA 3EدzgL3=CvqgQJxYQ+qζ 7s܉'T&6wѫoNylj3H3z 2e2l,F"~MgȷްO[KIєahdhN?\ uTop|6zF|Fgܹōz.-3>х[7wk})6Bj`ѭ._ʙZfc1ɠxj9(}0_O8W#G_z)KI?cc)>/27ݐ9GϮz݆ sXmֆcr[ 8sa`s^p1wps0hQcODLjB3S9C?1eeh ◞#/joiq4 PIQv~{ۖ6mz3f'yqֹnC60 3n PzMFjR:]z}0h()fr *w>nlXϛ858{  :BAܶ ڈg]PzHLjˮjU CGA1wKWܼ{ϣ&6?Qh@ͱ%2_,ˑtJѱ!hRpX?#~,h7lҳ][|B^@t V Fx֥ EGdٷ^ݴyk Gi9-Y~nFab_DaCs`fsk'3-fA'3gޯ<zus7M3mLJv># [k[<޶l՚u{1ŗ~SQpr%0^Nh mHѱu>>KAz~"gܹAT϶ۈ3]DBjD3uiCQi9yeWƁhrذyPnf7'/lCshfls崖s j:VtS~ WovNfYzF"<_q%tFTm +Bcr.Re:xW-ڴܭW?jLx7m۸av60مy9I"ѡCAmZ77 Tm s$<ӁATGHqų_(l9<+˖3U4T ++WԸmO@A44f#s\ex1'\_@i #t(蔟QoH|vzm`oc(y+.ssAQ<~/k@Jn5x(wn޺w=O_}hj6dȜ% /q! +*:",?zõϮ|YgmL +@gj[?jչx,vVCQ9_|UЮZ g|O>ͯMf adsN L?'swml  @Nmv.TR<+KjgE$֜i.kTj4m-[|}>'z^nՌ9[Z8V.脡3tgWoH|3/ٽ!_=nG\P :.`rN(uMpYC`U= <|4Ɓ-Y3J~~Bn~ll>CD\1DȤ&tǬQ=nǎnwrsA6[7֑XZl +XxC?ZERm4:xcA,mg9vVMڤ 5dH[ν 7VcL?{q37 5g +:SI?FX>z~g~ꉽAuo]0gm t#_j[|s,mD jgE9&_8|v;*1&ϘMƁ?{{98O;h43(B#?'ۍqj/gP\nYCrymj}yo{{7ٙKT>:C?'3l03&z  RxƔ&:\$JFk:*Xۇۥ + +AqtvYub8r줩.\Z > go&6 f^>Po7P>zCݴDm3)Qxa³hRxƳ;vVH/LiYCrʙv5j<Գ3afJV,J.g95Tnoϋ̛=s:#SA[y4 ]RW-( G w:n֠Mu GPO>{KWs3v5x_W.6\?KStl7|L{ϲW3x{4ym T#ivS`,ԩPDθN֜y ZᮻiWZ68̩9g[o$ۍP|K9Bz~'Q 7knǁAZ,ˁ*XЯԩQs6L3v58o̥̥\Ѕg?zS<|py˖R]XmN6y,(Kv.:mgΐ%gz[N:Iף G8u&<*g/3/ csraCTϼ ϫV\ :ݻxcAᏣ^'SrgP gIGKVy WՐVkt68o\˅]0>',Ƈ^n37[6oX2 .Qǂ,YQr5tږmfc'M5o\AǞ՟ֻqF06Wҳ96|v`PmkΧ9;K(|F{K f.~Ό =ӱ,nF*< 4 [,3Ev.o1EQRBə=)9u"83s0jx^6Rg:Rθ}K_ΊR!crf9˭ASFڐx6V.[L+uXxvQv;Gv.pܿE9.yV|)]Je#F*<Նq|߽ qRqTPR"g+'gy XPurvsfxֆ nXPVCvQ_;/{;t((>y>ʹNݏ\BxxH Zx2i<۹Wt Ήug-61([|~ݗs"LWKOڱ_(i;7b;gg +*J <=gg [AQܼl<s0YQK% =)rAgRag7 Gov: +*J]cٿRr~9Gxvϸv^*7a;QACAE쫜퓜ZXxNUnNƂ,fg ww5,Թ  +IA_;'頠RUj罝 ;Ϝzl-CAwR0v4:+Jr>gogz'cl,^4߮lC`T;GtF)R󁡰3݂D> ;a4la~V6 zonq|I>]bܿEE| )r>Fw֯uCA:)ا'΢PѣUZl(Jբr>l_;O;l],3o;}bC_EQA|`l$ o;kEڙ/tņFgETor},=n@ (r_TlhtVF|)nߑ0JPCUq>jQܶsWt ΊR8?bgY  +IA\j]p5W_aAA-6ZQ9xr, 0 +lH2\Ϣlt'_ЙT*rk翆v:!CA.JjN EvTe!Q ?(v>]Xl66ϽjtVE\ۙʆ=͗;Skgۙn-64:+Jr.v]وvwQƻ}: +9^ٰCA>bW.MtmZ|3AE6Te[6pR|슍a;6(:TjC\N2휱咍p..6LtbCgRI`zvK6>+6bҋ^E)i&X߇$P9ٙW6\۶vƶt3366Ѵ5-6P9+~ѣUaѶU3{yh3AE*Te`v}:TAήvsP;ݧ w%<ōePETΕAPnncC.-;_ᖝ$ *J5r v,6b#g9c&,64:+JerJ`f"l*:bCQ*sPv)6&Sܘ `A:TF\1d۹b#kٙov PD\9s ꖝ3.@~ņΊR)+tnl|U으)1 E^{bΉ`fQcr@]v Qh9Ul$jjs(+b#c9.6et`%ZFVVI+Ջʹ")RlΙ3A(J|ll(tyh~\Q:8ZVC+Uʹ")Tld/;$ .M=ꋍJ~Z"TΕIn/;'/@ +_{3xٙ Eɩ+EO٨F\`ٙ.@*(JNh}Qr5]_D\dv&QL0Xv,;K(|dž?O'?\ T¨+SL0QD;6|e}RsR~e]bٝb_ʵs4̶UW ũ/RQrXq&yRXl塾vvCAoi%Ҽ\K +ZhTΕKֲs^GQE}:CBv>*.q~V*sRYвظ9q팡`A;\L5srKtJ4TLb#s&(ߧ1n?̴ E̜o-JJerde&.@Jtdžݧ +lZqVA1gz9)OdQҙV?+ʹL0wyؠCyNjoHX- ;gT]Y̜!J. Cy?ZF+og|=(} CΟJi/{~2Y@TΕM f[6)ܾ ӹmg +beםf#Qm=^NIߊtE_~RsTΕMI3wx&/;߱ѩ]Mml~.j\c/'EIX:6t,*Q 7fNE /{+?}.S~ΎϵGQQbTO \vO)n>Bwl>桠lz]w;ix5<sege'cyI[CJE*ʧL/;s(ty_V +Kؙ _<'sS\3kdP̡/|!?CgճRTΕO3AYvvtQmg +6FV6;FDx/*dO$,bll] |IZ-:tgճRR l!GQPW;cC-;_r!;73s#= ?lf^V$/_΂%iV74 Z*\?gRGV/ `9(6MwlЫ(v%}z5|Q`#_;čOT̩fed+wY AG~V=+ʹY}[omg +FkDv(Ƃֆ@i?3?e?mLbNxY B|5 4+:0t 脟zVʇʹ*(0)6py<~!7 ,9;_`s<_!D3'lZ)__φ54;M~VYl塲OG3.٘4n7`e uYv 9-(95tB)3{Te)/V0'hZM ,=kxV* k&-;bE+tݶ`ӧLK+ oN糂G>E!_jgr +b^1;kl зglg:v♪ ϼU:+}e}>s7sR2J0|9!{,j4 C'rr +ETsb(H';;;`3N(qZЅXϟJrrmFYf2#seX uQG3ߵ;GIP3tP={fQ?JF\-dmb(|1l`w vdFz5W_Û33Y392LJ9c,1jHvA93<RwQ9W `^ +_+Yvҋp(-mHasBE {/KI16Df2Xeeq=ŪEdD󗾔ϩ%BճrQ9W gjp(p#w=_\;j3Hυ + I)9gf)3ˠ*$f#fleRI't28%>3;L I&C=9EvV*!g&mlYqPpfZHٹc6teJ\m ϒF6ye#'^/4!̑eH|ꩧf88/.mm mm|6>G)rznC9e?b yq{)֝gL;uvn|eg|p"%SEn?ƾ|<14g-3"a91e2LF6*>324G;gaihh64}70>Y9Ш߱kg=۱P˝;Y6ߙ6ӂ' Ϯ8$ NMoSfdYZfD|NjeJˤ3H }sι<}m>?I$ih14h=ϑewz +sATD ņy((v޲ Ρ]:ok쌥 .ڠos!z>g" g?(3̌2?t"fˤp2aÆ5:/̧6$S'l ?~ץ}Y=FNx.dr&2spdžؙj`(Cvc|KTxo2v6팱 Ϩ68Ly"eece(q&M\s5M zeSq&PqQ4:t紞ݎw\=óY TUF39n,%|pbi<3[1S`6^-7!f͚7oޢE1͛7k̘$M6)Z-X_J +Zm(ʹGb(!82s(ڠ| ۠cg>px#S缒/DOpd.Qb +aV6R[jݺu6mڂM֭ZF&L_) :݈n³_P;+ʹ+6|팡`Awρas;o۪ŵ۠ӳDJ篹 7|_BG'FPˤeced]vw0t ۷oSFfAs&?v9CϮzvvV7*#/ٰ+vγcN]:u.&VmWݫOu/ZM{\p-3eFZˤece;uܹ_t3N FV6?Kls^xV;+ʹ.6vC/+-^t\60D|HoD>?o-N!эҜ5̑)//3Ic'8[ݻ00ϻu;,m C[ASf?74!|'TvVjsUlDocW6xXXF$<_j6] `Ah8Z4mO/'/3]bv^FX&+'٫W} 9w^A#@s~ 5d's%ܦuePbb@'L8qInb&Ok>1O`Tm, GE!h-K3Fz,бR TlȺs?3iǎQm`k!n݆TгDJ>qfpᦼD66G0XY^duO{~iΙ ̽z!1;/)OL:uiӦM:e +\m,=(hch4t3vס޸SP.rëS9Qm@\d ʆ[wNgzg)-^ +X8݆s{vV6.t;S IMf+#eN6=wRB̼lxhܥk72-/O3f̜9k֬ -YfΜ9 +GObCCÍ)@;uK*ҳ9_J{SF4\?JrVr~.3|٧=ؾ`FOձ%gO0q@_)w剩Ӄ @ei˯fޣg>}Md8h0Č>C;'yl236|ѡ an[xɒ%K ,|xm ylh#FƏ3<S`=_ί7o*3Y +*%g(;gKƝw;TmDųYTU?J3;Rml,y"t3zvz&g]/5> +wet*=om, O{5w/eҌ}̠<}LJ,f2 )C֭_aC>X~ݺuFFҬh64=wY3ƏE1dPJn>>WYD, u9v~7yEV;sx9fL2lE9𳿲2۴iFxz:,h$S)zaxƋgR;gog6~gjo_n3&NvQ+ө&GM c`>{lmV'/)=m96xKvbC8v[r/mxvN{w[s;(Գ470~6{+Xh:|ln&qc~tКYql"3U"fxلeXN~衝;wa_Ow,}[H&@I|JS =u65mb35Ϯ8Hn,vVj s޾xNۈs?܈OF-[0vI?{33]JaXsfu63b6^6aVw~={|<݆ӳs1b;aEG_׶t5t GFx'_doHe.Ҝ3[f2C"s feae8G{챽{>N~'2<5$ E?!hK]rMlϯ-qA^P;+ʹkgg# r,FLhp3xT(ڄn] .] e-/7eyf\fPd^6Zagy}9|3i8(Q3P~x'~V, L"agYȴl(s]vy@[dyqcT8WOcieϞxwyF ]: \92Ryu`f^ˏ? |N&Gw[K]vӳ=ngT4:ųi.mgʹNPήڠ 6znB,/HnDWyC}Aб|Hr @ykfEeae_|ɋ4mr3Qolx<:@xؾ-QmwN FM\?JաrsRg7ڐ tT=zV>0y&_)%OM6Yڂ/gw 4wG`fFp~~wHFє!hzc+]z'&<ޥS bkX0ΟR;+ s!iQsXm y0&3up;gTrPc!CS##Eq)t*:C+sFx3uwHL3ETrxX9Vy'{Je1V-eFfIeXoI_Ip4{Qoډv3N۠dOF&C9@w?oթ6(<5|TkӲƂ83LY rCsP<ݷmz~ zvy {Ū"sT#ӦOJ +ݘOjfZglkfepbF`&/1Kg/ 4M&AKF~Gzvz; ?Qx=]߱] ^vI(:T*Da;_emz=hp}`y=nD^Oy9M6O&)CNx93_Ae-ܮ̉ȌllϬG4- Ϗ 3T@xyyFчܶUsZJ]dox;'TʾrSDvp, ϴLFRϏB&?^=*[/\o4 Q 8d;ًx/C.K3 _{͋Y,Je|&F&Aϯp=I9\myi|Flg}Pޕ*B\Hُ3~Uϯ̍?py+ahh8H$i5gN6^d]Ffμ'Qe̊^f+ ~>eI4׸xg3wϽWXs2;P91QBϤX϶{H&? Hdhh񼵱R2H^>_aJEf+fx,N5![-6 :3sg9 ncZE ͦjCg NۙoAb;CAW;}@\(dgp9۴lL n|}TNM6Yڃ/ͧl=1_\'3̌Mcb/['H6?I;C">nKn]8 *3| -H}?^Yxv `P +"%秞v% Coֈk#'x%ado +̙f2be#Z͆6 :/rp~]Jᙚg Raǂ&;+v֝y(qP9=vNV>+;;)/ۧL𒉈94 E@[ -~N虯7 TDA3s[ jg-6ʹ]mع`۠ɠtϱ_q~v͆[IKddكYS&xȄ#̴NT1[1[/wt h_EEOS)<;okwHLKI;_Fv(PGCvtZl(5F\WɰsyгwVg!ݻ|5IXp#l*2)fufgfJ 2KyxG&?Hp>DT +Ϗ<ٶe3B;T]|AsQx(ņQ9YnURn]L~-W#B?執66C'FS, 4i愘--h'o ++SMi.x߽woL[`i#3 ;u/} JP9]L=Hנ+֐tq2SEVĔܘ|70f9߳ ͆lSApS񙧤ڸwVgyμ[`e#Y;}:>r$礞9n?»|Tr44Z/MXf-OLɍ]Gkfs&v4R1=N5Rm<[X0e箝;mgۡ`X;gRQ9i +gmFgi7lapW˻|hh#icix:');/1'Nҙ9#2bNICO?8Ϯxx;v/mx;vnۅ: mYlLP*MΩ,s]!_>YEGI}oVv/'kJ3s$!UAr6|1*sܣkmZ6 u2ξ(|Q9usG[ȺlxWnD~_}z= +GIC)𱑲}'e~-Ksf93d0t?g,ga^ bk󃼴}gݣKvmZ\$ +9*6t& *:OfxN.R&+|hh#韐/w_\.\XY)]Y_{UKvnEvuݻtl׺lP_=$.64:+5G\G`7Iv>韷6~<>~Ϳy_Ռ̡~7?5(|ͳT=#Xv{)Ǎ6~0Jn(hkgڧb#5謔ʹ>P0rGsv#"Sh:@>%ȯ܋&oc̜!<9~ *_vteͪeΛ: +ֹ}> bC5:+5C\(Iϙ~(|:U$D:x'-(s ֶ@ ;c,Lg7[rm a=vmK/:?(6 t(ӯT4*zFq=wofoLw֐41=h9x$g.4yĜ!Hωn ){.mDv޼ajZ5m18θISN:^_`&Y)ʹޑT|{>7+h.)<cG2#s)fS~3g[mX;8}۷na%BCA;w}:)6N>ݱwqvV?{o[ + +MB $!@PbZRw~339/Y{?晠VgM&8DQQ+?u_JF##Y?5fg^o.<ې mcAW#x(;C)iܳ[vOGw;jgLgM(1fEggӠ=hAځO=ٟ:./ 4 ˜$ɸsXiݙ +ع^t8( +gNuVgM8$ן}@;Neґ_b*ph:s23tcG竤gNB5+.cgoax)Κ$QkeT-yMF(3$s&< 'H/ETQ6NߓBX0glK s6͆Fa Y{z(HΛ7`cEq uPu:+ΚDQ5>_̗qy4-s7mD,i|`mOggJ(9J6@Q5:Bp>U&cst>0+v|hlQ3A>'hOܰt8k$/tT73́ߪ_g'3ؠ(t<t,:':+Κ(ΚzBSs3?m痮>x.;:]Lu6^g=@gMRqr73 *iYry&HtNuV5qQ5IHդL'w7v 6gf;bwÆž;M h1&$76S&Ngoel'3A<'txŭ|L{Wȋ}QtIYzn<9q:Y`3[`JY4hn$%:ogtNܰAD1Y4dnmB:?<~$ +Vg_b^Sg78k yd_u6cg>sv'ts3:)Y8:6pcT\:ٛ:txyTg=b*iYuv΁]OGtxF:Ӯs ټE3NM_,hYu 6 u:<xLuV۞ڦG9+XWB+ ZfTDWgau/6goڤB+$`{&hCܾ]gJjM1?V5D y&HtQyt3^AE9uswQ5FlxƄ1#(G(i.KYNfygK`{&:tCCg(t7/tbAsQ5/1tu:bOpuv6^ ʍ~s.Nj7ϊF$BgLМD Tg:&H:O4v}z3AzFkoXR9ޯ$o\gMha JuVlu6^93=|P^x9@AIu$95Sq:йȊ(C_u("n>u%Z:'9/& }V5_B:3/l1Aa㰩 ̘<~4v߈:'9(ho0gƟt P(-7n D)T F#<_r Mt$7ϊFO`Wͮ3|긼M% AxDIF:9IhCB?GqhtNPt6;3ܡ(%W2]`: L/p( &x#J)w9,bfOt7ϊFLY&]DQFD3Qq9 +f0_MiW?LDqhBIX 6':n J(7TuN]A AC@ygY %LoٹwDz#ʍQS٩$ɷ('=@GyV5p⪳{9Tg {eD #Qeꜗ &,la\vI1s m98k4xǦ:AQ(( w:{f+e\PkiKtH#sn2YH +9 J( yl4dva6.[-ƘE|S-B|#8k4Q U;m{` 3ްa.=L_?"i32 ̎Ve6N~@q?6D~yV5DݰwD;һSKd:)h,كY\k?hq|Nsn SD&IuNzp73#:{3$4qFfvYP&}qlۆi0>ig&29 nF n:_惍x30. ʨMĆ-J{D~>sm(Mt9AF92n{;#9=uNmaK#qSsr׷зEi)"tR?ӤQ59AsA3gl Y@i&2(C`L,3V[1? >bMFC[@{>(<+MLbo. Ye\ _N;l)/Vf̶0ˬ3%[5-Dv|[?Q5V(/tsI[ossFzБҨWea*2ftXfE0C&V҆h-_#x#YqhbslӅ^&x02Anu6:gsRy-ͮAeQYDKίl@F !]e9ϕgYKF s;T ~%}& 6(J::Ͷ48Ñ칌,1wrȗ-Dtvs^(ϊF7Hu^U.^uu:`ÎF4L2KeL0eR9r^|ah&&ASv}0ϹCNYM\uvވb:k_&bS;au6`۾F1yl30{.#ˈ2s| YT#L4 }M#(3͟>'96g&6:BgչCr9M[6c\9eyL +3W 3L.e~G=DTqL7<˱Sg&>ɷ|? +Tv^gy7?lΙٔ,a .{,ɠp…<$)R~ +$h!M [d ox ?Q5$>[ty<+M$}#ʻoGVgauq:>|C`EIIe4{ L.C[Ae$\WP"/ ||y DС h{M7<9XTgYIT`u{EܼNWUns3;uNJ3\2*W@+W\Jj'ʕjB~d x1sg:5mhCqh'#ՙnEv mlxcg|(YG4-ivf?2 *#ɍ7iҴi3HsJ |Դi&MjDB[=xaن-i=P5Ip?WG/uf 6( +CAW篺sf3\}02"hѲeVZC8-jP&>?RotKf9tV5$ݦ3Iu6::3I 6*`dlW6E,#$vnrhy--f:3Vf?2(#m۶kӑB k׮m[* Dh*sGBm|yCgYIm:u :;3A`F@h#y91ߊٙg8DXffr2 *C;vԩs]t |wTht+ 42KL gl+F8k4ɒ:7lIt`VvFu,gel4|O3@fԘ frXFQnݺwѣGOH/ +>޽[7tfEh 4\Be>t|3?oE6NgYI#A9Tg{Æy7әgf +hLxu맙ei|_?PؔR˖+_Re*32,r.2ܫw>}۷? +>ӧw޽htgZ |ZRw؟r8k4HW{/_<43A`ԯ-cg`@ggi#AyΤYB!fgx|J4eL03.w'dx4h/|<`ZJbIh +fjUq]3e!KsI0Zj3ߔ$LjY&$ܺќmlmٔ`{*~3N&4S{y(2XT^4̀ʌ ]QF :tذ^aÆ :d:=KB3ؠ@ӀjVgZ36z.:+M$ΟK:xNlQ;Wsч:lWs }_N)4d9.8Ψ]^}[peF0Qe4yĈ#G=zX }1zQFA!L4 @sF4nؠ^]U*tCx ٌ<{;i$OAyDgmeg;}& p۹lBL:glxT/͙4d 4KiqF"sv2w֝`&eD=7n &LL4b"|4~q(h4z8 -@cҹcs&b}Qj ϸQO l?yomD'/Mqh't<ؠg[79cCAꌓ<8B˸Ix$JsMFA 0Ϗq!7V:+M +I:gxņ 6xc౳< >4^ǿ4!w' E3m5ͼQ'P6jҬyVVf@(OAg̘9s,l +>1ctD46}>7s)Ed,Fz8k4)$Au^- ذcm ^Z(Xƍ9>9ielPV6hgoZ_e:<3dx.f< h֚Jᨹrg:vMd.Ϝ( ,\hѢŐ%NE.\F,4=jaC޽zt>+/[xنW <-pb>MtV5T:g/<;Xry`ߞPW6h.ZIS!SGi~\37ܱSn{C2y<@@^tٲ˗?Y!//_lҥ"4{4M@c3Z|׷77:u醏gm<)w6|Bjkg&Vgg/y׬Xj lDLvVͤsqD~MCs2G4ϠI3=z *34f 3UWXrժUW^ |\ Rh"ZM><>Py!<תQ6hoÔgm'YqhRJ:{o <Ʃct_8w&n;CAҹ{6~Ժo`9/Wf?_K(n5\=gФKs~ *2Oysѹ~ngAtCx͍͛gZ26(}uV5T:(ʉxۙ΢.&:S28-⟉oϞ`dlF/9G7jyf W@e 0Qe4СÇ9rr >R`Th(ЫVX\}<׭YvwΊFj8tE;6dcudeï3l^gw hL7tf<=q"4ۗܛ +e1i}ri&E=p>e\q1x<^=vЮuR+٫7?tYqhRε!n`ovaz(a勣u[O޺[My>[E~e/O/91424JHT)K.93vf+.ˈٳ=Ob/si@}8ukVS}RLֽv^tnx0 ,G/^xҥg0m+ŋ4B#ǰ@;wlJ3>=G}zކg3ڐrFtΥFDUg HrۮlBٞEg^f\J.4 y@B?ψx@sQKsefg4iq>D\frYD"?AwϢd4% >C3 ֮^ $40m,2|xi/944fgl݆y4gF]efI ȫnW4BC 1txG 1gyF27~"}M(Zg&CI2ؐy('y֝='C2x]q6 R 4 +MD|KX2{2si6Sbiv)7lڲ'X=~+ .3Dk1oЗ91FС gNK}Ƈ3nn,Y`lm`yƵ mIs.6g&C l}:3v6+lu:=zFK<6g&i/6*L3DfgAONPSIḥ-8fg4e2ЗedL߄ ~&9DСh3=7=!?Cǂt$3ι=vV5%v݀o|W6uƓcFb36Lyw40}I|Eh1:,0diw}T퉓I~i?TO>s'YfeeT~[;65|&Ah4gϧN?zyޅ7yX'P;?d{W:-H^_P5 &`y(+PԹӮHx3댃gS7$4+hu&8OtVB G +@do 4FSn/oq0Cei̥HbP;A<ߡ4d,󌋗E˂1>F4h3gnϧN6 h.#;A s4ͨg.?˥N3HfhlPG_3A +M  7txSq6:WCF\o u?vV5L$ɶY|1<+sf e@w߹L43liɌ0S]Q?E*MD4@?s}tsy3۠y:;#ii#RgPG/}Md&cgP0xvS7AF9K,;`+/[c%>@Xh0?Y&fOfgHiyFuyA#@yf") qfGffa)Kd,,4lϗSKy>.mJ]PE퍨3;ۇv 6r:+Ml/Gy8ڐ}G&ekըVr +>|vh46B/{} +̦2#+]ly*ʹLq4S@5J3ˌY`]'3>tx =l<ڠ3?ĕ:U+-HݺsP7vΥd.t4ZO?uJ>+Ayyg|4X*N7ʕ- >r]ч hq`Fib ~p/}`!Ә}2@f0G| :3hGܙQfeY,{(.,Yx mZ}L3͝$w2=Z0`6g&;{+ɆFyo}i\ofAY}׷Qx nT`}~B_ &uARr1[KYqLَ#?eh^v}sf:)AfEZ|gAg!3-mtܤYwݱs. 6g&}(P狸Q@᝕wEOgܠgg& ?*NK+0L."sp\ 3(3| bh槀42se(3"g[ǓWg| +M里]8 +ܮu <]Jr\^PЌ%Rg&P0x3|D{?<60< n@}>AHt@ C,ؘ2Ӝdq)4ψ]qRh6sSwBB_6!hg4z +|L#δܼICߙt6+9wF$/>$7޾/KgLt\(Xag|4ئUM>8ߨ@KFEiP.,Ji2ӤK34͡ld60H#4->S}L tefMsUSFC-CFҐ&~*) }\`sfmuع+fgLaߡkO>,sf!?'DZR?__0#9s.ڶlX{PЌ 6r:+uZ: opxg%vp<:x`{vJܰ~4 + b4ztYtOAed]0׫sf(ss?<6Λ3kTgڵm>7mҨa] + =":m_§+W!esM4eڽG>Py[HW])`pS@"YxDxltGdn<_n0;GQg&ߡ g#up3gFs}IY?:yú5jRyڔIƍ5bsmZMQhأ15LZruA_#mڶ뀝[g ٝg,hL@G9$s8:ٌ?36C?t`u}iƏ1d@ߞPנnj,l;>oYqh3sΟȟ1gfflf ,:uiL#Gciy9m8shv1(?s{Kru Μ6iBlԯcg>ԿOgp PuV5MC8x,^xx6yJgn@}:X|ѭ+MD7mH7}O&MeqfPiL SiOC:!yF!_glx#]FUgYDlx:wcACFNyن-ϳgN:w-(tVZ"Ҡ4:m_6G[j՚] 00/M3qƄIS4ywN{|1)0<ψ95@xvg"u>wδf%Q7cı?`66b fuV5N:\2Olcfy ϝ-<?F۶i_6mڢL  iL )͋,Q= {\l. 8)>^L gNy[\Lu׬XhL+Y@}:oc#ת\RY כn[lgn@}2I|>th;wBA(w ,c_S`T5,HPggټ7x~GN, M Q#CLtn4Pƶ,˃ff7:33Liy<À2Osaکφg<կ󎭛֭~|yPعzwcy&8k4y*u\qi36x<ӣ58|l}0n^={=Pj +5| Ue q&4d;%4oܼGI+4IpA#Ls`_y,mdNuѺ3ls8vmgOWnlxwl`Cqh$Iu^A˻N{<>[M1|uA_ 8pepy$y4$ 7ٴfAûYzoB4>f5G9?y~;c4yQe#-CA;k@Z)b9N8k4Y8:>+dL;;=wضuFώ3gL@OCGBЕ eff̦iʌ )tL[:7gn4g˳S}t߮:?:a\8vӳkǶ- 6r:+M%ZgcA<;~xoۂ y˖" @4 HC.O'ByW4d6 *2Ϡ|$r9s?0ϟ'Ggڨ[:gV66;>]Vvwlв9'^8k4Y?}S߳/vy͍i۷ПWZB3g Ҡ)'3etف+3ΙYfgPiy L|]0~q߁]񎺧Y}oوiѤ!ECOs:+M&,7#߼| O7>x}޴a:z=w"= RS3@y\uy%~[D}:¥Vp,sr]sҜ?3g]KO݁fEfFglQ~&X0`NUgY-m8 y6{dx:nAo`޶u˦(d4 M>]@*/^.0o',88~KO<4ĉܦ6g2}: ]ƕ z(cgv 6pc؈z&LuV5,MξFI2㠙34V)`> 4t wx+t)v޺ 6(JtyLr:+M'΁8u♦lhޱ +LӾ'9} .[C2?#2tf'ygݹD5{4GO9庼Al3ؘm0񜠬IƪΊF-mvm#>"cPhDr Q>|2eps`35O[2v}:l 3A<'txD(dO"tM=>hl,4 F#Ґ#2e)>󌴦9c͝θ፝q7ؠ;6pY 9A\ D8k4ٔk<mѳL7l|@H4 Ht('d,g"26f2̾썚$i"Uq;; x UFtwVgYɮD/aexg.]$h21M˳2,P T]miFIz#t;|cgoAGQ ^vv u:9+Yqh/Yfdٛnx}sϒH4 H/S2,feqSih">;cgv6 B`4"MLCy U&fa}@>?t6cg30GQ|ew=ĝ Yqhr ͳ=}-Bl45G*ⲁٓٛfHi3_uޱ>q^Ó(!nsQnTgYɑdg[]-"4 F#Ҩ49}6 *3[Ed9i"s`.;9L;"չ:ߞYqhr&1:GgZ*4-DѤ4mјC{װ .KaL"ă \v:Dr:+MN%Y +4m6F# Ծ9sK98<<~^N'QwFs6Eqhr,2³3͟@-Bi&G2.(#);l$N''Q!ny`.VgY$ٙn>U|fB4JK~g0/ذl]0KsZEl3AS/u:$ؑC#:w~VgYѤijgg"4F&b`2AYgf3!n|' +WҭRg&H=hBZ{ODee9R`iC4'l3>t ^<{żŻ:Իu?tώЎl4#m|Ore9$sTi4p;'t$n9b?WZgFHϑ̟#fhF:.*}0G˜h"`y&G%4ΊFIshfij';*貅9JD9w_Auu!Pu]) HfhtLղL.{0ȜWilwvs\ΊF[IijshGhct0=0Ȝh"go3U1Pg&sЮ Ǯ>]2ǔ ::TK<;AucF>}B[ ~2U?sż%P{ruV5M~Eh餱ǿ`N*s_Ct7ΣbsܽY^g&P0sh#txӿc`Qd$'Qb̴ΊF P +ϴxg `hl$·:o^:ΊF!:t8_YeAl9b.Xn\6Yqh$ hGщm|E3A{ŽȭӨ:+M$.>3caɜ2MѤSB> _u'Qu: {ѤYLaCȊx?*;stXg&eD:ۿJDugTu~Q^X^Yqh2Qh cu_ۿ,LLu[дΊF3&ۿ,NUfCuV5tN,$:?/u̽(P/Su>9r9Eܦ:wVWgYI$5e3r]XduTYqhBz=Z9PS{VuV5<u9qq:4Iu뜓YqhV 9a#ɨʩ99(r:+Mގ8Aա.6ΊFsǪhnd:GۭηgsuV5 UgJߋPun\V +@uV5͍Tg:lڰnVgYɚܺy:?Yqh47x:wfsuV5͍pu{Yqh47zTWIuV5 FUɺ8k4>nu9"n_uչ-V*+]"'hnVq8k4?1yN;Y]gFr]y,WNu.8k4|7Cu:% hC2PGU:WV[~[ygFo)hE2VOxy^|kTgYd:wxs:+&$p_?tu#hG2]puYqh4#2S;\&hI:WWfCuV5M>I*M_uUcGwIuqWgYd}u.\(۪hKRί|@u^]8k4||_'sueSuV5MIIslΊF?WGXߊK:WR%ɶ8k4,ݣϒWgYhb|,ˬΊFGI:_VePN;"窳hSB7&λչ:+&?%:_չwTgY䫤X_W<='hU"?GQ5չ|UgFr}y԰A}:hҠWbSgFBu~;\׮<ӫέ:8k4|LTׯW6ɪ׿fe:+&%3yFSnjs{YQgFߒRu~5:T^uϱ:(ksqnަCph,I󇙬οJPgY~Zh44_)i&8۷|$m:2ݯwϓCI{J<"δN\/63@3Fv!fi8-MCFU-ރG>G3 @ch4i`m~xAy,OiL8tWg?W΅xDwh]>¡35Lu |h'Fߓ 3Ҍm8_U:yˆ5OGCe cp~ +o>S(K׵?+l':_:;"3h"{FI)p` 4m~U(W~/<,+|&h4&":}R0f5|gO8J8oƱ 4-y_h&&t +X~;o``.Cq~ܙSǏڿg(i]û^ûq?D+Yn>qǯyRh]iKyzpp]Z՜סxO'_} +kA:9nҴYPWPu޳БP .?x~57!oh4[h:vfh~ ϣ? řwlݴn8ˢs=ٮkdA?q[װC}\cƜX7lپkCGI.=,@ЯyCh5. +tfh泧N@q޿g-׭z|yOܨ^-ڥ{CwegmYtu z"h86 +<6mݱ{ìSO_4z8EgKXHwS(!OeLs=K_vm;ACG<_ hU5&r b`{e?gϜ"ݵc+Ǘ.?gԉF!]:Dlw2u;)['2t6s ̘=66{AcPg2sMh4My/Q˗!/<4Cm>uټ{-8/_#)Ǝ6J8{A +Uùkyܤi3,Xuޱ{;<% h@rYh9P@ϓgǎ"qřǏ9t`^;oBp. E.:{OiW:\5 T1&O5w;<?y +}| +\0h4i NSO$I֮^y6N5F2on69g7 MgkԪרi˶\;q.A7l޺}4 +}''iFIUOY3gNG{ڱ l^zr8Cq0v԰ک]x|p=s}3tk#Nz8dq׮ߴeyC(ӧi`FѤUκASNYH3f̅#G;~F14&]LDcǎI}КwBm޼qZy\зWFy]G G)4&}sTf~epy4y1@3~}zܪyj⌻#(>stream +9gbY#r>̃zأ%KU׬]6Zm7lԘh0mvc:DFѤA"_`֦M֭e1\^J +PEf8P#P31s [ ׭WF5G[തF0 ,7m"0k֨V'P+iy/pqMM5R9:{elu.Pm@y&+T\f-nn <*-4&  &7j԰ad\Zs2\">6Yުjdh:{ 0gT*T2 tz`ttCXhH[Hrzs5breG-P +[~#s&pՙ7,:w}}<%+E|&k!uiL@k4M%Hrj׮] YfKs)P{ g`3 L#sSl t{3z̜85% ]#oPN}aig*mP|;3 `i.0J6|g{[Q5Yu}p<5uƲ3o1yMEJaZ R155w󻕛}⼘sο|g4QӒLmQ 0+wWI.C@e3^;\+j,8;9;~6FC =M 0M-2l憚[n6E _qK΍ԙ +5;oԹ3g4 FK#G0 ì 3[^&11ivjvis݉|rm;S3 + MFI0jcm^+Ѧə́)mv<_<`L W0~ FK3 ì6fH`e2f$fcf,hڌissX3$϶ٳI?nME7I 0: VyNf٪٦憛M[sTڰ gg#h24(MiL0 X )FhfHMAèfYnCvvߨɳmPqs%h04($Mv`YIk(8xً IU3ThyFGamJT{6~ Eć 0+ ,Z/)iJnܡ$h04*$m<0 "3f#zوٛ٫٦Krvɳsg149%mxaf=pZC-A-5ےƒ|m M&IafC-/)g&3Wji47/.皝93g549ZڙafFC-/ٙ٫9LYv6zFg4,]af ;Ѳ1s.7/^sФhr{^ 0B7es55F͋ɹa0yznM6xafUi +QN-5/^΁C=M&E;IWfY*+o3j(i,)vnMvxafUi͚hZ f4ռ<7vn&Ϥ皟IVѡaֈ@rFJ]j^;ܥg1s7 0kBCoz 1j^9s hkўaVݜ~l|/.;z iٚaf%i͉&fc溚暝z~vhafir_]]j^L~9zaVnT;ɳtMmK3 ìuU^n~40:S/6rܴs@MEY7β\ Б?T7\s(YfY/t3_vneh60kٞkH%qs[>a֋.|yjNAYSf+Kiz>a֞nA^3+a^|Sfg40o\f|NAY#V՘yQA3 ü\zaoj!aRZઇa qպeaaaaaaaaaaySlon>>7m?n}?9L0IĹJR %DUDy^Ҭ{N2֙*Lt4(.LT+2FNX +BP1UFl q4Et{" hW2.RQq (q"mg,2 l^'Z +8tD\^ee\a[.JdOXDIpFxu-GS1?~ъnݎ>ڙ>hczY,rQvd8~ݺwo>n|;v}_ߎDvvEM{v;!/<99yOpI`g7yqz;2Z8G(NWpMfvI 3{0A+TQHNFV:Np,p)E?);.B-޻upqh#3*>j9cT1s)G?:ZGNg#S?LJwD|{orO/`4zrJcձ!klZ?4z 1WT1H.e@AOP(U;"OZBʹZVCi[ڐK?k5vpL%XKM]N>>nvuksN!JD"ȬFڵ*Ldf㝊!+ +RdҁTv7sX44tXՆH8ɤ.kza mUL'aeYÄX)}L^jƒ`AWɼTp}pc.H=CE<VŐA>bUAQ-Ϊjޝxstt+Ssr{_'Q +5&b2/|\Fls**X?ip&0rx%|^3X;J# k" t{tI E S[dEQlY`+)ձzc/cXgQ󝟜q~w,tcF[U%lYsֶq'M$/ +Y%p[e8VɢU5(%t,N)HtmN`{IlIuucgN?yX[aMt^P'(5VL "OʏCmFo:0 (a*ap VcQ +AM)w Oū*i>io;~ ,{:c:rރ]esQv-VQYd\5e{uVT %UT\lZfyUR).ˋǠBd_p+[y h| 9oR`M^HߥH؈lD6QǹV2beCquy/TJ猾f}>1Ġۿ+v9c1ÆdC!/ϐ" M 2NT@Hrz^YbOӤy-ŅN.btԱh'ag;\YO +|NSמl\;tjmuQL jsWI^ #j鳓A.; ފM'ǓAtFpj͇_q+? +endstream endobj 292 0 obj <>stream +%AI12_CompressedDataxYɕ&NCRr|4kZV#bX$sL5j^؜lfވ`24S"<3Y_~wwͰyn?O޾ۏp&7dB߾y7 }sǻ7?874DZL~X7?@ۏt]?J?CX6aq6)_s~cN7ڽ?޼ +!o^􉔗ͫ ˛_}*݌aҴܤ1&~&Uᄒ{޿?|O6?roq{{3۟/No$|}^d}?s hd/~5ǏtS_î}:/zC Fo?;}n%MWe7!Iv(ˆf$ԯ-OS)4O]L9Mth>L!mrr0I?To޿y~+YܜA~ۻGz-2q?}[D狏PG"oȔ;]hqOwX77w~Qh"Ɖ 3LfCS1MCCcbO-?ͻ*7tÛ/Oq37~?~{gsBiCFO[}5[FD@޾JZ}/'Ň70?_wo~_{M삖o ߦP~LNMcmoSۘ]#F>˿ҿǿmrM9SғF9ҿHA':&޾nscn?l)Dz Eƒ04-ԣt_z{.h[~Wbw ${?1w՟ozt_P~#݇w?'/ou߶(tGziG$16/qC!4߾}WVY(I_3|C +߼_}Nw_҃7ZIo6쓤iYny0ilS~+__a{^n|C*i{7?{uԘ}?|1+$qy;:a80b 0A +۰ p H!H6s\▞mORSJӒi鐎锇IY%8б||*C Q!R沔]ٗC9q14cq"w;xi04N4O˴v~:N9qNsyy?|Z%.,2-,ea*ۼ-qKC|_i{„hv45;]^F|f:V]ǁ;ia)OyisЕ. t֤mu5?Ъ˺Ӫ:Җo֞^okoWrf@Qi`T`4/tPӁiֿ(liKH/8t4絗uϾ޶Ҳ;]٣-ku-Lqڟ!!ܻζޖMuJwkt[nu.͞Ҵ||Y Wy`yűzlmmeXW^ za&Ƴ=p JF ~= v/A;rP|$J/,ND׉eז.DGDt:68#t :,{fZn"bBdh@T*DM Љht:i4HG9SNt<qw8GvH,{ 9DAj$Dem ~r$'*5D#Q'dJ$zHCAmwD#dQv"dݑ`pK3[n0m|4#L{/|$|>I[hcD@zG{?O4Ӆ}y@St$L:8G"BZ8ݎVp!^3){PLSL|@iG\j!n5*$R&GlH'dDB|o"'G i x$J=]D]#L\5޳Ώ[x7g5²ue}^kK,խkZݺΏ]۫+۬+ͺ^_ٳuC8=4ݑ\]dV@#.ZZc0%VX֗H7Xʹ(S!?L4Y~ 1AI? <$̑L7e؄a@x1w36ynnx|zw6WL7wwo6J5^Sf? Q(7)/C39\/q66 < ex8#}׷޼}xIi!1;gXr8:lоSEX-j]E׽M>jެ{=]kDZ4:Im7?hvC3ZE,ç!۱G0Wd^mcXcn9zЈG^AJMX|[ Üf}cà 0p"F{vz ze7 (Y $sTIFֱWv컫Є@FLI1BכXY(d +Bc7(y;u'9()ncfJzD?$8a/$uF==wϤw"Y3Oh"t?*%6Vu1*ҁ&HGh*%HGp|.:'=+G`Ç !W4SMi H?5tfJtG:iC4 A20+;V~/|o5V*!᯦~#?ցmϏGc..]ͭ\U<ܚJ +]VtUYn`̛{A|m`Zk:LmpN%EǁϵO|hSw9`:gW_B߈5 nObuvN^ *32y762mRl +lQL \tG!/ RlBvL%rP>Q%o6`G#.ksNP +u!#;OMʻp \d$H;#|(A#_thKsI{?vͱ펥9p,[<~Wps,pq<}ruNh +^VZ +VtҽLx,>]5-PDTm5RI^꺩Sw4mcggݵ9{sDiw34TY2lI%aIP&j1ooZԠfXѤbBEW#0[Qz +$BV,ce7G쎋r!9^R yti01iW'L 0Pq^rPL+bdԥD-7Q~wkIƓg0d$`=VU}qkcxu$١)I%%hk%6$eǸfs,I$5hF$}DR$Qf4C]JdI{ź% %FL={3|xbi 6=>6NP-I2&'n4Bn +(O3mjKiqWLc駉H!Gl\)>Bd.eJ!)D 1v,CX$WH'МRPG1Ε%gIhR7>ϔ50k($ ns'->J%@E>53*R5pYDbF#H'oPPm7[fOzeAsp׸[ɶb(.̒G(v&>͌2@t.xrcu =eV^D>0f5aae25#LДYp}`I5wbV; }eN J,8Y߸#cb#wL. c6$؉ b0= +d p`#f:70;ٖ=.~=+3bJfκ- :[=f7AIJlGFA?3Ѕ +ھ8$O6nwp I؟ +aBl3.LHXw8 ^ g R_FPLi}X܉!AWӬZF(ʙte8 b=>cw](Pfoa:82 w|?nuyafHiYC 3N4v~&d4ʱOHEP@E]Cp9dBk_ۆ0X4h/M=IJMn 4ΔS5l;#"ݕŒ@G(()èi VVzjx5.Uc=έRl;tv'Z٥lYvf[M\\i 4ƁW7N[^̓ccP/# hxE٣,}#+=m2^=c3G +OJmzi^ڪfo[rMiEDklF&MXv_ogRo9=cy5 ZY SGs%K*LLFvBVkZ^cڈ聙;8.ǫ@_kCJ͉kF ĝ%A綸YWp@-s[%~t@1K5 xH^# b$eG5;"$Rb ,@W*Q'Jn$v+|REL5T =b¬QQŠXZ:8?2xh$<n)qù{\RSz Kg$rSz/%:Sc=&cu]az":kuչW b5<֙sI*V qeB+Xb Ljro&#l?AAjYY}h΀q 6O{`J{-,u`,ڀJHp%B;& 9x3Id녕9u5Ã&Ugg%RǬ㠸[`/pxNl~fl߮}a&,&`,rؠkYyR3>j<8(whzVa6>C#4hѳ~YFU͠uLɵ'f*G)J`='9{o՗015>>*K}Dfn/'Zz%J.u1_yUrqGIB.-.4YPy +|-FPp0/am#̴4zXtW1q!4 'OF-OC\8IaQbÉ~᱅SnL4" +7w~];huPL NJ9Vڃ|H/_hfV.ӔRYۆߴY9O4tW߭W`C *E~=92up.fΏm= c^1^8J=4b_-<3Jvv7kؼ +]XVkչ5kwmk}DM5ϫ^_p^}<(ֆp.`F 5s8vO؅1bUQg #sg[4bx1<@]i^iވonh _WaY߳+y`N!W*" 퇇L +v# sA/zԝ$[ZTs֯uzg;N999999999999?=-kɟVC,j@cT__x1Ȃ,0(`%XfaKWg$ZYm!,fV" b&E3o +?q'Xڐ\Td/۳ Ld G- pQ f(hhj0Kg0Qg +Ai@jaV VI +>`mII35 5$'yHΨ%(g/>~,.vpi[ #נ` +-##8t9߸Wpm=C0͐mmW&eVa슥x~m=eqkHzm@9_T?MuFq)SXɄ_ 57mle?5 })7wܬ'sY83=+X`5x8u0Qk2:0N[=,S-\50YtD쫶sXX#8 m{=ԏS畟>Urlp7WjsƎzs;;.F +1^8ʅ 1{EMΨ-i&*)򚽼kf`2(ׁR!p 0лWo"TdEJ e\tC wEd8]nбP? L|O2xO \L=:Gu!GPjdF8Z Cf6^Q˃Wp-2i\yxH'"[ǕyPqZm[:ڳP1e\.8D3t :IWfl ͥ1_q#=xxDʂUZ;Swe?=Wyq?r% (ld0v9 o 5 S,8̀0A a%jnA O #qu^ʺsKr)?<`t{N,6}(1̫}wzO酶Rnlr}`C35RilE*`ik^r[Ͷ<:ܖ8/OTah=FӐ 4J'`J醴6 h`4he *Oˏx0F*a :]+1^p^z7GM_8Z|>^zKՂCm|VHfG7=jusfu5~;uV[pSl؄py_uβiܑ5>{xM$}E^.px{>9e:P,1ElpvގMRʑC&\fn]R[Un4M.> +R<  ;/)2".-he9PH#%nJԹ+4_}&kQ}T좽va4%.jEMqѴ 7$c2PߏMJSJM٠E A%p)Oo03X_hp FN [OɭFZLFd[۸6*j:6i:o06gHfD` ;}oK=2۟'? ڗHmp6T o/&ܾ __,k{;6Aզ4CŽrKFC̓>XE[r͒5rz-b,Z~ 9zi\kZk|4 'mQӄ頖\={-eQ$C88a‘Ik ϣBaY=uQ[[m'jͮɑ*li[ͥ8`m}gKhU]㚝m[ͦCUKi^*uXW[Oӵ&vusoΩ+̚{3W˳Ccm[Otmc#4/u4Ox?97Ly52Έ@O~PKhD107wֆq0e!^z \9Z24U \brJ gѼx_ɋC{ZOi_b筿jfcܔhACf-5ՒVxK +â-*wyEU9b;}䍿T3,Yu`4nVWp$qpe'6zRwSutŧ V90$'ݽ;P~xԄL 47?Yik"%U,V(")aԤg߷b:*HӁ'S㤡N68J%t#N*Iif،=m3.I96 3<6!(M``4{jt/u" ezMyU=߽1M9ISG!Z=LtZP4 r-y0RCEq5p;ZX)祴1l s+FPY[Pxh0+#w8˥瘮+` |:> Iêm٪'dve֐s. W]V苤Pk0pwWykiQ/Հ*m^ ^ v{q<X Ω֟FV΁ǯŵgؽG>e;MVVnk-{|+O^,_V.g+OhąF׎=;hΕtbPRja=\ @n^~7mԵ3uI(<ݳ=]WzIc< ,\!4z?\} dw#e8Y F3!qf}'metlqUfP^[ vMnHKhG5VQY=UbCVqVBfEA:6!]C.hCt>$p&֧T9Վ<4CƣMPcZq"[}89 uiu]R]3:<^ ֕VYVReUQ.m([j^[U* j*ͮ2zvYGթ$ղt@e;Ff7JmtT$^BCIŷN=aWle!WMxUvuNQ47ZliqK\]{ִ!.m:-ɞyLԓ^{Naeog/45B8񗨽m3LZrZ+w68Z5n(rY|FXs&UƵu|zrn(*yZ-rwC>sG=`,}0 ,sShj :p0zm=H +5,oe_HJ hXGÜSCm8\=H':d_DsJҟ5МW5X)Ag#MmmJK%UHL 'zYbR)mtc~t&&3 7a?hN~Oc߳I,‡ӈf3rԺ%O!D?ӈjĹԘghP] D^dP*1V.V磗:<#RIkuy:}S}LGhXK{Y~Vcͷ'VoǛ[b1J[n--,oDkΚ*~p9mXbG[V>;*c-q`dGt#U.:< 2e@-e$Z0Kꎸ:CِW!gDޛ Ǫ7'<|l8*)rA#O?GvEW6F}62*&{Uw_V޶Rf1-?2-G?sgʿy׺<~ytZ4W;]97#6&ޥ ؞~=^b`B줤mJ" '\Nc=$\>4\O57R_oLxKX!I [Y5ҭ,j+.7yvRw%utx>>qP#v(YI)pimay6qQnax4?&F䟸{Pv2j/Y0%ң 7).ӥ֗i]m} +W! +UnS%',W'Oƕ\–;n'18]/8nG&4tM+5WZ:wKM^p$RVG. -@Rf# c)G6--iWDb C + p_߇O$~ﻏwwDo÷|otOX?Sj/95h qeE Uv=3h660ecph/4-n!ɛxQ@D!f0h!m8Yxǽ>>R.3__|xw_zn//_[ǻh޿}{o1MM)ɽ0ߐ)K ˔6io)?#N~ ?~7>n6_OŕF|g7cw1.xo?~xxn?ic?ڽvOtv8~_n_;~_޽;5s도hp%$Qsf+-YDv7I0OtmiH D7L);a$j/t +n +ZN@7cΨ\죅aąD!f b, .<Fw>;In.$,,x35cP4dh3@>ti)1WMF3m~ī9n^GIY +4Ʌd"%rZtLL.w%Ɂ?Jb& D|2 RA 4IoJ[iF$BO/-٪'+YɐG[f"}#e!@OFsH@>А6rCJ&/4]3H5b B+bltzy3 #~D4Vda{3aC&9ÛM?J/4>-&7%)0 4&`M;YФSsy~3ɠOAM17)bQ7Ĝ=J&@@K= .' qL ]#GAG>U^7He[h]P&% +(8+zSjů +H!F|鯀6az}ƹZWHiĒ@0ZLÎ >GO@;-=4m$7'K᧥1DsϣY>FEVtN )4PXDLh_d˄)[GXĒi1a$Y!cID|@@ħSSKhiOJH2?!Iʎ\򺠘NLh9;+)oyn0T303AqATOͳ*~lq&arFKTOn@CѦ2o M8"tVj ~/9؊BG WC(r%"NIN 5i8ڒ m&Zc-P =?4M &6Ȓ2z>V2/3CH$igbGlhp8$֠ЦUN]9 NLml-zR@@r"=``ݎ&>>Hyy 2D34[,Jnhb=2M{R6؎JX&u&,IQ-)G)<<}'fnbGRވ'}$3@y'RLҀ0S? jJ?v$I06XTZXЙ(D[l=#FDX=IuldD5 b3َ[)x ¯a'M#v]#j[Msi.m?N2@Iu)HU+e*Y`r; :)xU@Fqt"D6@TNZefJ2<ˆ@S.(%KUAL_sAش;cM;<ïk;,j~"p 501s̡LB:Zjz`3HaiM 1$t2~jʸܛLy̲B;l/~t&_f +m=x\gnd<% A~4 ݇-~~J1Me#t>3=D*SǜtK! 5y 8"!  av: +Zf0 Rc%X,2krEb^2&UAGC캈$=}_`-Ⱥ(}_D*[G8ܕV&f8Ɍ0uB[)™Rxd53d{d5B+B y +-9f'@gb R %nzd[ .;v +`* ޶[ְޠ-tҐ!W ! `4,hi$D WV; +Xbeu7HZ<(tzb;W1 8Vtݘ, +qa@3T5;t1uK TtH@H2/iゆq[QD .y6,8V`no .Z=g.&Iz?$/kB'td'<BZ~RϘ=P<ۓtgF%)t'Pka쪛řeC5\\>z t`=Nq3U AHTgu*8acfr ɴ*5Π@qcULw9AxUST}~m vƹр3䚯dGBu>GnDpD1H7w!Q_S"\\riY}ni 1;ưt$NuꞚ0 غfEʤAe0k+4>Ɣ n y<-~6c[̓C-jNbjp9~ڞHSπ"1JP\Y5/x Vtw ˩`]q'~r 5PWq~9nӆCgk"R͈18GzuL)a? +!DU2s4ߢZ^nvl?*j,׎U\XCC( ,6Vrryvro{&PKM^8dre!&w9. w/1R}.iЋdEvwzSiAJQz-CҙViNj> מWԫYSu;qb>.Wk3sj`I皮\v_5_k +^]HWYij4{}fFw- sZt1o[7 횹_K^Kvnù[7}V{ptGxo`u[{Zѻ[f!WgJ;j9X$],#'irCoh6oHSb+1l+]1*VL"'XPDbUC\eԡ 4upշ0H|/0N\T6DW@/_U5.l!!|KMomQ;=*fCjFDCPSj"Hs#2_xiIbĵffvF֌$ah.DdⲀ^@jc ^EɂPᤰү=_8ͳ|+Q"L,v~.w(|egi3zni 5MC-lqu}l `|L "{(T^iO# `۟ +cFFtpO#8Ç\aJz:zӎ_է /88lbݝM H(P~g2ݯu z=,AVC|j"]e:>tS>ӭS4ƻe!$"Bz%6h1X}a?ȅb{&NǢY$bGAge>H %")Q{dƙ B؞.b L@?ԃHIOB*s $*M> #yUx,U1]/$=1KVG0/ϐ/1I2iq(Q)ɥe>GšyŜ#dP?8pşVΔi5zF YAcmrxE~T<̲|N<||K,Y? DWihZ|FCBj mi+1‰%3"7nʕmUJu&|?c'ٽ_6u\Uvi6U&έl+G3OFgltm__cr~=OP*Q>eHs04]0ynMRZn藈@k"Y4qWpHrc2϶T85ADq)IYDy,:)I00CLˠ('A`uŁ'"qrZi3Z`@b1X,ieH‡9Mژ}AB-禲 1-n 46qj=̜$8OΉ0(YËA!q+="ҙΖt_PYzBb u #Ug}o^!Wg,INr#},>l +$8v x*0aŠE?Qg`2q/0H-HH4 >Vu}}A }68 'Xf~-"l 8|ƈnj;_zs̷̒XPs,ފ:mTo4E<w(<ۺ'y SFsKWa cP2Х41B:Fm"+$'K7ucR4[OkC+wUP'~˻on?} fRKe$#Om2@TL 1Z-ĺ*2XEPWd5%@|*V%:Vd2{ۊ 1OyE4[A"0Tz x¾Kx+1D89f1đfZ!NB r 8_ż]9LV(-cEI1p}Q9!?ZYPT[=(0TZ0+B'ZE~V N#/nEؑ.د]? ҉&Z%ҿ:hC VgYL6@q/j8_1g^9  `KG+3Z 6@9Ɍ {^HZZۊE˹WYzqUlQU@#ٕ+0{J;qrm2%^ԭHW}SLsҼ8c -9 A\{Ցn=KdG=|i%hfQ)F6hQzi lIU;^;bE8iGq-q`fu{TY=HNQ7"ݰSbbL/?KIц4Mn4,+WW*5^K^&{i1kPdM}f6)N V\4PY)t#ͳ&kw5<;5Qm)exnt4뢒ҕj*YQ+3=V5ۙ3e+y,Yߝ)4M25f0!fYT$ú]SԒY1U[X1!H/"؆]&/+=Zi]HFF4+fU\|2EhpWhOi%"/e,OsX+t߭ >]"EY.ietj.F+橑=YKttLTz P#XOUsI*M9QRuɫ6h90=2.دE+{i}qzOvYUhI.[<ŏ燻]yƹK 2`]-@:m!_bxZUUI)$gW%JVk@cm7cwg(jXX7+q +N1G9;6X1+GK9ڳ=G_;:@kqܞ:a׎\egAtp/@䀶KýDWeK8{I舼 LP5p%} PŴ S*XiyA.Tzt sT=4+9BT̝Bg#̽TBsC4GsWUKS~9%EڛY#8k:!.~î?7Cՙ0NY)չ5)_4.!aQ|"==U' 5Df]-(Ӊk&Sh[uA:-4RDzb$]Ւt~@9{gByTu"C ֔TCiyf ?Ӗ^dMbj +CkYI@/ԧc^3q<8cձ],%׬U8@V`NMi1$, <4J>˯|6ǫVU?1=sGr ۪m!?k|ZA!?p:ݶ +ZA kPS2{hrϜ~>6¾6@u=8Q~ + ,͵T l&~B-;C7uP Ua.ki,ت\UQ,V=V`Gm -]%8%`qƫWAڜ8?8-P bɈW +9w%pZzA @u mWwEOx̀?dݫ&K9At'}?Di}G0]*k]TzxRO ğ$|>$DžeJ/oK_#Y1zˮjL}6+/SJ패:#VԩGB:u؎/hWJTڰ>2@NmV. + +9e*>o~twτt-g :w+d|_IWӜ,1zq.vHW5g.:4!W sѡOEv4Mi@V,:ʹ^lZs y=  phkq*:ȁG P|9).[XY+7M*قI'͓|28/f2KzbኍP-+_ +!1[J+JԑDeW>ձo.{vE1X:ev8"X͎PVף.hW|Шfd?ӣmF>%||n;[GvUFV̤06&D+-mk$hU0fc^l\{Z3HyN`d\+v +f?j̠p`6¯o1j3.#sOhW0C Z՞T(f5).,0`!,٪L5̸ib(PY"MZͱҵ.avVb/t>ᖐ]3r +Wy*Y{ꗭ˗]=LT&.4BX $+R1}n}-.Z"{@3;ZQP97H`C3Lj΢3=x4'6ZBM4>ܔda`b& Y| KJ|&kk(!+$y"f +h !@1"吐1Q$4F$ poY 3&rd{b=X$usŰ= À(..܏ /Zp"k DHAarQ;DiN"Yn \=F h@HԓbJ5Pt1pXMQ*(PH2jG%Rҽ=3sZ~ֵ(!w6J)H)e)%Ѣ+)Au}O Pv)p+c_f)qj'0.=j]RB[ks).ݻxaBPeQUlh/֞L_]zcAzhE;-NX748 ^v% bXniVa` p 2UXBBb Faa jwG/;Ongi_-a"iImEVĆ(m x iJЮ-Ai@zD\cLk.u 7ȊgHy89 Y9 L۶6Kz:n=0 djĩ %pZqhe |҅u.eWZCȜ- b +ejDBjt#aC~]bKc\7rL(-#-1dPOomՓP$PBeY@IW92}%^vDss(K&")QvӜh3ȶ֜31Slzx"^Zr%82(cu7Ja/& 0,W)䘋JoifX-oi* GyUГ mMY!xքzh^:-#+[N]c,oyrr.smnܟ3w!%ӯ̜Ɯ~ڞvuכ@cM)o5?gxޕ_'[!۬ynvkoe[5}ݽӆ^vjVӕ"'uO޼i\> -}_նںvEkn˵c HmnLQGnl,7{]НYztgzxsho\ܻ۽\.;u`m1{ѻCֻx.9q%*e*P\J/ . t0f&N)M{U8kυNH SY0KgMKUKXiRxsfѪ\%G v߀q^#C9a +XP݁-xbaꨚ+lˁ}-ރ#]/oq½]Pim\8qAc^T!29ZG,A̅?슂|.'G[;%#Inʐ!JcOtVO%zs Nİ Pf +dE!F">`ۑX_ zإF!br[FSZ oHZŒT𪛵\uZ8I4Y9v< |x6<z-q*p- +Dr2݀W'7Qg*DF^ +b[& ʭ!Z1S3Tg@i^hBn3{# /¢DOc2 +˥Aq綍ib3|p%6oԌTS9٦x +qшk$#eaE9MKrq d:"-s^Ը N/\Ge sQ3i̊zZ.1挩8Gq'׸=(d-h!D.:2Dt%"bx'nR(QJaUqEJ+kz>̍LH1N&M3x VZX0Ѽ Dj2_^*~浉fꅪ\`J8t 86SϘړU+Eg4*sTj3+elH+nK}@#\YM]ę Mȹso +.t25 vpu˴ތzpKӣ3Lצ \)ڕrdqkdf +Zo[l1AnU rgطU;% ,l +fK p)gTe}Q6]T"p20-Yf;2#0ý\f'b9ՠHsL 2o<s{؝dل0"3Y,vl8uK"txDe6f+1jTYs$ufPU߷1.\P~Bo$>=unC->Y$Lz=l)Qu;# +BY- +쨰OeК5~:swU@HLpP/>SRFTlvY}||+>3G2ݮ`9uvZaQԨ—|N7lN_w*hǍsȨ#"XέB)l\~e/Hzuk6fF4sAb=&>UB]a#2 +kIYJp09V > B{*@/ "51 %%]`$iUPZK24j4L $?DAz64( Eb 1S;"]QSSo\.g`:a3[l0%(%W2cťDIuG;iSt$>%yNk嗈 LRgم>94>]oj:]-{vU.YIhc3\z}.8VFcI[zp'q/1-6BFhsrAIԘpp-3WFͅl7=V=m56[nn+E rDv+_G}*4jJxk\IK)}@ QnV<\HsϞp^QxNPLXAqĚpU;DqRjGAZ 2XD1Dj`>y) VrS'"1ת G\A5*F Ǚav'H[~NjBە  7}io̴D!\$dc!@>L.g2%5sny?'8o4i_ĵcORL%J-I6|qM9/L3JWһ/!gP1;6?F?k̯He5mL P9r PcWD?(5KFp#ހ۹QawwJ~iJz>f?N4)KH_yT"H(Ў"=.uI2$yцq a)a}e]~r*%/{{u]$UkQ o08{q?}  I=.ގ~x^~3޷~rN w|䇐1V8SZIZo䓨G.CEPOqWDbTᓎr%ᔨ䔄8Pn`v:uJ^OS:oSBJ~urJlXVN.vh)尟/NIW;wJu>I}O>-) +c>  O'8kW1]|/i;]LR3O 9իc?:?_n1Y[TRB6Ah.!lcjff(i2RRETf |KM*> 7s@e~2\1 HȢYC^k7 OBTsYCgcMs;^;V꩚DMp' +Hb9"`Wt(>$qH/MKi}fllݔDG7ًɆ'>@aź(^WB"vG,TY}q*a6|ؔ?_s!6(Z.p2dNEUe\w|{Ȩ? FJ;ã +IJEw8OP,`Xȝ\_p XRvK`, (F!)(4X+PoѭTӓּnИg`t-Ԏxu=~TܗmUӢ ӍhCշ^ E[GJm֬`,ڐTE? ͋6'bsjèxJ9Vm3ڰ mrՆzDc.m3jH2jic%1\ZjUgAjCkg;6qت]A\Z}~lV$3b]e=.Qc_c!dc`;C1*i-)O;a!u)L.Kl߯?>Gx}#WՁjk4MuinD[W +±Uq22UQP}:V톦$L6q^D뫶fC1ڭP>w]vE6 M=W&uNK7=M "X3VnNs˶fD1uN9zG6N. 7G,gp7,ܚb ʅ 7KؼpS<f,LI4n*s :.<kxMWd9n?g_`7a.9 (O-ˀdy*L(fPpm"`چu QE@{2" LNg9^'hHGE@NYf[r(^sS, +p"Ce_E@~:hFPKoT9;=CU_ +ku4sx/~8(x~R +| +}񧜂dt_>*K9_^ȗ'ojd(9_ֆW-=_T"|9u=|*eE2"ς;=M2*I_ΖitٲBdj(aeKlY'sty-ސe tYf6?]tyŁUtyPdJ$e)\Nftma=_N)'+^>̗e#_ZU2"0P/#ž/'Sx}}G ObamUC;^H@#FpvIwcS>inPУ;Rr':5.ˉЃ6,-%j⁾kȗJBb̋dm~X ˆ4DZTX8OR +p1FTﴳٵRX7E4%P*A)9fW]zD i?#^aX1Nuv +D:ԇi Y*(ao{I6q +  7' 47jԣ +;IZEJ9bfyEB^b"4"b w?A*:$2q߭>)(0WN|9&Bb= MWҹfW IZPV1>$7{noZ[ $-}YB1b^])z؏5(ZjeKL=-g `1B;ZpAOb"Q,&X4g=K]ihF)αmyR+TVY;ށ+~U"'FNzoDTy>SP-7laXPk2'痜vf$*GO~"3 +VV@nH +>'tڨHe"kVzΉW2wRPcW@ID /kR)1}ԗOZ#Clvf/f0RNT6rW|ڼs>2̆qbHdW֛p5BႮ8Qkhx("^ZDe%^FUER W[x9XvW}mA(a+ׅ˥*{ nr<]+eoTbAk\oOP56̾rlʆ6OzjO]N\|#'W.ʻǯ-yw(' 03{nLfMh}.[ݽnS[W_UEgA8_ΦB*bgOl!u1i~2׈ Aet$ì(q8I,`R)pW"P4z0YHc%9=0Y0撕^΅'>z- V5Djk,6k"mwy\&;Xs~e *ؚx^863V$zFszD& W@R@EMӽ\|Kf6#%n""fb@."rFԯ)g!٪.d/\4e2][Cb=p/٣r q > $3\&lI0O,jqn@A +Jz6Sifj˂TuWPzȡZn#72%] T ٢9!T_Dz_hē~# +֩wye"Hxάz)6]Ndȕt;" +ҏVZ:a#fi1mEIC\/T!JMn奜~0̿<s"5&!o~EaF?崗uܣ6FW(}EA0_ǬNomV*d~YkF:YLͯ8 GavY ϑ5t.Y PV]ee9]Z'חtYN7uF}2R̾a4jGLm!Dܡ +%wLÔNϼ[u)rsaݏ)oڶ3vW{"$Q^d SQ",`rE:gCF]+lbF)&3j +GB%eag5=ӋP^FTe~Kn*Y[՟T(6*jG|ѯZO+M? "r SZ3Xbھ!c ZAC8oxYv{BQjXU\VF|^o)gns"cs5ɝL7'cvf¶m8RO~̭Lb%PJyt<H p*|1hs,R։ϔ0[B\Dl[n9)O^ m#_\W?ܰ_E~K.Hf!| T&[gɟ;),'BQRz*qtJvUű|ܧY7 zZKă^V(z*- +kj́8@!f.a@KY T*ȣI邪]j9oB!xR#Qal5N]ƃk$" +r{^REqd[;BR|6kV3G뗟xTæbg5]\!y;'>roB!ARyTsEQHoӘ"5s|DK5Ғ `EDX[?;a` +;ЊKR~O*eVݥo/>f7X*'àWaɿjm{B<}v9|C]m41_%Z ;WnTE>-Kc'3h|ZyrW:_i~yK򓏻aC1Gi~s$Oc~]+tO'NSh_biO֟GsX?GsX?G429292``O#9#ϫx3? ~ ~ <79796ؠ`0`C9?l415```S9ߧcXO ƴ<59595`` ~Q +a7ꊡN;7|rxghW7o7])97 +hqkIj<מux[%lɍOn<4n; _U~V| +2):R3t +Pgx@ +uUtx2 %rb@ +m΀ )^B3 6Cg@ +mf H-I.)^B3 6s̀ ɀ I 3Rj3$R3$<# d?=qP>4b@w*jˋ@ + OǞia IG8rȹB%QzƍGA3M(1| +eW6w6.E"!#]UfN|N/@L負ITM ֆ2ԇ|ڼзKttLz%v_hgϿ)B'DARi7nzDJͻ vCt47>֡8{%?|9'SzؐjTv09_5v. vvE1W'y BfjIlPfb[ㆮ$QQ).*؜ţc{4fpyrN;_iyKK?ƗO|_iߨ* t>4~(&+0x{a$yK) +؞DEl7rZj%Īqͨm[14cY†dsj6ˠ`XH +1-W1AtA/(ɃibٜGTc!*dz8äiK>7'ffCSm#ITS 1OaYG)c Wi]s>,Fa3yPcBwt=?xZg"je$FRo>C*x0Y '_ p6f 1d5}3rM$^U=\OOji0/!Ϩ DYc~ \=i.r=}T)A%;45f1: /7+*NG{ o^c~휂Hf<$>=WK?Vˎ~P^5+TL š`g%O]m # lX)kybТW֞+r+>p(Ƕ:ktTj +|Veٍ'ˆ +kfc3Xa3ÂcCeN׽ fwg9Xb2XÖX In2^3om14rRW JD#Q/n<,cAvW'CH,aSs1I٤>WЮ _{3_7omt%m1Hteqh͐_1db YtYu*S¡t"9-NQ]wc4V +q"pJ@Z-,C 3sý{npBS%R5$(\y\3_,@+R|ոPs\,A#ӂˇv6 h a#² :XO^Fr_Bq ^Q)ÃY30j)U4M~ck_u^j~Av\3m1֒mvM-0=ScX h t٬e8.Y=wH-Q@lHH]`i5yzx]M%4֬ oJ^^%W@x-F`l4s(%9g}ZBH[nH9 w~ |gu-@~F`8 Px1 s{q|O2 IY JlkwK|ym/oE`/HF Vd2䥤bҜ)bq_4;W͟x]U)(\Klr.K }UO˼96 FFGqL47)IsCP=c&f5>W:5@nXf㝇4WЏ)Y= O~q$_2,A)#ו^{Kk@~'d OƈNw{{]k#H׭E3(;l{W'f=c1ƞ#Y`E>#wyI{v$Ȏ?JxIt /0vKmG#;B sS4'x$5"n#F)e| OQF1ɽH-]y9;f %ڱ B&坬KT85 89wOXZb($]*߷W>{oliC58ȼ{3qgOWqD[uluˈxSK"N}2G`Avd9٬`ʄ;^{f,H>F`L(e>Y\y>7R{.kӍsy[TЄhZ[2lSdqy&YOmv4 +5YF,-9O/ +63_ Q޳%(:D}u( +l}"\%ZFY/_,w5sbb~VYo/ʒ{}3 7%*m:,/ˊ41<<,G#Βum>=PCVs0r5\~EeX10A3 }QvmL{g/af`N'u~Q1Ҩ ~ۦ +SQg|XSI+jVj~,8_(ꠍfF˻:E/ $(aXEǶL+ܷÂFQ)*ɰKӿU|^qRҦ(Pn+IvE9-6xv &CcJf@z6vl&bԏ~?.@,T,LkSBveӔ7ZVOwmGjT*A|r݃\V ۠z.{"J=޽7\0͕` 4O_9y^&e#~r_{曋6ElhPFa,H4${.וkmݖ47flFϫdoED^9k.R-Ðt8a[` :0 |6&h$74_3xp D jzATq]űo]{qm&zixSGjE9)Ht_߁3is]7ﶃ@Y+*5?~I}c~r?ӻHΤ?Ȅ8Z6,UL^< +m$Zv.oMn F/!Cj\C&P;$7~÷/ah~m_O׿ޭ߼n}o_>yrW_oP۷?~_?~߽׼g_?|/~ _|w_Mg_}o~oݿo?aY\ZEE?!r˜??|.kWJ{u&s㑃 ?d3t0hIꎜ>A-_-ؖ q/u݋20Ѹ]B:B{Zr#} 187aq6Y m/ b h]uٸª/mJea mW LF]fmT-;z R4izءZTѺ]kD=}SM Xr_m>~ +/[h4WՔ9(Z"k1HlO)h PnQt2Vs2{S"KFͅhԜ6kkAW0Ōek<+B2^pj)3wAak]UZR/Üخz\}mZP.R&3فF,Kd]WsBr% rbޗ7Z:*uU?N5ܷn7M+w%?)ZsliF+e;0eٓ +f0u$EދUTljƧJUorn 8S&"M>8CqA$Cџt'K`^~\.J +ku4vʛTp[lA4StE OJd8֤wiLXS[id_Aonh~A%vgy +W'0q9{I%7+b? Gýa<^KڅyOeV਍*)jNg '6cހs8k +COcy@v*qmby,}YAhgܬť8Wi=HT/_Dq@ftb9- H+ߝԲؽ- +p[#Sp#іfޔF>! bYaoBˢ 2s!tA"Bh- +Nznj nߎ=ijouك\D'E^/Q4&l2t_3*]"?v ycS߹XЪ`zvu8bsWhj#PE4k wjcR3֣Zb(,*9?oX1Ϣ;zTY gHD \uzN}^ mލ&~}qʖ՘Xt1ga&| ^ %.I%Xn%Θ$fss hEd b%9(w^*i/P kꖲ:C'Ռ +G݂wVXϥ+yWkb42 /-VX^+v}0KH:Uӯ%3,~{hPHjB{҂EY3o6 +mJK=NeWٍd:]ڹcd9ucSrqUYm'_# "6( {s37(^?Y{M3!•?v`1)5e.*+J A'"e*e(' x1d̈Ȭr5Sy@ZjPE'y)DHwdGh:4$,,]Vda±&Ku \FXfȢ" w>_(%\f>-uۉ 0:%[fݸ7Dг 7ͅ9U khS37$SAgWwy EL̚E#U.p>r,B3nǥ L4}"AX TвOgq]ì҉~2H&PZH_ ^M8@y:%skg#%aFoXI1RtT4X+GztH{yr%?0E6UPΞ"G/%Z0/ ,O֍^&vcn[0.6$Q +1I +'H R\mz]:wr%_@ >ӽtmNQ[,L&%jrײe7ʑ~!n,FF湹ؐHΧ>eFV24K3Aq +e,cV$PZ( +At +z̻PL6{Vgz'"ΗpܠBdTY,`ܨ7km#b.';sgy|FGL.QڦOKt1J~*W߄N_// fZ*2釺nXT%(e#/p*})˯vq L5CABb\AW)#/*tjͳݭŜ&7.9a4dXN!ܒ i4ugRArUׄĞj5z,U9A\H`*R$>_ꚬ}υ i^h"0,BܖC:ANţz-5/4ԈTxa=$t،F;lg_Fy,+z`L]^ۭZ}(e!EetUSOÖ06k /pS4 U  DžahU i@lhWLGzC/'K|Z2R&̻{' sjC1:P9OaBՂZ%cBa5TobNVYFb8 +(Td@ޑ/Y4%㴃XW:(U+4fH7Gٚ =&g]~BYsޖ>/dWhrC/tu0v0~KP$0ryE,*KR?zv=F]U:tQMWUaUZ&rJ>)sz`Gf8$"M[5[)JℱKîD<'MZx)q*/87l> Ν[ jwuGl2T E][4߷*^-uТ֨Xݶ3wT,b)C^j~f4bM0z>zP|oqn"D/a**%bcf,4Us6h'EQY չFnrҽVVq (GK]jZP C\F?(pnO-߅Csb7l(Z7!'5vXՇB u`fr{T^+pb_@PT]OV+*ɫQ} ӡN ! }g ŽKݛ.$T +g)vcrO+@IB&r;*em,1ݫӗ4*Ni [/5k#Rju@GTL+dTCp,) A\Ǫe\"hF/'nkC UCmK^Ц7=8\ՅIzJ8wib}yƈUBNsF@7!SР+Om6d%R_vQ*/Dbl@~iY>N~Xc< +`SmEѢ-~ƭTtnMJU3a,TN|(V+HʫkBr0a`Јa.s_S4>+e 8q7+椤)~86g[MOd9!0M>EnvX 𹿏ZA|^IKBKA}*,i>$2\f%`[wh>MշGwUeS"!/")q;!bzPuyeQ[us(*R;Te=ؖ` @^d7*Vt\IDzluUKP84# ZUL]AOʑ;0WwvE7)~MT=}Y ol>FwUaf fUeڬ$jATâ? ӟ {n ikbp|/փnjC4k @g;ClT [0c]RyV¡6V Sc/tq~ f77r2/A!)|-ގ.טv&CDVmWk&H3X/DM{ܼh7U>6^1`rPU&$);c'5=PND,GigG#ܬ}EMEJ_~GQΤHx^ɓ==*Pǚ`v%T<裍CEE~u耗jVM ֠$](k)+KZ%;,Dk"@x|~Di- UpuxfF6Ҳ8iW54,D(h>u~Y%}5UY '7٬XEfNӱ :uغ=.1Rt&x'bJ!b8cu]mC\ _4a!.=X1|@mnGОX34d+89=f}&O|ADKv%bRM1qaO>Rz2|-nabUm ~Me3lF, 3lGZXAL'#_lGCu1$US-1 nNk})}klEk>|_um3)1 CFlVLCkn"`eK[f];%lF_ת^zK;ؐUӈ%PӶ0J6:܋I&/q4& Ef:);w6W + *l&@遏mp$abp4 s)6q˾D>&yE=L`3/.0@ꪑ;Q9ꘓ:Djxg/{Xn VSO_nJ?h k;uY^9g8S5ol_U^a}]Sw@_MR^RK(zRYĻLEL-y,hH+"0H#idT|J4jV"H|@vmPmB ڎ[mhER$WEf-8&ESIvE⳪b' \Lr w3?'d;1msFjoL5Œ*& }2n )3|< ̈́}nu{ 6͏mkm{ю4rN*I慷p~fesE DcPRF'{fw+$ ʢOg%W gMX ++A!soav_~fuM +Iai=L=ZUK}ϔh֦Ox&%VF\P K\ tc3vZVSGqU#Mɦjډ)͝7I bh11L#r3 M&/Oſe 2bґXZ߷zTzw@PmﴚaA6QnLN?VUga"L9i5eX1G[n"Dy)V)\~Jj:2Q],(­BTA 'c5id=lPOC+&{crpq Ic"iI +hѩxPSPȁiisn M-|Z>|wDMUoYl`mX\4 C`Y^2* ZNWX˒#H2I[O!rɔmHBnf16:4z#sb,&/y{I%XdC Q\nl,ik-չl~l-U@m8!EQi$7^kKVAY*@kV10: -۰/UQ2KZZ؜vqNN9ʖUDs2# +䁥:hV4+>VĭNWVGۻxH  ׵2"=8wĿX+\r wRoHT!ŇnZz!:b8")BQ^1=m6UR ~iv5X@)$ +vzQQSe9|eMp5|4響n02=#2ea .aXæj4rwrf(N'9:>zY\fUI^XIY`!͔SF&T?|O6`^(zPyR/"Rok2DiKu5V%Oڵ؜-]yK)=wwgtF]^\6XmU@쀄Bر@Bm,;n0a~cdT9OUg{)f ;47H\Y*V{Y6T++tK]ZlX.MRT#7MKZ%䒔 +/єwf jq~.̥3xRvrU FORvJt$ް SԴLdB7dGJ}%| n*d\ߐZDrJްXE͋NQg)D6FYcm.̖*/WVdmf*&j%~ց-Zubs>$[/\ >`"^Q;mKdpRS7 PѭFnݍS?G ĜsQ\@M_.d&9I"t +IQ%|aEY7۬:\ۧIq>2JFxfnSvf!NcpҜpd`qFun&`Zlω-=;WQb9K0sE1=uy9uQCܾeLUf%,{ra6~3 LI`ax%z6|7\6jO_@*N^?HLUᠿ2wuf>WSkihXR#wds +| ,+Tޭ9Įؘ$0֕Xa%*Tr=FhV +e ͺ1T^_eIi }wֽ0&ƢQ7ӬqGCIF^:Cx U+Ds6ᗠu[☭m* *tUO"u|V/rY5&ME*A^nx554f356 cv72F)R{nm|)MP,,vlNT +\^s?yyi,&'Y[g +U}Rs`*i 9t?R?Q9fĖ:Az,#QW+&+#:Ca/؅9<:7kQU[ڤ0C})F~Mj 1o7-å+a>p+ I$dWĦ"dW&!bʹAU7BvfBvLBv͋7 a찼+LBvERT_ +yÅn?1 Bv%ICȮ0? A`F,de/mrߊW!;'!;Y6`Bv%BȮ )dGc!d$dGQo,^`v!;u}F_8YnnW!;22 ay#dy0 a#W!;BvpMBv0 +٥5YȎ"!;cVBv2?4YȎgFސYN !狎,JF;kб2c;άc :v:vu/ꪔD:vIǮ:Uq:v5`c'ˤcW~U7YJj0rѱ,tFZSNINI9Qˬc华]-Nj]]Ӡc|W;6u0ctc ]]N2pYRYNu;б+tc?uJ-]uбQ.c';b]iԱ+G4L:vi "AǮl:cW@R:vcWh::v3ؕѱ:֓QǮ.;IǮUc'èc'ë]QcбL:vC8O;HI"INNx:v:voԱӑ:v$ⓎYcGgcL:v7)Q)u,O;бuԱaԱӯqɓg=إaԱKcQu*.OtԱLv:votlұ c'짎$';nŤcI.c'QǮMcW5UZߣ]&nuJR;!LԱ,&`:v:v2:vu+otN:v&*ݫ5I>{ԱUǮmֱ3}AǮFyn{Քhױ:vFTG4L:vi AN;cG:uI.cA&;:v:¨c1Ѭc'QäcWFNUQäc-^u(N:vUB;X&;w:vg;,]ьCcaԱO""QǮHaԱ+L>u0:vXf;$xc'c]G;ceL:vyұI.͡cW :vlotUg;ɤcYǮCǎkR+:vĤcgqԱIn0] `z:v2O:vXf;,ot0:vL:vudtG;,ot8YǮћt˨c͡cWEǎ*/:v'BԱ+uIf;JOڋ]IrIǮEǎc7XFnbmcǏ>uԞt2Աyұ&;]SǎcG~_An :vt슺>]BCǮtJfRw:vc-]Nc7XFnBqvұѼѱc9uDfnt9t䳎Eק YǎԤcG%䍎EYǎ=Qu#u~cIθFL:viu;F :v"~itԱcVsұ{ԧ{u꺽iIǮ +bбO:v$̳̓Y;=IˤcRSǎiұO&;ot :vu//:vuQsu:vLatݨcፎ̓27:veL:vt*ԱjƨcGjֱӌCN3ߓ]UccuO;YN\O;&;Y&;Y:vg;O:vܡ7:v&;oL:v躾ѱc:tֱDǤc}QluNtotG;qot0:v|T]ACc'ˤc'SNݑQǎӘuݽUG;p?t(:v%cGFǎ||ֱSquұScGaֱ+:vE8;D&;,,O;̳,c:vܶINŤYNQǮHiUǎ';ˬcGYNoǨcGW䍎]:QFu8;^Yǎ:v&SǎuTu7:v2:v2L:vX:veݳQ;Nvֱ+4t/jO"u{F;6x:a?t0T'';'Dc'ècZcֱ+tZ"k}ѱDzԱTm]MǎScWDб .бpcGh+uX&;zoO;uTu +Br˞:v<ʧꌣ]wб"ԱΠcGvұ#0xرۤcÚtT}at8IN] б;Ա+!:vEԱ+zձu스"W;[+;ao:vQNUQǮHb:vSǎUcұ<і~ 0رߤcGԱ'"up;2INyԱ+e}c'c'þv"$cuұ4'; Cc*%u4mбSX:حcGc"cG=QXjyѱB t0(btػ'ucujױӴvQhuNRб[8|ѱ3G;&:v6>u츷]QUNUmtJʆ1;aFBjԱ+"Qձcut,~ؕGL;7:v?:vf}G] T٬c'c'ˤc华YǮ=ayc; 0رȿѱyұ2axauu0ѱ#u:v.ot{;ZP&;]흎=YnMh7:vUD,v}au :vFcѤcWyauğF;,O;nc'CǮ;ܛuv_ttx_f;%:vEQǎ]gWj^]ǎYǮ;Z;vu*O +ڤcǵ:vA:vXg; :vӎ]NIˬc华] ԱK(;S';ǤcWбӌcYIǎy͇^aұM:v@:vhF>cWmұtVG;͊uh[:v"dtǞtG;^槎ǤcW:vx󧎝IIǎucjұ֯:vD$Iǎ-:vȓ]B`бб+:Qՙt4UcGjұSbб{?}_ O;&;F;:vUS/cLjSc'ècg[hISǮ+tv:v8秎Ĥcgt@=u&; 0SNANhQSNQNQNzءB0u6;Ѷ36S^wnuԺuOuXk1@FL:v~ձqԱaԱԱ:5FPEQ9QǮ=إ5tLJ=t`Wbұ5 +c5tL_QN BUP% qdZF%;5줺AJvvLJv8*mR0CɎe|RS(1*id'deV{[?d%;JvEAɎ*ݤdd.ۨd'èdJvXG%;SG%;Mm=Tv@^LJv`6JvLJv41PuTaTUɎ^͠dAN@QɎ'0)=܇OTcvVӆ7Jv2OJv*NJvECɎB̬dWLJv_Q8dr<+ّZQyRb찼QdvRt>+)H-f%;r7JvUtI. ]:@]ݳ<*UugF%;%;U.dg4*U(<)2)aydLpR1+ىdWJv`Jvd~d'΍INEQɮ&%n%;('%ڂRcYN%IɮP,9)QQSaxRSV7)٩9TyR2+aydd'ˤdg<[JvT|g% K97Jv'%/Jv Q<+\])̣tA%QɮH)dG=+JrNJvBLJvLJvy(<)2*GJv~f%;̬d-G%b{ +~U+ى!mTAFNT`ؙ]r=fxQ3ˋ]CNI%;CcJva]LJvٕt!Pp]9n( ;PuReRT+JvEeQ%;պF%;QMJv<슘G%;Ȭd7XFJvNJv (i@xRdI.dLJvoxf%;Yɮ[&%;3Jv`5f%YɮHD*ىd'bQNYN, %;%Yɮ[fP+g(dGXPv3+xQSdeVSrPd7Y4=Jv&%;&G%;%;ҨYˬd-%;nd' +@I]mV`duRdǴCdaR%;یJv&%;>O%;ISNANJv:Cɮ*Hdx(fdWХH_*%AW2+٥eRKk(ّ"NJvx(فtF%4LJvJv&%݋QNQɮˤdG*dmRaP%;=)q]]wJvs;(&%LJvi %;dWRyQ5)Yq+QdGyVSwRKˤdgAN8Q(a0JvduRaT|U Jvu]=*م-*CN+d'd3QUx^d7lTLJvJvX'%;%;PuT0)ax*qV]N]{T3d'dC Ȩd' +QɮjvUN!ĤdGudWcRS tTdGy|RaRKäd׭d'Ϩd{US~T0)PuTӁ%MJvԙ'%;F%nՕj4BSNhQɎ2dW~xUd&%;]=*م1fUF%;ƨd'H&%;3*٥58*ّR<ʱJv &%; =(2LJv}UckR6*@z*Q옋0+us(ىdRc􍒝F%;e}Q{?}g%JvG5D$d F0+wd¨bw8%ENfwB3ə$iUú}<D5}O<~/:^_p::xpzھxt|骻]M2p#×d:gܡ-sRƯ;:$lE+t|N͋>ʥg|/\)s-9eEBx%w®( \stχ*qɜS;t5, >D5s +J<`̛p 7G)}港TY9꽀svg@ٓ#y 8G{V88'qYuc,w")GdBΡ΁Ce$K9\IBe/+>I++sKϺZޑsR-?9E ވs8œvɴ| +-6.Lo#"$isJM(Deiw](risrvpYsmxLSWeHh;9)nqPrT,( s#=8 '=f8>qz5]$"D6ɺ ^X!g)G")\VzU; a˪<oh9&CANAwT.mI8g +WI!,rz Y1 +IvNbA{ hkS E %vAS DZ90TpKfPm4kڠ%"o15>rl[䔐xt^lm'pkďc_x@@  P'>w|vY;>N?=X9сŽbY!N_ۑ$|݌@zz(^8~:p /Sw~\>)\p?n +7Cǯ +qoYYp\Zo'zG^T 8 W T9/l_)]8T&+gA 1G"WkfIe8 <؝q8VŽX>pvkqvD%Dz%FibL8B,ia-;n +7`A1petYΣt9t`Ϳ;nӻ1CᨉĘ/_$Ǚo2:bD8 ,5:0j#''@qyݸ(fo8y%P8YN8<#>u)踥::Ne}'fZZLJO66d!K7,7pچ:8Wrp64;8N Q4o pvpTW +c *(;e㻏č!J˹i,` `$sƱMJc&kSl]COy Qiqvk9ܸ- Xדqt: Ja2'&:KC7)۱qh5q= {qʫ+ȸ'Nt1xqX>WdNk,8ikN&TY[MP}b6HOĝ J運E #(p 4j+8>#I8͆z'<\mp8XX0NIRdDdݫlO߁/?wT8"^EEpn- BQp 'LS Cnv.ˈ%ys aCga܁p*pgŒ9xnLÙ.F &N'J&M_lNsSC+0pKIMv Ǐ)8d'NE'w!8KEጁGP?nz9dD)pS%>ܘoܫφzT͌K*8*] 2n#\-aæ)3C਒+J3WfÅC̺z v늻1n|q5?`=7E,n5V"o>n7ܙXF]  M7B\CHpS䂇&#h<nR,.7Mp8nPq$sڀM'šp#['Ώl|pf'pDg( +MAV? &Vo{]ۻo3EKm;yEk۞3*wt`yLrV6QcJV;~9m4&MUT?&joF]铉mQ[6ΑHk ҽ~ݞHھÿ?)+y']6Am$!6yUފ[J*:0m*S {P]1DOq0p׼D)>Yr킹~]Jg*)5TKIij4߭?"T'8_}S{&ZmԌ5)N>l:'u(cêDZM?-\/ƅ)hlVK06.k،pb#GsHvMᨻN&o8 Gj`ӗda 7l=*zl&Qz l) |~vQ&@o f5}.W ,?us$턬ŚQ 0,蹘kWr qN tw8zbZmL]1nMǠē(ujNbiOo5%ӸZ#v\FWY%Ӓ +endstream endobj 293 0 obj <>stream +M]}k3zT:b-HgAX_mt@> RQvB[[MQ; ,U6ZGFu&XuZdª^bcޡ ݮ Uk靐jcATh5G4a4#-DꦝBsISkZL\:~f`w(5帎LҭRSρöq4AfUO&~^@T؄'/ BsLJ5Af~pOALvcw?NcA;0ix,vv Zb N#eilڿiF9 p{DN#[O~5izm}R|6,Xf㊣JUet2@0o:vtE=vV^~BIȄNӌqDg74UA&t2Aj'I(i8Y;8 XR^R+Cwr:vr +p&9M"W5}AiZZHdsS:9 Om?LpV46c8mQL +|8éir\_4ppjFMӟkI4ŷm4b1 =lS$[HC^bQ/jnىBDhH~¦g:,H5ĦMFEuօM#Bx`(0NشBt< C4p@6 JPG`Ӱ%i074D&5 cP+ +H675+ +AܨiR Pn^ 34lulK$lZ隖6o*4=f Fq&z` Ք$l/Yl6L M@LM7KP*Y4Q`4iʲ4FrvjD(*PMPӔiꋚMSh杚f)'sX[Ƽx&BM☎MC͢&4K`Yf6wh~;^0YSo4e>Yy$dc@nL>`C}b!S^iu5Mm7F ޅNMSF5T@e hZmJ4%U:4L#EBB7uMdayRqy?އ}k͠~ 4Siڙh`ڏ'3(+Ri>rfd82MB>4J#+x7JZ7Pi~Xr倊3 +VdvفG4Ћe1M4-+ME%`*[$$P֗Piy$A@F`Io>IizV0*adT`;*PiKQ]KuT* oTV{* hwT"1G!h T-)bqIJ**:Hiر$TZŵ +Yi6`URG&7+ &JB+<+WHfaοf4_4čagIxt$V.y~`_fu$'79JV<*M + h/MIi"4Y)M["|AJcZn}ZMP%vP/cҤZ@iDNLuk + wP͏8mPZ==[إAiK4T!tYL\o"BQi4im4r1Yj3=;gYik߿Kn +'Ɓ\kZkb*$0H=;!sDWJvbʁJB$)޶3ըn(PiPXKB!i TnJB QFu(Pilg99Jf]PiT J+g)'*MuvsVR,m=я#밀16 KӖ"j?K'-̈́.R3#KGt$^2KCa +^.vY@0K<R9p-xiW^,9xiС ĠpiL)츴%$\ڒFY|ը4'-jɻ9EtܫqҴDKS~~f܉2S546tĜFBaYZo73^XgK#b{qh4;(2* Ba+h<=e cGNoID1i'%y=ںtD:3հ[{(v\5,;ή+I]怉9;N9;8ÜEۃqGwR0-fovotN7Tl3url7TG-a-pSI50=Z jX9=*U WfXf'mlF"ΌW{(8Pݭo;, ob#ztu¯0fp3|D^P2u]2vtuY^#Tþ䀗ىeZ ]fB/v٬V2m)ȭ,`/#(f.d&k^fr _~=trr2r^b;5h`@z/Qa2%yi>3C_V"q?{GN~5_`\eIB/E/+OA/`{Ǘш~92egp_&vz/[J—Y=s[. /|䶺Ӆ/:Hӛq_ƀ;l1eR WgٞA<%;LėiO2N2|Y +|Y2mpL*{ʮaA—j2^W$$y\^-ЇM ^64Bnm[ _۪ |%|tAIL b.%󠜙^oN<ʝ&^'v]VpE\@&22[&'e+u~vtD5?>.CP2<.YL 6ekHǝQ販$tT]fЃ\r[vBex_|d.S6} ]'e\GmJBDQ(r,Hu]F 'GBz,p)i}[{ze\))b|Jک^K1S qm&FːBEԜly&x7jla⎄]fhsٯ? +c]ZLF5J;̈%*2}){]l:lLm+AsL,4ژwxW^aiuβ60U tˬ%I/Su\0K|ʤQ$s/S1+^+)$xR^F9Ml6m>OwMV=eN53Vlrܙ^s2HoYŕe0TˈHg˖˖)Μ_Q6(;/Su2T݄/ӻi zKDPq/[/j̴5b,UuWjqɖ=X z+̦3,i/|\$=LĬwXIZ==ne7 z%!Bt)`E;=,d8M;'uxϠ2$Uv)Yrq7C:j01eANYJgBW%E,AU 6>1(<]mo+M:M(1t#ʑxUc5ձk7)dcXJ䢪Utv{lܲ<`7@;bc,.Lŋ\T#50)UD"m2wn^&aXXc1Jf c`  +}Fl2>ڟ+~o{`L9 mun4TӮ8Z6&wS+l]O:5د>7 MWٰ?[lΊ,d(M+#RE?FFÒJ~RKe<5ӷD?mnD`6fG> L @Il>?JײpR҅l:G$y"τ)qNja8zbi/ce>C{1w W^QvXt#&ƑF'g { +[{N%pJrId!2CȂ2M} vj)y`^Vu@FM :y uX Bi76Ң^^Uk(幫]AIv%VeK)O҄K֟bjLL:yŹˉ8al7d]b4pZ]V' aX CK(=1ݓ&,7^)Qd+ϩ[P/ PpX~7B]= hϼ]z1A4ɟ";ŗz+^Y{1: WqE%L3Lv8cO%}- +n("3W@|Jeik`})PBpd/}n]meB=0 .+=մ* (-hۺ iE_;TtK\.mZ(Żx~vKcxd4TӪw"S붩O,6*ߵ}Di4SQzȤPidT-d5|+xUowqP3DqߥԺ!6Z}ݕ&KEVTi6TvC +/PuS)Wa#ZtdZѵQfghgI0ݬ65o㶑c Նld +7Na)ƨm ll/s3PPYRlNЛMC#}^oT5ŽM ]3K/uܔpdjd~~0a;}2^~]>TئVKnnʭxNCtG U{5ܪzSsD-YM\@yBۊK"6 +ſ,ǨЍDYa֧Sbrv߭R<:fzIc?muY 4IeY 6TNV+%r/۶q]a3ֽ1JΩehLeѧ->,Rٍ\2ÞN:n&W3g+ec.źV|kib ifgPi.&m6YЉO.̩4D(n?V-nVtl4@pCB=͝}}ډ g󩤁a +(77kwەSS&+ +HvV A5omu4Ȏ\k4/¿rG+3oXKbZN' AUL7A2|UcH\VzTs=4H)Sz؛Ѣ*6ΐcMz擇|'k7\)FKm)W+k醓pm OWqsd`Ild P\ 5ϴ{Or"۹-U `ȯ=t|F}UuX3=A_ǧCP|vXLx-5ۚl %_^C% +;J#mEܯu2No %]`W2MFIZsȷ6*ߦ +NN˝!Q|_DPXn$ے<}o=@]|7a@u W[ +gi3?C{/\CWޮ%lN͟Pm{*iX["M:ߧr 'd6NX, +ifnx-ĢFMt[Q=rMGLM-sQN&y,KBYTUjmNNҒ]~Ry*JQ~DHģ| co9X KiL nbLrki6vTvY.Ħ +k3# +w*{٠rz`/Ԋh>zuqKJYNlA喢֬ƕif/]X` M,4.NˊrV4ezOZAz "se:eOӂJ;4/Ԝ%$cljM9oRZ62Zmd;VЛ[䖬n*% +&nOO:#2*{)mÏ-yaiW3yXɅIy + wT^KA'UBJM! ܀5Q +Y:Sj,Jp`6h%HgɜSsI9:c2 h>atpI%&?DiBmlE].)rRبsKa}<Ѳϛ|/ +002]sAi +slIiDe{@T2 gSDY U+H|,v_JPqӹsȬqꉟrT S~O"ƽ _2ud(1 +ZM3|q?-aX"kׯZNݠPqn Qn8tc-g|Xe#!ɞbrcGKk4VNPR ?S)毭x^Qj +djtOz>F~N-C҉l3Q*Cv< +1ѣp񖾆6jBi}bF7ύ*T^DLaWml<mY~ώjڻTs!Spl9qB.NݓMyG53( +j9mbejՃv9ϙs-r!w2p?۾"i'T󟘵H>ѭk=ҽN4@'JURF+&E,FwJ /%V,f%ja[CQ/VjG KY ї^*cց Ilmﺱ鐵i?.Ez)dGZԒ{`Md;^#I]W`-Sի +:yOZl=QIRUI΂I.Lݒi BxU$aa1LFNJS +eT9k.Fvŋul:|`:l@(>ˊS++iNWdÙ-hUGeiޘ4,XG(}T +M<4ҧg)#*6uEX,^ B&ck#,; Z|BM3ȭ{{AH|?ӑ}m`y ++訊_̩:h0 a}o:sx-ęqF1:imʕerI7PB؀J +hPϤ::Ս/a~87j]([D s@\Vݶ :nK 0f03Ae*VeV[WsQ`*T [t1qO;|w=+}Aq9gz$X2Pw^J}YK=qrBV2ji5x]+8f-JU'N쬰PۛVDoc%CzN)r4X"JDžFl| +jJFYɄk3lӛQ/ ݶ9LCZճXZ'B̀uh]-GEk'/$,q(!^Vlfrz :shvۨKe ,lg%;fE4E +G$a rd<<0|WQۂZ0=eGW+ftPcw|_P_29"`@otQZOV + ' `@XGrRrU L@OV:,.6M]n*h&=E-+n~q +%Y(ߥو$a*k%*MQcV"GY>!={Cҝ~;jej[)nF"!w~þ]IzkNvFH72ƲY\>El?Ty=H3[Olgbz #AJ@CURk&{bTTbt .7㽔TL{֮ԧI8N*IG_u;/T+?n2m?'O'yM= +$*sx+}ce3UP}=L]Xv!ѽGP +בV1CnChR[TA'ݽէ)dH>g2&nd9ɺ+$[Fxxcu,&uXKeQiS,Q/۵_*hSZϵzYx)x5R +* S֪G&9̱_독LyQ3xi}Ea佇=HTM6+[Rlm"?rM5_iˌkyM5߹'JNV-?|&aA 6+ SI\, { b0UB 7}l +TI(mY$$/S?JG7="=X ޻D*Bb֋%շ'TNm9AVŰpY +QDפc)!e:*N;c#uF]=fذWcup=2eK"6Z.'K]V5};DBc״^n"&+e&}R>xXLGsKhf5Ӵ t7n֬Y[͊K-ɰs-l21 Ki!eB~yLi\! sܞ2v-5W\B#*q~9 BJ)V.hrPHcX%pA`h6QXS#NXrXcV_>̨r`f힕=Z\j5]ܵ;)O=-tl>z<=keߑd٫`;-z0$>/eyoz#̈ao)QDzĸ$4i$3jaxtX/ST@#EF} ?}[h8˼"tTLք)WY)EN?"Zy߀l2J)ଯD Z`Bs60$!Amq,zϼ~Z_EDB%d܃ 䝤*\ l/hŚHY ?cΘͻ<:4Oл(DuFAkL\,H 7P8Dk aD)g}V6S@]᧬:K+pݻ.4) 7ieʳc2&;]d2s ܗxD(^6-1nkTK!ubpNECjM!}Sŗ]Xs`CLr\[Pz"pݦP +imZaBA: ЪCߛ'FԶsK(bXpB֚q߯a39'?FB`ma C>UZ.elCH]D0(JEhiЭKn]ď?bl&2X͠E-DN&9Ikǐ1{qVk)7jhuV{ k'YY̮vRE1}aȸg}5.V 35(vၳ?l wy(b [)&TY/X z3Fnqj Uy6-,j$!?Og2/l%k9pQ:A7(Sd}y0@߳P*`pȱRVI \KClrTݰR+d&wV,Z?PinQy_L +!|B}|J(KЀC,YB-K(h[ 4ڃgsT g oQl|FJDqkF2>U97YCReIv2P|%b}y-\bO3Pv"XT?ˤ@zv^*S-AiΣxb:N?4dZ!M3ztObdbȇu.@ IV6%$P&4p"ȤXyhSi2pyZ܅4p ݉d P!D" 1($R ѬJcM{Te-2Eno4Qu*nm˓Ć[ *CTQk*eXc#ʯ$1Z@TW]Y 扇Q,Wbݣؐ@M<(vX6)}1C$_P%D^fЬVv6 B%j Lg#P#]<=twj@#4,T2[%P+}>eC "k[X )(@](k۪l;6|Y<C;2uR+Evy)p?aiБ.yUD'dB҂_])떩=C-&qT `iz:h$k *`أJڦR ɇ5DQDIF:|cm5EĽ0ŕSp +-<ǽ+tF5c:#*oV ǽ6wD캋%=U97yL++: sLm͘ mwٿvǾe{z;EmоS3E%1mM*Sm-Rȥx3h z+{++ֺ֊ΪJx6ҭD9lDWv4lDʁ_[a`(2R{˓+kK7W1nSR'{t»~AhӸtUw(<%ށ|_3WQ%f?T%"eX1*i\E gV?mg"J*1_\E/qd_\E3WQk*A|q¹aW{qtv"K7WQr*}*~o"r*qy^3W[*jlJ'W7WW*j6\ť$|&;WQEU*J\E +Xԯr^\ER7"J*JU2WQgU|,wvT_<p hUܔtal\EWQW-q,+/"b*$b-/"lXE)XVQQXmXEoXZ/b+aRxcV dUh?~`j HU6*XEYw= +/Uk*}ci+MXEe"po"Ӑ\ R~`%gUUT C*66z3/97VQr*r`*JU"fc~c+ XݱZ*mKXEMXi9soXEU}UOnXJ +e*r;kaqKXE¾ +aelXE );VqɁUeD7VQ#P*ܰKٱjXE~V*|cqIXE66"/}c%gb/a%*RB8&RVqXE`iLX*A*.%a7ٱ*XELXJ[ĎU$웰%~`AXEzV7VQ*2 'fXE(%cv/UDIXEVٱ2V=IUE?J +g +2VQZ?3VOUļUDNXE^}**}*6ww"n HU$|PXXE~cV%aVQ?c3Vq);VqUT#cvUTA*ʠ1aUp2Vw*‹c58oXEU\J*.9 +%b Ub*N0cK"E7 JXE}Ul|aycV%aۨ3VQJ*JUN:a'5/3VX;VqSvzڒ#q"}*k*XE8 );VqɁUXE daן *2Vڥ7VoUlXXE*:R2VQ"քU**rXEA8'fU\J*nc5f>VRV7V+V~ i+c5;gRVqoXE >_XE.̎UV-aU/"d $cUd'ډeR0*R__XEJV &X*.%aXEVθU$LX弱&"QڄU\J*.ٰݰU'"6 XW.cq LXE3;߱I*jPXEVq) *XE=NoM;VQU\ʆUD')%?܁ HUy}c%g"J*7VF(%cq@{c2VQeU\r`哗`ugUd(9c5gBobVi*RHXZ/&XMٱKb }cI'"DZaQXEU4ώU䗾,HVrlXMٰKub%x|c %V{ "o,SVqSvMG*b*j@XEVq) *XEvo" 8X*3ycxVQUT'cէ`Xf{@ڱKIX%;VN%Hn*I6cXOa[fb+ ȁ ȍ3VQWV9aHXE)?\ۄUDXEU (P*2ٽ@f/2VQXEŽwIU(V9a$XE, hՍVic*Bjٱ|e"/"UT}*6r/3V_cuXE (!cDV%aQXE @* **^VQXEuf"U}cXk**j*XE~`%g|* L*$"Hrf*kd^ߌU'aH^XE?7"Cl*G5eD^XE] ~DUl氽ad"c (V6au2VѪ^XE Ȭ Vь>vb[~*&"J*7VQUOX5>dXE56"+7"*"cXEj~țUd&"87V۱O% 2VFaUv)a_XEԄU#{*Ji*&cmc5}c"XEVQaXE VFm*jK a &"Q7VpZ*։}b#?LVQJ*Z&"ʆUza1JLXEU$*R枰D6w" 3`*d"7VQUرJ*V:;VQaU$*vXEZV/v"o"UDHXE+ +*za9vvXE}ٌUT9a*Ͽ?c`*R6چUKn*RW*"'"uoXEUaf"8IVdw"ys}aU3t=Hx*2ug;VQXES;V_UDyUlU~=ɋrXEega5e2x?Vx;V+VQUT;c)cXJU4z H1aXE2` %W\XE}aW&yAXEV`Xڱf"Uao^zU$B*NXE}UDyck8Mt*` 3VK U%"'+a+TVQccl"wݰPFa&bwrnXE}XEp b* |c)HXE4cUIJ=a+a~aLXEXEXEUD9ˆURX'" H2aU<_XE aE*Rh*j`XEa5H*R6 7V~*JJSLVhsΆUrVєo"/φU HOܸTiXEu|mlXBUgfXEUܰ4$M\/ްc*ְXE~`رVH;aC&-_X:9Ui*R2V^/b +rbUDNXEUd*2NXJU);cHXEJXEUXE( H}*JUԪ&cdC?tXEv"/o6". fUd[ı*]Ulv"J*7VQr*JٰVQU$PrU ؎U UʄUDyaXXEf3V_XE:VQ*R*V;VϸU *V7VUt VބUԯXEeXEhʆUL/\XEUğ0a*iXE VQ" HXE3 xaXEZ.VQoU =a xVFs*ͷcvڄUUDNXE)(V~UUDyc +XE2Vh9HX**j*N**g**~a ci$>V^U#+ao"齄UߎUo{HwF*I}JXE3VњvL?4a1ݱd*dbcc¿Uf"U$*zbcر:;V7V6U(y*ҳ(o"UUSUԏXE;VQ XɚXEW*K*'c,oXEHz*ѝ述ʳg"9aI#d\VE*jtUj*TIXE- XE^2VQ"5[ ȶ!a-/"`U1cu`%VQ&cicaUXEB;V6 XE0XE0V*6wn݌UUӑ( hǼc*JXF 3$XEM&#cUE*'c5P*Rc)IXE)? (E*XNUx;dܰXEy3^"Ďs3wޱÿ R~`{9] (Ui ؏_8Vq DL,@D?2V\f) `!*.%_)VшuaY|astςlaUD"(|6p+Ja1,Z`E] V+jRX7X9d{h2XȞ%`E7XѬv"J+7XQr+M`EBowBX|\`Eb HC( H HVl+|zkH`E] V|_C VTG+r`+JVDN`Eb (XQ VB>V?<)ON`Eg~XQJ+JV Q'b _ V$&6V? cVB+.ի(pH`E7XQ VPs+`ť:X~Vl ( (Xg+`E~`ü_`Mً[`E}h+t+bzvXqBi+ +z`+0L`E:H`E 2ħXc+yXVH9QXюyy%"L BXQkV4KXkVĚ'I`E`E2y7X6"5 X!ֽfͶUuRbX0G+$B^`EVD|O+dT2XH+1 HV”"N HVJXqYdeE+R4V'RXqVk'" V4VT*){QX% VR~ `E˳`E[^`E^dH+nNNd+Rv*V:1SH`P'XQɝ$8 V4y+n++?k4L"zo"6;XV4 M'L`Eyk_`E8XQ`E`EXqSv `Ŋ WI`E +X V4y+$Xe+pI`ť$X d`E`E.M+_V_+`EXdȆ4UzKC-ͿV4HV]`Eor`Hg"YVTL+XhV4Vr;QX V$mI`E<5<@ Hm+b+6ov Vd+bIրW0'7XVM$"67o"uR;XVd\~%g"f V< 1o"~@ xV6XQr+`H`E8`E+Xw32XV++6&D[5`E * V\rf`E 5`EZX M+nV\r;XVDM`E[n`E֮`E`E+Z+j%8qjN`ť$hYܿ&E7B?Xp+.%M&^`EXQJ+"$"J++&e+Na+8[`E&Vu+.!<[`Eo } HL+6s+g+`E^+"'"&J hXQn+D&`E*mw"7XZwQ+⬜fѰ=Vԁ H5){`v=_`ť$&;XVS_`EXQJ+ ț`Y $"] );Xqf +-x+R8.d(~`Ec+0!dTY+J`EV +4My`E3XvHL+j2`E`Ex2XNXY&K`EU[+``ť$X`E`Ezv.{+? X9/j^p*,!T؝EP}D%Qj/HgPzEa z*pL%%d$mD0HDmK7Q$Q"}N?OLHb|fEL:b4L8Yv&6blhD}cMRQhע"+g"r&mbqD,kT8eCԽN*џ8T~{-49뜖f1Ai9@ XOF b/tXyfٞD96hM'ZH?jFI5 /~3ݍzx|OpxpéL9<`2&Oj(80Pp1% o?? 0pC݌hZffzFK ] lxpwz(( +k\38!Q A5,tbS rkhLB!LXBw_Xâr( k(UJiGEyρ5,g|~&[kXrְasa9@lr Ձlzzh@+J_b8LY\C\5B.gr XKdГkXFtz}IYWybJ&1h6,\C$'P +5,2ְLWJ5*& +qU.5<tS4O6)A4s ?:qڑ\W[4C /::d=,Lexz"1 eX,8PTD c8ՠ^޿?ل O 1T垅|  hBkU9gIZ&PB8Ъ=z\(܄ 3\ + ˉ3̓Fc UaW9p + ZTgjjz'^Wwb 75f+B.iXs# + NR[cpZ %s + N\.uzNaWK$Na}G*)als +%2 ՗p?S()Da L! +SXH4 +WU0Q9AqM`P<8zZSB%Bl_Bɥ8\ON!MSKG_l-ywS :0<eL!]nB;o{gH)HB|S'aq +LH!*OH!YlB{[G2k[O@ +C +BnaڌMON:PPk5mM@xEN_PȠ |7|9¥$@&;[ŕfs.> OƄ'4օ'lOh 2kP '\Jn +[wYzlˢs$k gwXy\?xdA9ۛ':!9gցpˤ.% +S:aQjt/:aډl +Po=̜N^!|I',_TyD$ϰ|_"^!~ 3ф-kḧ́c YD=G=k ޱB$ɬ7&*"2[7K@B3%3qo4BX%+`"& %V,xP퉁sEWaIWC>(K!S !^~AXdfH B'tZd~^fqfJ6Rp0X]0Џ L[@0%0#< +ֈ֗BX&qg6c!%0RN8$!r7sY™9kڄ ,섎k"g ;< 8X(v`QT/``EU'lp,InaEuہ:?M%lhxe\=6|sA)S`%X6TN`(lP2k` ֎BYN_+<T\Jb .9XړY +.Nris?ִMf25QspwYv5B .%l} +Ԡ" ߐPo"΁r^q W4z2jPD/ *KɨR&jP +PKԠ˅KW! 3U7:!*j𲊣1ȝ)lRFET);dP^de8v/% Ȇuz)\A)bJA}=CR2\r@Y3esջmYdnI] ^OxA &tA0?ϟ~(6'@p' Gܫm++8ՠ +*_PlϒJtSP%QCtL< +hOtN çCNV4iAx46%:ח` F,+ %x eq-Vj%E_;|qqn2|M.gأ6" KI%DPc4v"H"Ԟ#DPa*#EP#jEP8k ^" "( 2%G "Hש-8ܩ(DTDprѫӝ vVG,?VI|GW?dX "X+'D Rx"X$pAlIA]' r/!XBv2m~/ W2C0z q9_,n)V!KN=THhEKI$ߝA=H=1ۊb2EQ'=ngTBDD>$b9z彝:.>ˎ<'8,O$!8BP'(u\ A AdƩ`ځs8.% C.`*O`vx^fj7O0CP?2CPsl!Xk2Q a < y%ԒC/`7k_}d(/'?,|f~xJmǵ,v ZWBjuM<2ȁ#ئ@zpٹl'6`l ( oQhx_31P/Pzy.5į X + F,@EI.:(P} +,ܟ@m̼: 7 H_ }R!`*A< P P JJX5@^-8nF(0(wL`^ȹOcTwL^hdxsϲ(aU)wPucsHfxD>+zp0mzڢƖ2g寙PhJdU|\TCo fx< v 9r )~ +`ޑ &J :{0zXM<@@(Vؽ? ifwXWg`$$V؀#ùE _ןH~}V ;O7[&߈ҀI80ʨ uG)O0~"U P֬5pjI0>b '7ږU DjV7w5LnLpx lXO{MVV̾v۪8#GOdڭNVاZ>%ڎ,^Wi%4h}nugYWf d7P}E?Ns` K4h;-c9;5(}]]>:wå]̧ABQ9}Eמ2 :MvBG-}X_'춂ϧe`<+T?n-uy޹@=L,ܭ͡qᐃ`ԖȿOc9j-!^ kS6s365|D|YE6!(ˀ>dC!Ba 'F+w߆W%@_ W rgi Cu$P|> Luڰ?;O4O*M>VyJK R 1>M<]SZ3 GX?SEO [oK@8O5FNxBP χˢq8?|R-ᕧlMO$“|Rl>"@TOpsfI6'r7rx )֮|_  IAӋ^w8_j)g]+7FΎGWe(y&JuTn:_a|p>1p>u'Nx-8NǏpW)|sI*:iHlg +6wiKg.82KI}XB촜J*}|Tڰ 'ɘӽ}$p>z pꈢ &8F +8"t8*lJp>4X/4|7;VގӋk磁V OJ|7l>#}C^Pj, ?|*73&'8E㯶|5Zo'O9;Op>: +8@ _a&Xhvb]p>zW(yNp>K{SPˆp>|NyY83BZp>Neo| +8 <+L2{GVJW.|p>N޳JO_V3,{qGD):eU-31>|ߓ,`Sԁ|Oj|( 36Mh̃8&"_3xG%8d @V-CbL/a/ƠCrZh>zT1|VDd>̧uK9qT}*"u@ t2B&!cU| +Q;|z쭨)|4-R +|T|<Ϛ5r4ӵټٽ*rPh?|Z%|m=kXWN󩨕mi9` ,̧(̧(T|ra.@Bz!\~*y Ü*;0aؖ|-۔؁|@> ȧAC*N}R@>^r jV.)toѨI]PfY'Y8#+DdO^")g ؃&"R]r  =|,Eȇ|(;Fu'AID>\D>=Xȧj~3oW|xQs;N.ihԼh!3x|a~<>x<ڏI^a@KYV#!h1q|eI&X8>"V/ Gx3\i-v |kɘ6Uό]|yEkOd! +JwnE^N<>,@>zQfLܖ~O7VhA{_G)CeZts9h^zB$J'jyy(:vJtwpe* B> l@>bHf 2dS8|Rt.#| {l A@ #o޾ ǠOqVTp՞N[JBmr @ ɇ^3aL>-ԒϨxiеFDC?|(&ODcY{]xrakM;;JOX,'8sA۔dAl^ q; [BmV<7&OL>io#HȳMNXLL~[M҅n2 +@L>m##3CC-ۣNH +Q+͋2U?Ŏx b$Of]99{ir0 pO j8oxq&E6@|: 7L>J>^ >f~FhV &ZdApӡz$ (y#6ѕ>{p. $IS0Ǥ O^z.➦#3_wFu]3MQs:AۻoO{'A^}G)^K(D7O;5qB=Z*}Of Ido) W::'cc<*\+j `X] +/&t=X0zTV|,vBE$]Ѿ= wUh#彄Tg]<%MD=Pҭ, &B:zW('OMst^$nY +}e73S;&OvB$ a}WEb,dbn.k}ifJ=ґ=_sѢb=e#xy2@oTc|vzT 7*yÝg2:O. ''v^}Q[VOh?f.ǹyݲNGݫ;yHb ,HyrZf" P^yvLsAڿSCyqfYe.^!N KI/'"k@3PY<3i"1*a䣎) i_GPf0(#OeCvq^<[Nțj"p4yef+v@^|ҽ)[|[NțDQ @d%wEkrD37[BBMyvZ)dւA^־aϨ*7t8T h2ޏ)gCfGktcoYvꗿGв 5wLK Kyv§vQ5}3SeD3<{~pFߓYI헿ʴbKOBړ.PUlDU;b!_/;`0+9[mu/˄4x5 7N$?-μ4MOUX%"l,4clط`w5zm~(?(iˁV&-n&%O9®ޅK#ep%kةKHir->^^ݱ8ԗy[{Sgl`ų=1`ٵ6O"S 8 =a|.i*xgT(vx?:3{FtX%%>- נX|3#)ŁW#)f ^9H'(3Hy Fj0t^~5+<:M!Gu}>Z49,ͫ%64SS+h޷9J_%jBk+^i% ذJaF!'+wK `ݰ(. |'N)k^WSQώflx,EI]T۬E6 U~y A 0Mѷ<?Fv *9+i4W2j3Uv Q]N։ L`Sw索>}EݛpƯro%G[& chX{jQQ~m*hW{*AS\ qS.WCZb-r_'p]%n=Yj+?R*Z2|>,t #K9j5JkBފLAdƤע#}`;L>O1-!vz +o.톓G+ Sψ Xj.kRX3o( $;&Pe'-C w7&^ۚh`)Tm_>xYpjCI>^uk9ר} ^\ 5v\~'O=Ǯ0ׁf;ٔ4 ? )M^(v ӻ{;P-,EQiFd$TXk `{jT e^I}e#b>!m|Y 6j)1,d\aMR +*φWI{jƽ?U!lu56eQ{)&wKHgPlx/îؙPػx-ީS5߸Y'_Dڭ2롲9 +H|z"n9 oQvVO:*n|ڳW +QEt.=u;OafC/WϬ=B&;vQ&r tLKʍSBYq[@NS{\WXʹjUjEW>VPJI?Tg`XVmB-Y*ukK.ڕ e/ОTG*EUQTgcl~T|@j p`lΗeiy/b}}4 Pf-[Tik=ҭ + yxhRUx=E,F_!DN)͆@ckRSW?! ,Zh a/_VtҒBQ DfK7h#m֒[6!w"lG AVu5Wd~"M!( f aE>K7HHa!QlWmRr(B`cÒb:p`,,t`:QO( +-5:f]kF5XQ\ Ԇ1) x L9(R=6I'vxM#zA)L;nk$fr&`,PORe5%X`QV|d H--&=P_$鲑y}h@>{l@ +"yP_|X;ku"{j`ZӔz)> TMD;ОU4hAf캽ڵ^|OԏDPu%Y#L1wPFEK'GP_NW&ߎj{U} FBٰVLLX >PCksB{Lދթ/k[mg5z:+?WM[GݨЦUJK `57m + rrEN>txih\xq^aV2Z6(Ʒiր]5g:4Qh!>BU9w!+bE,V"E]!5,ƠAr꧞N +q)e|*Zۂ<,NPr_o*U zBKe +ɘߔѦz(pPC1$1gnwA[0 ]dg.jNnV,zC찮×o5Q +@1^D%U ^soW336m{x5" `*Q#/EάYЄҳD# +{KsPpԉKSZYԙVu1>Z/t7\BJNhOUj; ,- ʩtfxG>7~!;]*YhaUuCˉE,'x,iSv.P-B8F6[V, !aW +1Qzif-{(:,-/WiE;%FlgTaISࣺ1z7l'T.շ Ԃ鞽/%jnftPc|.$b|ɔ|p(E+F)TI@\2_c"b?>LJKyOU.ll]>aAnSXQ%0;( J(e&C*l佔 VxxF# +5+ŴPsg֝W(CSB j+r,dqcZ(>g,DuOU01˕o#+n7,TiQ:͌nV]ȅbW0T)Nuh}\­t%ltk`A*u%]JQUݶzѝӶVBq!Nwo CXa\"`K!bʏv mR ) {}zy[Ђp+Xqbe .hq6, cgtkFL+TRVcV3Hא83=X"K] 1Ԕ{4l2$3@!Bk +95%-%}Q*I7mxŅ\H FLYd˨')nmGzWR,[)BhbӁuZiʴ#GUZ;2~@`s9P >ֵ?"wF^d{MBJUjuc_UJkAxPŖ4*s eeZ*Hrk \9*Ty;fY]}sFzSvLg} Ww^p %$+nU*^2 /O&Nᰚ.=сIvd-a#w>ipec6fJ' + 3^%ʫ%e>8Q[Vڴ@ R].TW/0@;{6#Z`l2|_2ywXm]DKm0kvimVzǬV ZLTAzl4u%F2_bcZ\>ۢgKUHCia.G6R) ÐQhHoCT]j=-hdkfѵW[1f!!D[b"Lsz_ Z݆$.ߞtTOjR/<nU^?M&[T_C?~`+\t1  T=P.1Adlm;6e)K_4pͲYxc2 u7K^ +{mCfYQeX877vR 6>#%"uiF2z˯xda>f u`뾼f'Gb%v"! XTρLCziȎwKP2kcmf@#陬iVljY2?}F cf+) j()-+1c, )jh y~H;P] һ ׶05AjPniHR ) h8k(0 J|m3}l@Ct)8o+w*~߅TRi&rSQ^Ht$xŸۢ3\@}EħQM'mͦ!ɸwD~dĖTbze/Y/#&V=_EǚjJ4e/La%Wyh]¢,G!ӣƀ7*/%f)L$r +VE,sɗ%I 'kcފI挀'ꥩDz>caZj&P~3C ]9ͧ)pTs-yBIYAV@Pr=FO7F]DrJz^US +?N(EXD[Gs 嚕BWر_VًbW2#*Wk(׌"bБK  dNr☛,9PbnR #;PyDδ嗊AOLJ3[Ne'jl'J6VM`D87;2{'|;Lv`M>k˶S0R ܘj­p)2DNzdoxf9~EBqa$}@Q1l8R.oDV?l"&D,Xƫ|zXn7Mn%^+ ڼ +Du/_8t&@Mt} ۿ}w٫:nEU6|ks%Wk-.(K%91˾_y-cWn4eP-vTsݘ-h"7Ps +sfCfv2gih}r =TOf ֋|/_kz9wEA׻Jжcf{0U|s5;AeChlbCHs+[МIN@s/ Y.~1PD\y xj +sc(Z6aOcҦ : 8.A0DC9 dJYLi(&@q#;URKYO^@μ<;Gl94fᠪ*e1)dOPze +Gk߶Nȭ Ȅp};7{dlo[3.qڎ+u* İ5%O~"t\y5b)euÖ8L~˜ë،ѱrn!xc2ZGَ d%EJHRz[{[Mqo*vaeʛvI.L^BGD+AEIEO.l[r*O\./n/+֬KՆ\h(uVD'V㰬7){+&ۅlӚbU 8[ߏy>q:V.V;nB˃0ӗZZ0?D^-׆Od=k/g$Jƺ]iwTTؿ`SR G D*yVZPox~-7 VԻ`ŊK'XQ V%H`EǿZKX%"R2Xрp(i+d+VmV5+iX.K+Vv"'XQr+d},8? 2z]`E>גuXQԺޏZ'X\A`ŢC&)xB@+BN`E} V,%c1rާWUX ="SIJ`E)±zVKu~y+P]hD|cl`rI b:3=׏UDL\EU,2xܹmAz}*r;W޹A?RJUR.s\^W5\&Ulebo7s[O"J*6 +\ŦURpm\Vb7b`kZ%bkUDL\EUl0>3WQJ*JUl*6,_\ռu|*J\EL\:q%gUlXqظZѝ(㙫i4s߷D|Or_W%q\\EU(ObUs\\Zbm Wʷn=q:afKdxxr5e])WqSJ\Ūz'WQr*q5~r%gb/q+6bm(}*nU\rp72WQk/\*O*VWq)U%b7b-b*V%bUg\ŪƴU| q+XeU 흫3p%g"J*x<ȉmo\Eə-q|*e" UU-s Vs7eǧm'O\E}/\E=cH>qS\FKU WQOD*jOq?3WqUe_d"]*WשU(O"U*({*j ~r7WGUܔ*2'"%qmظW=&\EL\E"UԋKI\%W߸\EnU$Z*A4Y'p &vb<0UR2WN_U(ȩObWQ2sS\E"X WѦ읫T*.e*Nq"Д\E _qipd$";W~p&$"j*l*❵sIz$<\E"e* H\E!\E]/\EB9;WUTl WQUg=WUp*zyr%g"9UUX"qb*<$gvF*u|rE\F Ul>6~n\EU|kx\Eˉ<WMOp탫(5sd"ʓsHVUdM\E 2WQUdJ\EM_߹(Obár*$">Zd~B*>~㣅WtWQ{aUDf\Ej~ȇUdI\EWp+ٹXDvj\EɥWU*&"um\E)ܟ\EdwbWQ/X)Y۸Uٵ'WQiUQ\0S|*V7;WXl*}r+;WN{pU$fR2WU(W>Uԗ\E]U$*V +v"͝X)~pub*d"_hd"OUTN W*͛3eb=7UԇebUUԗ\E[;WQ W-sWQʓ(5q\J󃫨/'L\'n'WoWsu"r*V Ur'WՍ}}\Ū.q+ܸUo]>'I8COU|\E2㼒^6R׳(&BKepyi-sUP\E>dܙX0>W1m*2=Hp**H,q6Pcqup X&l"-K;WQU2 WQgfƷU$D*J\E}UDyrk8Ms_Z%ebbl*V ="v*2Wzp586IUWQoo\E®XWQ_ WQO**J*RS:5sUԯ\jk̍QUT[*2'bW9qQq3WQr*f+\eXW.'Wȫ%q e}*U|bU=M*VUD>(*O1RXgb*Jxh'Wqqi'WQ_XHa~rȗ5+n\E]U!_>^W*jHiUz*Wb*j\EhKWsrUX\E X@f%b +hrbUDN\EU(9s+U;WQb5;эHD*jRWQ“Xͅp*߹p+./;WQJ*j=X5\EeWQe{O"=چUTIV$UTb#nsQWS\Eə(e*_H&"U WQr*BI\E)OUR&"ʃo\E3WA*R֙HǓXD\E^WUTh* Wr޹:5sHObS2q3WQEOb{]\ES6b:qqWQJ*JUl -\*U6q?4\Ez.WQ OUX* Ud5&WMshs&"m4O"r*J\E)_4$ew"ʓUTC*c}r-isu-o\EepZM\i\Ez\EVl[*U4&U4Ul\EWU ?!W";WS\E~WUl}\E'hF;Wȩ؈Gn\F~Uw\2o*r\ECWk\EzWQ_#sU]`6" zO5m\EBNԓ(y*Ҵ(O"U$UUUԏ\E O>+q%pM +.fUU q1N\E{|pY[o\Enr*{rdV WJBUԒUTV*x WѾs\E󅫨et*j˖*XUTe**b?ʪe" ?"'W:U:\E'Wqs1K\Eu}*J\EUc\E>1qd/\UĪ2q5*6wƏU$*\EbwHU޹T$"UDN\EUÞ\Ee"p*gq ۓc*.%!6ٹ0$fD&|9,S^*b*&"J*zr '2(U߸s\Eg4xݹ" (*nJ)S!1*B*\EjX<VD>ϲȊ(, yݓZ"+Bxa;dEܪY$+VYQ3ͣAVĢ#Y$"}O"r"+oNV|&+{+(`&+2]?Ɋd Y%9IVȊqYn'Yg"+V6;YQ*_ȊldEY'Y9QY*YQHNV$$+dEݖLV|_􇇬XIUdELdE)_Ȋ2Yn"+JBVT<((۳/dEVQ5BVDNdE)( YÃDVdGȊ-3YC"+6C-mdE=_Ȋ"DV\NVjHdvNVħ8ȊORh?i'+jBVDNdEDV3qf"vObeɊ'RRq&;YQ4٪<Ɋ$"1DVdGPBȊ8"uj&+0LdE:脍t&+*H|:;&"Y'Y9db[AV$Ȋ(h<Ȋ +gϙB,{ɊdE5}!+Jd8|!+"dELdE>IVLV dEm3YQ +X'&6"JdEDVJY9Qv"IVT-S&+dRY䝬Y2]"+ YDVq'+ YqydAV4僬8 +RȊ*BVzԝUY&+.%dEbgb+AVԵdJNVAVDMdEDV$+/dbjh'+JBV$1_LdE{ZdEeH&+nʎN[r);NdE<~!+CȊvd%dũYQ p!+YdEm;2Yq)hNVTH&+~!+?ktL">O">;YDVIVɊR2YcdY6DVu|#+jdEYq)ɐQWIdE)$+QY~郬XzɊ3Yq)NV2vbY[ȊfUT&NdEM_ȊlHYQ56<l'+LV$JdMɊKb[)4&CH\"+qLdEO"HOa"+0ɊSHdũYQ勉&Ev&hʃ +bȊ|!+ +h*W|dE:dE5eB{j/dE`YQ=CDV\r.ɊjBVl'+V&30LVoLV<%_Ǧ*'VQBOTE( "MJSQ +fqq/"{Tv'M΢) +lߜLQi9JJ#ʣQZjU($QvB)ÚHω] hmq;}L*vژ:!j֢:bB~ֳ-"v.~>#/J&=Q]2G)EʫX_8:q8||.nJECTii&+ wtYi>^DO\"~-Z83%v哕(KZeTרgDXO)qNJTLviVzH>}l<#>.k_nQ'+& Q͚!V&,b)`-(ĦᲑcљ7J&8&j흙HB|%@Tq g #"Y" ~ >הbE {vva!e a sQz-bһb* @ryW=?ex Xbs߳5db nE@,Zjz.b:p"Q:P<"" Jedn$ J!3 Ryrx$ ̮X-պY1!%D$ D)ˇ/0ROMNq' jkXT@2UQʏpq} ( ?(}xXUj&0>օipleZ?dRCEɡYb3IR $)$R=gcR OgePP(t6tr{J yd!f=D%=:oS8p8Thj"an&p ;pA7Զւ,T]W+ 5ޖ*+@l86\s "XXÛ6jHK°zA.=́w^'Y*lIDâtXvyOaGP2kI4, +NDbK+8,K R N 4Js0xF"%4`i!8=}xr'ku(LU K16SɣBȓcXT/D4/8EVcXucXv[yp ,PXE,*SU0-0g-¸~L!B !S.u" o1C [jģv(av]6z!aױx>bЅ^Jz/nz2֤Ɠ1:PbnV3lZrˑ , + 5Z_ + +BU'XaT̐hz8OZaQvDVsB;ZaP +yVX*L@ +%0# WXT~ +]&+OȴB+x +Kq +Dnv-u3+Y&X~z +{a +ikЄLi ł{ zX|,1S *sM`Q%,*ȸgQyspO¿<G(pQ + q>pP +#9Tt#J.9puLFxl7իQ-"TƒN"<# B&9N +r, QwgU)$R??}T7*yJ`͔؃RT18yv-ѭjr Bi%l%tP#\ b? {zNqqJY\.p +SWyYTΆ Tx7 }7(f6x#(ejnT[qXQ$7H{uZbz9uӞp4RZz9jqG2p%|'nP +),Jt:nP{Öԍj7ˢ J\L }g rgS6([2fHRB`|}p4 3 Vy 6%y6_` =~:ջ}9|bx6TATgΠTp{Q:dPk62τAm`P6dZMV +xA'] W  -],rqOjr;wuؔuO HZb)}@ +O d3RPnZ&Rx6)HuTD +cThw'#x׵RM J$ +hDAE(y}~ݴ@A]4bF$Fa);lc@Z۪n@AhA] +} +վxz0:"4A +۵`Ϩ% MB jrn^$AȖ:g^A kao_Ll(L;ԿɅCPqg}s oo*+?A  tݽ46!rx70(jTPށ TL}4kcɪ&(Wq?ަ@*I *: F݉ɫZf,Z8T#+P%Q5O<է۱k!.5euXHNTaAT߬I,tI ѽWCդ \u)TuP~'4T?/mc3܄3IPէ +d$:ohp"|.a^^;J{!P +Jםe\ꧧO?uBL_oH?D 'ѯazAÓw$zWN#X~~40LMYl?P~<OKmK'ζoۊ2H~DI~Ym +m6+Q!Q~ȌCѝ(?)L(?4 L_n 'zO3,G%ܓY<5凬8a$P$? LSuڰ?;ɯɯОvE*O_irdv_BI~J8$?5n$?(r, o | [jׯ+I>A~(,g'GP$0I'STjoRQB;ω'가ǼXL9.0~v!)!:-0~|F)G@H?>?=,V4?jH&_!_өV_W׷OYO_a3 q-NA`W(]~pҪ\iSR 1)~@xs?t! 'Ư/c +;N|%_/]&Oo}XQ^júczGk'Vl@20~j$Z0~? D Jl*H?4tƯDK-Xd+oŽ%HYfƞIubba&aVd91~c?^?0W.2ƏBy^ъ$?0q'F kT31~ U`jO_1Ppƞ?zRظD^)+}I?NO,J%'M;O_V3A,{QHrGԄ) HlBԵb냀VG=)j?V؍O +G~Pt*(~tJ?s)ca*>0~Rvd 5ZMu/xŏl:VAڵ ~40K?v+t^p2FϹB(S ?}DSIcoѵH})cͺ* ~ACjXXf)D X=OϲE*O/u-_W'"VU'Y+!T6`"$3TEVb2T;O*&Oa,Wf*Ogk) vjD 68h?~ZSCߧX=B??:OGeCu(ߢQ[2u NC8mWrxZhԄQ=+*bDV v4;B'łBuFo6Z}> V9}Bl}>g'Jfvrvcݧbx}6TG%`7zR(U>d*݇ƽ}|s7Wū/rj|p"_yl0?;llIvtR%n H @UO͂G݇FP}R>VN侪mA.(nݲME6ag-9}2O> $vݷ)L9}]}+Ov 9Pvv'ugI>)_}z2O7t}ZX.%eMԼh!B|4}a~>x>UR<7}qs!l>Ԋ2$, p[G#;zLp@_(LbֶW:x"3t'YTDSjeCф؏}dzfV>[yOtSfg@Cj-$NvQ)>/z(*1,|2J}OOtݱ>bXCƞ,}R,1辊c::.}՜`ԁG>3'}W8VSš{oSvxߒއ1hOh+ Gkh5z m|6+&+Ӡk@߇L PIOcY{] JgTv~_}YHJM6}-``tJ>>Nê}KHMvEF+a}:$$MNkYL>E;}K+:} +@>V0>luGfaQ'$ŢB"_u_W@)fNObk6Ǟ =П?5M>4p8}M2O95j8oxqfIA[G靜ľa*ԉ#1EԎoOwQHɑaGOrp:~?7> p>|0dձ|eqB󡞋ͧ{s_wFu#]^A皢Ã˧ ~Rqg".3=H&&txyhu݉|S "tH*}xSie& [J-9p|hk,Cd~sTP|Wwazi O fA[u@{2._= 8 +#(t=יzZR{@[YZce7vTw$Iۓ{TO/佥$^ oISPOd>jHLVwX){ ]{.2q}= K;oh1ì'lO d=}UF w|ڛB-pISwBkBؓj;Pz q~>V2z֛c1hɢ(ژ3ΜwD/@M@=*^ɨv#M0=v+LYe.^!0}+%&}=TK\h}q1#=hz,)%̔vir8Yj+]\Cߖ@9BfYsMsC$ȝ3;MOɕIjSAOO{4 ߜ9<=<=)B'OTaYo^Rx*8[M|EՑ~g*pz +[iˆn^؆/pzLVM8YN fN%+a0ʓ'n^ӓM}{pO1hIZшol RrS= WM*'N??pzȬڂǩZΟ|zxn/\zD+qzMo4Ln; W j~+&No) i_g̊ANSِ]yܰF [қj"p4Qz% It<vlJO*fA!˜PzNJO_߉˕Hzk/ RJoɁҳ?'IO;m"*L8bB)l8@$ɭ-tJhh'}7'J@z.$H$=첃W`:otG $=]K^[[j iWMbɤca:Fny-| םyni#+}GPǽ_"O׿~~'o~_g~o|폼O/:E/y/}?_ǿ~ /?˿>HՏM7~o~~2/_oݟ_ǿ?x?T׏_?׏7] dF)K// !ɤ 4Bn%leUf#ƿ7P(f:g?_OG8v{Ab8v@᫢P1p[w;o!" ACǓQ45 u*=N +@\d2CNT.Tᵮ秎7ׂN4CQSC\2j{W;I*H< +_@*ۓ.~G?kseU*yJiRq)E'uM3MrΓo#I5霴s`ẜE=r2oM@l)N{)˄lf +l +L +&!pqA+hUVϱ?iC*N>! B"v9&;JȋzMh{aKe2cPl{\e83v|68U +yѦ * J ^D h;}og\wZSТ܅F`{5T1^אbx|Ft0AgYf翥e PQ-A{~3dgdj(B“cĤa91xAZG\w<&L9v8M,v*'d:7X`UPFu +uFQɨ (sO{1M{ʀϰ 0i'(޵f=DbxeyvJuJ]|D$ЛiPV1%y7'z=Q +4j +Uxz.x;3$@ʀDs@"L/ěɀ;?C9TW:y*S?**½k86X1֪klItHis8"hU GS.]F}S:q]Km^S eRQ%jM LVTտkKq +Y:lm1izYR\jSb(K,sꔒPZޜPY2G㮒3wMrw; DbΎn*#dpڙtE)f_[# MݟHe2G]9aXD@C#jwXzd9AH/[>Abz]`wa~{7D5ݖP򡦐oNUJlps6=X@f([f@N)"ݴZ ݺUS g[͈I#'0p`Cj̣GTg~Nmf\b &Nf(3aWi_!z(^(A3Uj~ɆTä- Dwcl=0ρ +x;!Cő$r[rZ9gV@qf5nW6h6se bD5 \%z!wl|s2CSyd)Љ``1"*kEz6v +)jlx<+U-^[#= ihEU-LpA@M8螱>6! scV옺n/PbIld!"+bGAL0XEߪȓ=JiaVx,؊5wgF15 I/K&(J~ [δMޢ2R=aarJEuz]@3zֳ~ " *'fϷc{i*<ӕjt+0tg)8ݛ!XPBw3y:xHpѱ*w!%.Va?$(OH.t (0 @eP*m9pے(.Vᡪ'"qޘݸ]r OMqa`&Bn]s09#PgIT# #'0g;X3BU{!b XUD +ߏ\5z(S݈J/"휃)E8m3U 6D< f0vm\V=aM=0=f`Fլ-Avbllw:8v1E#/6=' !sU EdrU^v=)UJxX9c{eH饉d!lGPjK݋Tmq'VPZ`SH3hTJrvp($f`Jg+ˢ}VF׀*$Ŷ'/$Hf~<e3P.AA"\R`CQj[Ya6f>իe ºZɉЗQ}t(1*SGɠ$X}2YS9VVNK_+F5lSg=w  g,UN"^DLX+:噡C8/0AA᫋8Ls+f"Ó|SMˋK-nAt ilr t:$g?NBX%MR[R?dT+HZa'̊1۹уz +HM[ԃꖅ=5kW GӃ"Fe89p&גK!C +WEcщ!+V #j=#STUz@^T^c+^$d`Zx 4)^& Pf9iPt2?[FFe#*Kn $xF6 ɗF +1y7U;J$^b ,]aʬ Qc< u@VQRm,\8b)8$8w=*Y Tf)/@ L+"(20n.3Ke·AݳT\l=;=":Q} ʹ$r Cƴ~ߝ: 4XR Rgd(2hWlmF@N4,jդ,(G)’"R $R@/nQ*Vxl^;K{)HsH$;mUwr& wQ9ym_bt+Kwc&K9\dJ⺆_gMS"9ҽC3jOм=hUt롈=)WlIx)YT$}v--hJ3S-`y7un" +7;fUG1A)ga%fNߋ"k+E!-@ag LEwy kW5mG,$+a9HqN6ElCAkaȅ~KyfI))=Tu&p1D^ G]LXe98rhq!&]EYQ2$z{3.F1M= V6U +d*\ጔ" &@ h0`p*9 D v" +4,բ'ܜ³TI5w~ZXKV\7P^0!fC0 GdeЙ:z$f30ʃ4MMrYLqCIO8`TPSnxm kg Dh\QΙ,{zb*f_GntJjJ"P\`~-W.t@|'45v66sɆ) ؉ d@(EjQJ R_ 0e+赶BqT(caj*εi..T20{ +,wfJf;HJ;|z xFd!(Z&q SϚfYYFr +6* +cT49?b庄]AY' ,;fjl:G3IVרgDj fT<#ڊ<Z@D\ҿVe-frUʯ6 UrCAa +4R%{09yg$3ט6{2͞w;4lnmbqi!U,pb N(^{LָR#ƲHA5+la p21}Qz *@g2zaO&qHق8NQZScsxl)jڻ=8b۲@rmD/Ȝd-NSCΛ?u!q;\"hL*9I˪;Q)񇗦|Y3QO3p^-NZM֭WzFVe!Kߥ[xZ)Rt+%Y_&,Yɪ%zj5dF9x*z&5eun;-eͬ-T`{,ڃBQFfum\8n*+; Kת#Wg9+r}\9G6\J$R\Hb=TKN ,ĖN@5&{#jrx(!w(@E2KEpXhfs:skl٩lB +WyA^:wgNBU"'XN^]do@u#Q=yoxs٢H*%SC8|1S(hVJ27TYk@=ȭG5:M Px+>R?*%3p7:&vaRzPM0G=a&[&թv8/un$%s1z-$!b4X[YT"4*'0kve2|m>o=hY862K6GVQdKXW1yG-iUYYּeP7-xΡMiڇ")ArZ6Xf>Rd "OEF͔$!7#n%MYxa`J(mv ẉE "p"Vk6s0PExlmkŘ#@u ya qW@4.+or`9t? ֎J' 0GXl +n]G-n *R~+ f0(l(-3S %W `(4X䗂 zT}7=l^T](L vUzԥX?qzȥ.YݜqNuwYM}2\pqqm*iGV%nmadbUgt-q`h3yĽ)#"xt`NN,+`baq*TLytg !GoutM7I^ibzuMF#O㈂x"Zɟ7&\ @ qQ +odfۻ< +ݹzT_ ClK:#NNi Ӆ`% d: C4KtڭEt2Ljuy؆C3*˰tKn0rI($l-*e +amM1hnʧDSEhgqJz00 h971qM-yIQujSLep~ +"N%ZB R)Yrց&iCKlmGAƼi e&PPf2g1@2+pWQ 'Md̀h^g iDՂP@VshEOe$hnf@ipK#[S5K Ff ФȜ@F3~7U&hfbDܞgyf$xjH(Kra\1Y`a{1otpSxjش_ii¥)'(rZUvH\7beEDT2TR"Ehhܽ{?8̢wXL.VQQ8{P#9UzhZM14iЅpY:ڳ{EᫀYL&?%=Yy^KhȈ\؈Β7A$JvtqP i\pA:jכD|_,w҄0"揨7ޒS*{~Ɩ֫-BYkTL\5w!ՙ9!,YGt-^-`SNUSZjYdp zjI]hGEF{yz;' +͙SXE(lT<T DgR8fRU|vVH>stream +2)4%wiR,(/!zo]+iɪSҸ;c9 6S:[<~"[ BW@BFZZ +U9{tkWg4? ϝlgf.|I=vV(LTTtƕbK.X8oaz|ԥiZyyWlIm/@owZ4 i! +Q,rX%ʹFE2q #)o 73U/8AyR?TӸ>h ^ajE" RuaփeN8!PTp0f앴`E4B^4tLHp+$a6khU^AP;YHd_D9ᠡ +*h,hɂnf|tI ߰)uºyRN2=ː5蒌 C zAtp-<)Y~ =AVq| M1PV'o4S+rrj\J)fP<Z-6YЅ)Zr)o׵*1M[lp&۷hN*1*xHMÓXkOa@)f7j*mg-[ለ-JWlKfI1KgLXlªgo9c҃3ѪVx* 64f<|3 QjXVdHx^#zbУH9yC1_j&c̚5B0M8vT Yױ9a *F*I\uJ n8skE?jk.Ms,j*(dž5AfPr1bҫ T4rlWq)X|hO(ZЈj/FDhMJ +ˍNWQIHRE ?cP$&>4y)2, '#/sR/ʷVx护ݤhUDZB:U*T.̍"t[.[D lɦn9 $ebD*U-RuZC*0uW)D@5U)D@u׹],9=U TGB%A`lhU9px G󥄑1Raܘ !0-D;5f|aJHo704eYz^DR_fYo>gE@u"(Īv L՜zsi ]jERdd3I]+&!co"zoceeU:CaGБl@sbn\zB*q J]8H+#4%jt{!ݹ<`*''\,tgdn<7yq($D~Œ,%aZ倘-`dq1gh1YyfyqN鰧6Tӕ1vXC3j)OhQgCoYB/t_oh +nމbUY8=!Il$sb%4))0V +l=xX)}Q+ԑl.|8J]"2T3Q8AN+5(A(51Yalpne[7ݪ0dәkZhCiTE͟ޚù"l1z;ՀYTžqCV8eQZy{<=zR"&)̒#_٢TexW]2b {ލʹb4->C +0J&"۫DTg*BQ*=}&.ej!HH[xyp4Vzj/StkIe ~P  +,AF`4(|Zӹ%Z<[Y3ㅖM|k /|rcp*z f=iw TF$yŖ#U4xK|L*)h `9rlLC qsnR۴P372#wPS`4>ݦ׷.,+j$j_uT2:Oep>zLcb& ܦ';ycp6;"XP(ߏAMh̖ё'T 6M(QT1k ë”Kƴ`%S#X*g \tn LQdBUg8 &GZ9sqRr6)9VO}ܶ{-5d/u R]aVIk"̣wqlgKEh5ZK[em鋕CFU;F?њɳjUokh5dž +6NgUd1Pm,E@m4ylρchu}_[n>}o/޼zWۄ_.n^Gn Ưoï?_2~߯[}V/'_n,PuYLj7^Q}2ve7tf4F "E>+t60x2}\VD~W@9ı$Hm߯0 &OW!?c_Nat2# +6,D,? +!/ Ps<ƟWĻB:cȮ[]wjѡ70<:xi\n]÷tBu^|pr9uޭ44tڢ +bjR΀3؀dgNށZ&_^ 5'Υ44慸maBn/k x}\e,;ZE)ጠX3F'(t3Ҁb:=Pi<0iotGѕ= 3.g8܀<6c` Gg [|ᩡw=Z6JgPƠMiGMr盿5w|Fǔ:8uXN'-ֆInp + +I{s>ȑ~p}Ogg'Qd~ooft/~~׿yE?|s}w/nlLo^j'6\߼|aw|f#͟?'7.b py+_\Mw(FMLoiIo^p([w,oY(yڴc-}uw/Ž濿:7>zx7o.;dopyE~}X=Iֻh=E9Žs>G9/>\^ŷ\_/jwKAX{-}?[Wo_#_o__9~&CϮ^>>4tӓn$nzMO zlP9n~}vprd(I9=)'窜~p⋷s<,?7 ,=??_:^Ge 듛oxv^??c3,/G/o.''>o| j'JxLX0(lTbq;F>իW ͱܤcI/Xz@:|od\]^@Z1HVϏ{3Dv,"sqwwuA&/kѫgׯ{ŷJ7~}L :68Ɓ*G1n/Fw)H1 {,iCpX(ZQv,b]}w}ib'xj?GD75hf5 +%`=揵^=@ƏlЫb)cDxu}ssP-=eˋhM_<?˷o2_Z_˗oߗ:Jָ2_״W٣*Iw׷ &.޾~}}qL kgtNKOl&=ȥv,SҶX#α ]:v|\K?o}إv,t$;J|cXڱP'tD.c :':y_= +y<Տ/ZN/:'0gZWwc# ߉Ptpz߉Ӆ;]. +]<@w3dɆO «LJ]ߓO9 <߹ʓ?O~gh;O~ABWo(ql ?ۇWC7z4@;R +p><<2p_~pqzm:oHNu7TؿhDœm!~]~xhxƊ|$TXHW<\<a|LZXW#9(-Oj;zy3*.~콚GZ#o>CBi--oش'шx'͑oxs|z{vƛVt2ޜ7'1$Ԏd9ogW|7W)J,E%8m9di`9Fd8R'ƓmxIۓ)gȽyε6^R ?T.?8CKsۿzcT?;_o=M##`Kc +:>U {ʱ`ϿBs0O*칢S%S%? +u.>{dQ{ΧpD@2e'GIAIA} :)'>!2WC$T"'=i' > 뇷o.gI7=N;=hIG竟~+g{Dy*r*ک,ʞ+:Ey2e?QcRBuC-c6^߿/_\\+{qyGy{X XF7/?Dd?b,uׯ^= hǡ;WT o0ȍ'cU%_=S7>/!4P:.\݌f}gDJLϘ=|RϹFݩ4{{* v{NO2V!PYXZsBO!$Ԭ=JT)ɫJO%:v||O'^/8'#ZGCX%? |f +>&=i1x1cˏWo#Ƨho BکLQ2 r] PW#9O:by{1ۿϏd?|26y΢"T=o+sy,sZַGYo%19\n`8Er 9Qx,e3vxr/#ǵ?^?U[s'LߝBF鍏ۻ3zx煉t'F?} +!B.^:࡜'x;~Lu,M:&%>'O~rssR~{<7p#X菿* ӫ?]/~-_X.nGnGpo=<-f_G={?|O7;~s\}E}jPWƿeߣIȫWi[5;s/R1΢zͫۏ~Ɛx*5ȷj/j }EMɯ.Ij_xW*_hwjs*%y^j Jlc +6P#5`U|Kr|s#WcsŘL+c0"V>+ >uq|R^j\Lae>zXaOKLmE{>:Ksa`i>ݴ2lt_8RPi)}5|N5Vc<,{W +}5M2.z0v"!56Ϸ=.c1S G3+Uh8)}1Ɯ֘x ?ƄC*X/u]ǮƐyBoxvsq7o1)j~ݿlۣ=k7^}zsuoґwϴ'V_ ӫW!}-**kkiG(}n vQ> 6UjqRAE_zq+Wg.@Z@R= J+rb&+ǜC˘ߘB)㮆qG`t(> q܅qxDv\A-i:ݔ񗄭M:.ؕ@}5%'RM8رغq>a]u|^ Z%qƴk#_mkcр17bcd'w:h t"PEZMǩ;]q0ڸwzƠ<DZi+Q˒qA C)`z3_ Dʀ_ǪH7k٠.nJy&mlՠu 󸧑DG9ilB4Bz<.H{ςT@Bt +3P[7!&h8dqbܤA5FeFj{aҍqmA+oD 7.uۗv\c=GӲ#XJ +3. (8}FcqyFA &h4hč&Lx3>MeFz>X\Y:\%G^JhcMG:p +T-K8= dCe,LP>+ <_߈XNC`6Hטi&@;mꢀc+!%B2hf ffkr' +8k .Luuh2n}H/ U +BiGC" I%@'L,h5悵 $T_y &4WBqB2o,C.E8$|KDUqLbY81O\%}"-"gNCX M}o%vWc=!`e9{czEqt4Qб]DžXBa +jP <H9(VPme}4\q _Hヌ9KJrD"\7$H"D`>n:knkn:[%=Xf"(#xи)ĵA' i[:V}#6«IĘ/"8 lWrp$oD4=tƆt9NL,,x,Rc +Q@Q0l/+ ?QKaĴ@W5D䯈9$g:g&uC 8Z&=dr@ O8i`?:֒XIBD,t_E]@FL0ώu>AhnUp`k&TI ꍷyȖt=ؠMXw&BX +j4F2f$]kva[$] 8P fs\b攻|2Z&`% oL+_=G:9oЈ6 Hz5T@L^'ck+)'N;<_d!Tl$3퐈k']!zE +.f:Se~Uw7n([/\WiT̬136WՀt ƟA+vuc!,( Lc]BcQ&@4臑u+`ʐ3=߀^r$Qg*va$]" 26qPP$'rajv0QeJ0qV1H*9D,b!L&N +l9ʀIȂ0 >hCZK E!9g(Y zJ!zPcHb$l 3A`2(.ɑ Y" 1 @LD#YDr" ^p'譆N:(ۇ#40HCucp29nk ?WGt +q-jC&䇌QG/?ɖ i033H@fAo+k!ΌB};9F7tf%X)&YOb!{AX%lqt` l NVnZX03r@H {ڹAa%1K 2&MNBӎld*X圦F~Y: 9 +@8s(NPOD&"eHѰ<8"KMYxODY&FbcKB$F>38y;|TE՗ E vk.^k,(4Vm`lj+ʑ~m/9I(80g0Pt$(c&-:K8x}|.l^"^Mw񈤩J$[9;:\ 6 9&I5M[]ݨb56RkNP+7.mo/v u~)$$25^b&1N J?Z bڸ1[5nLur/90rz +*Gbg'Q&I d$ t8IaEO^PlU'wnL+By_BsNJw"U!r-@j!QI>B`b@,X6R: S+]n&;,S9T"b$36~Qolrn)rdg;溵%/E^C[]!uճex-d^:\YuQ u,$1y\0f 0|bܯNAȷ,h.NTa`>[f ql0JPE+' 'n$$aUAؑ($zAlPP]"PA3/X3B=+3YS]qÖ<~5BRNFjt‰;cG @OpK-V"4BTԱ8;'<p(ֆpa )a(J I qH:=d-6db"AMF]x̼\Ob#Q9ޑ GdgW`2B!^RY 琖]#Q(+d$ X(m1ld[dwl7ͺd鍞A`ϸGJH~c0I^ĨlgՌqDFeIqM obL!6#UoZJ,U2fXH^8DK"@p< m}B"I $8@6el=?dbsDT"D d!TތK)@olB_Z<(!8 +~BL0N0 4>=0o - ֒/}ڹ0g0\@/1®8Hb; .M[&5"\ 8y&IA9T .)vK<ŋb)9mp`s":"ga%+ؐ6(2t m猦X~nwqO,2|"`D %HhJm.™tld.R;a) us֭S`ށ m2Dk~lrܬw{w6]@ߑP!ɺJM/.ORCQ2G8Q 8н +IdM@ Lkvkg>\BC!WR + 9D/[' +XC(hU:`ń%#mFBG,:S#fФA =p0B>i䈣TDؑ0_iK6N'*b/sQR儵LGxQRAF<HqFl\XHSrQ0p t8@az$B +3#ÙyyAVbj-rv/7h{R0$ MS8 zh9L&k@da ^kJCnpY|⺞Ȃkqm,F7!d!6#Ф KXn}JS!3rd?"@v 4(c /^.فa[Hzkww2 T(,yf/B=./"BbF%셓q,ޘ;t9e/oBw$ fwL[˰Kqowl +yEۼy֌slƖ.-"SvD,\w,cwVV2A6g3x+2m!a3K"\%z!a K'~d@Exxfz51Ry7?

[DgF-I%[Z'2c$#.Duǫx5 :D2P*"B=&BUb832{}>(<*c@PN6J%ŀr\"\C>'Ybδ"li\vu6I&ilD͛IBTn3`cb[ YV,Ud\ׁ!`ճ -#wdqɍ6,/ܶv yQmk8f}1btG).,8VPoOɩ|N}SI縣s3Mwmm-.gp{g9{)_"v W;Q)T*o@Ǻ|bJ +iu`F8p#"aʒ%%u2&Ά3U%on}9_7|:S+մc,<99V+RI +@á-q?Ď.D"^{IR"$Bxcwo+juR+qjQ*UxqJ +:E2syL"H +QX \Zc1Ϸ5[݇ j.-vrg +")3cG5 +Ǣ6CbvF~ +"[\ ZR*e,#QU"3ReqVNO`huPVQ[BwNl.g۞mo*>vwӝւ-NԦ KmAP{rrTAA8qH2hIHoJm6=2mw!Mm27K (b*Ez*<(Q[j>M{{_1rǠ,RҼ,LKl0m0~mZauVɟ# C̚mwƉba vfFVS M Öf` +3fM +)EvݦG\jS\*K݆Mg-dKƁƓ&q-%KɂF2jg2 kE_82npF `VeMav 1W7:;V<j`у/:s9+\Jx).Tf͛ؖz%+ʎizIUwz*Y +xBM\)lH[AU)a >S% U45)bFy jJHXg[hDŚHG&=[naM="S +ʺҎȡ#l.m[`$1cy[ѪO,+& GD o?cHMŽӜm.?W7xC$Dܧ9Ǔ-ȷ7,pI$|EΨ@uQ@.o΍˶ Kdfd. +bjYȖH$ŋ5X PbxI?f싹 " u.O7BX[Duc9*"Մ^ ߱> s֎4<8zEogvDol.iXH$[lʡ( ҤixB?*ʥn 0%!AQeVyCKlDd0Xӏ&AB:!8m-.(YC8&B Q9 ]#Rs9MD[vV؏u-f,uJSrD3 Uz ᥷SB&R"Dg Z9Cm}wӀ9-b1z?JyMJ”|l*ֺ7$淪6z dnAo1)s^>M(2fQy$ڙ)5󯵡5Z  t&?^(y ffh%ЍKZ8c۔"YOs/Xhvĭ4[mf۶צ5QJAO3lvO]`Òr;cc\[l0R%^Eq6adtae6*Q$7UNMxY;U-#JS>:zJ"w粋vsAYKM̦M`,OkCgkTzaˊ>@>ZUsV LjY]X\'NEM/zY 4?eAֻF6eJ~pyzjunW.?\޹U"{-ZsY;p{ W +{jbxfߍu~p~E/(i_8m_ufYK`& \d3FH j/I/8mOqڻ:>W@:?5;v-у0tzwu|Gf{6>q&+ɣ'AQۻO:~rg}ıۑR}S=nq c=wP!spI5p1|3|U7F^$/.;>s*ΐlc8yl!%,zz~5` Q|9W?ve08(͟1B-n0*$ZsU Zn8 wtuֵ8g7{tvm濧}W!y>ٟ; +MLT +(E=Pꨈ0JIȀ4 مE _fr/n6PX"zHa`A2*ʽ'M)0PEBNs/.i/,9Py ߦOg{3APyQe€8}v"N 6MB8dc),^@v$ECr ^ iҳ&zk |T\UP (IOl#Px0 fQ0~K-˛э/avt-K{@P4SAv$oc22LD!A5uܖhBnF*9}ث:H|YCXKF" y4u v@k²!֠;ALvO= =F P܂:A%وzMΡI(iE_[o]M +Nue2N +Z {/GN9 ̿Zׁd Y@O ˅ZЅC==yV4)9^oX:&}1owv zL i[S$3'7] Jv%H䭣w=c7;/$_مI\!D)ܔ(NRW2?n"?(}qBntx-_EfVT8r>"5jQCįғTg>Au6_,AH46͆J4Q$0("9TWxlT*$PYRU! T_DkW Zv(J h␿ +v/iF\85jP%ivFBPc(8]۵ '1( FM:j=\ScVʂScyɏ<5#(˃AaI>1^N VF h>IJ^X yR,_#UNBIK\>[hzslG NϜ[R8%6 ܨȺoUz\$A^,Ib^G:=Y1FE۩N/߉tRHx|x8nsό.1yK8I5Ps +[f.7Wd$H Ffz>agdf,JV@Rث8nIu' 4 d B뉹X RdْwLATCH]4?ɽ+%NQAK3WJ\)9zѳ X'OЅ&쮔bFfAf + +@(R<3+iw[yw;% oom;%|`ꆱKcI M)3ůp u;@J*R +Nkkl ׻-o#ʩ@bFk-5*IQFt5J>/ u,6@4  xmɄC=B" JTP#{D%JhEߓHk3J\+YuEܻVVDh !%TLc&F(D.Qf։4Hȳ@LNywFk%w@Z?alV)5Ix2V{<9 +Ÿ%" +zcΩF]!R#R탓: +U-mBYb0LQJ:}aD) Io +[γ;ny d+Fs\b "B@gʼkCPrON j!,VrR1r&/N |Ny5@MH' -cE^8IA- s S`B~ ţ:ƑȈg G3n- [;AJPzo A^We!d1j0}5%v3$sё)O74"sjEf c\؀,@]"A8Hf_T76SLj A5.*9Ƃ#4c&U@?@§욑YSB'0d3 ԪN)l7VKsC#T냘%i2ZKŅ sҮ;vиN5 ;h^ezýQus +KQ\.abiNH +rhL$|\4uqe^Fm`, +(LhQ]>wc)BHS30Ydj5L삃zc]ՕY̋Ќ)8K-BSuW"p]\(9 <cY +DRcZhc7I'ĘN|O**\\y,J)yX阮P[z +O'L޹sP(6ֹciBg{wOk\5324<sXW 575^oWXRo1 hyޖ8DS33 +"Yf;ozgW%@.o A7h1;b +^12 Y炑ރs=8Gznp7Bq#T%Fq7B#nD5.&l7Bq#T%Fq7B#n*G]{. q#Ը*7B#nNfFUq#ԸaqCq#T%FJčP"nDUj\čP*7B 꺹q#Ը*7BU"nD2.F$#nD2.F$T"n (ڙT"nD +^G܈q#JčHEXgaYRɘT"nDR10&h7鼔"q#JčH7"q#JčH*7(#nDRA6\!q#JčH*7"q#Jč!E V$p&F$T"nD2.FrčPEUq#Ը*7BU"nq#T%FJč~ʊoΪ&+;d5!U_ Aoe_$~~B77>g?lNmyoqhvd[o~$[X- xB͌-YBU~ ~*V? +O/Tb#jZDjo@֌+PPbȡOSXV5>d{;mH6VVGVVMY[@"+Uˋ!?X48P~:7fMhlWQVI-C3*~odcVwΘU~o ]oe?<oze;^lZX +tJ"eX7O(:42T c6\ac][ <9Z[8e"#Mri2$0e MnYg,k4ЖNA|!AS + rX.Ԩ4wWȒ v +s{@ Ae?儞 RƐCv:gߍw@O].6 ˉ0wTT>=1(+Z4iJkAkIPu[es ?5^뮑 (*@hk_Kz̥Pm.BIӢVƸO#l{݌ߐ ,R~8H ۔րNn< ;ıS i!M p)k46XZ]sX4T; 5di>MMS֮X}jKP:ȑ{biJK:ʢHtL,¨HeK/naFD+TE5)h`+eu).Zf9x n07.epӏ nV$':M*c3lŊ-͵8cMhAಸqM$qL A>z,,9 (y LsS8H`哗čkS @~&6s}Frɸf +KcLA%.%g1~- +#F /0#cFƆȱ?뢠XNBT& .ťTnFxDQAY?TnR溡;%hc?C[ȹVx 3};?YMb? FO ]JZmkdnׁw|g !G0 uhw_X;UJ( m鄝!ٻ0*2VL]T#IIro/*҂H5:r/*2֒6TcaRT, ecpRrR0fZȘ咓32D +@qz@AHڸXE\ZڸȈM^'Z>1=2kSsLk^R] _\ @ aT8ze).HpCTInſ i8Z 5sB]a+ o~B(iN=RI \8ֹ} ,'T :*rLk  +4 +5ͩ'р|5&Nrc~2(EV܃W$|I56Pakd.&#vہ|'y*ga ℒCgNT6T9WY{ ] +Bz3Nz,A{3 XvyqӒہ|7Z̕V;7wc }0a&X2K +QB:Uh]npLQKZtf΢[蠖Uq,:tgBwG"Duxv8W^qƠ)Cm4ώKUyFYXP}z]onq{1{ex?b7@ +#Y!2-?2U$T+" +wZR ;/S{ Dۛ߳*056͗hةlΒC5̂&<J4/0-vFƎ<$$ ? 㲽c +c9C6=Ŕ(7XcSΛL00;0X`V$w*KUGF\{ry∋3,i6TCJa޶溠vr + \ٽ 8(*DP҅Lَ\ɖ(2o{R8>B1WZk0-ާCLuެe_aAp@g4UBLDŢ^6@Jw4KO.=RV9!V.eESN_?P$?q&J +?5'U✒ -fXLPi5޸ ϶(vd,? [1=DwJ1rMZ +v"$@%Ju"Za|ς%!%AE:Zg2+J\'WDM>/CfoGʻo#0(YX,'L7<#m41Pb-۝E{K=@N#adQ4YDeUb,nʼW#X~^Kj?%Ubj73]4@6?œw(/V2, +ȟ@i|c3:fbQ1(p4Rʕ +[ѿl4-~3fߤPs!ē>S;8ó Đ}'82~J\燶`o#eQ!4*1X% n +׆AhHU!E@Dmb +W1QFKUj(1xQ+(X mCl'WKF'&% ƐvMtw=j4Xt$WSwԏlŘt8"4T1eOri)kQe"x@̝ cжTjUl 58/-M-T1dU< 4־䃰O Mz;|[s r9{w ks7zX7F~0n}v^Ya^c۾viv!Bj㈣C0p3ۍѠ- +6f{vz֭wțZ|;h㻽~6ϊ̙G|mZܜ",g@3wFeuzVgQmO??cIT{u`=}ZxX8JٱEEJ;8‘:(USz hlujw0?EUz;6y5ڭMq6Zd{qG}`Mp"ʞa6+~͋x/4(imc ]#LDR&˃TM'I8dw֧Qa`7kj3[:SHDmcH@Gb8~Ż8+&`/eC朑yv"6twj36I=DYsQas:s,:,,Sɘ9Kዉ_Qm$v_O +%Ǧp̓njxO;h߅ q`B#}6,hm^ (/pKx]@lM7 84-:[|v V뭆Uiw3$k˼W<hJU]%%fcђRtyT`a:0b¶=ZO-&t +^o 7ND@@XȹN1./BX^(ә@vO]. ?H:,r`Ž;LNno}.'dNnHeX{C7XLJs%u>7Ơ6W=}VF7sp$M3 |n 07ȒJGGH:gkUt As1MNb&hSJ3{ia3Mk2E +]D P J%WVc>+6ֻ&}d3;,!2I%fJa}-&~"bO@I~1#"qRD> ACJl3Mxϓtt(_# _3Up!i=a&s$k:>&J͎cqY0cef!>0JWڎTw!q/m_O9a_߁I *ds#zz)sY "ciÖlUI%`>#R_koQx# 4Tb5N¿Ц>̂JK4DP3vLy!R⭵aPp! +vBhW,Uv=j5dó:{bIwhecl %z"8`>riZ]{P6iW,Qhl.1F@.cjIΣ1sjTC| #YkjխC2kS]SL`^|0[UYr6)c}S_ ]s[4OI3 J3&!O1.RD"@*Kf +G@ +ȡ;/!B ^ZL?d*.xLA0&JBE"Σ +?Є +⤨k[sBu%/?Q.S@ +WV}Qt)&q wɘD_ >EFOAE$ȍپt*0 KSB! @ylpIg*dphJS1. Se''>QWAY=Kp%85,z3q1a8S$v.ùў)fƭS`2aFq(] @J^Rpt--Dǯ$g U-3R+1fJ4_qjQל-vk2 5*gF;2( 61981F+/Co"nUD!~XQmK%H'op ) q/PTF% 3eBĴ94 Bb@>N`u^LTǴ +Q!ጳm(LpM)$-8H +4oLXw Q@\ E4Ҍl 'PH>9dT0~q&:*$RIcs pBҩ2#` Ƒp^3!I@92N>rJW/8 P#i K3*g^(a91LeQ(F1 ~\Gz@/eNJO8} *r7`J2!0]!H 0"%:"vX 3H@]3L2XBe1#z3* XEaE#e֔  +5e'Z@ 1aC]8nLha={l0K<ІR93?P7t[gTQq9*L@&f XIʅ=I¼iJ?iQΰ9FVXyYi60+d$$DD'%D +WB!Ȼ@y}e|3i.josJ#]%tjF%$,&y3L!_2y`EiGb^7g@oB-0+%,@iQ\%ǬH)[ Ȕ +:_',7BLx#78+A&J&@e*T!E2Kh},ٽ].8fXS鶘,\Whe0sb(^DT4"<&g\H* #CXaՂuJsaHESvLOP2fl@V!9I <`0ƌNjOtT#Z pNH<,f*̰ Fdx#)!%ᡕwAEʅPg #`15LP࿩JPV7\P(jX JSiWPpc%cy(3h.,&sLE3Z#+ \,Z +CGHbH|X:)O@KIY'ɝq'gUnQ`f!b,Bcu$bWE 2$'OR[HP-"HƊK],|Vvb*ZI9b*+Pnqw4*hB/f|mxɠRlthÄstȭn #ʷ1͓0A^ qd!HN7 Zskl +$QD Z aȂK8`'V(œa1\oWNV[\FȊ2nDL*N@bb9 JDG +g¥ z0#(yP%&GeɲkZb`Pb:-aB -ִsVIrpLERf(XG+teihKv{iʜJb_)}Z.ˋfg(F#S{ |ysx]V';R94` {Ņx̩ iWBENA jaɺXp` ̌d-t,%dXu@BDHRdrM9 rd:P[چS6tƜVet1X]ͅߨ-ӃdfbS.uE](wQaCzIh3u0Y8p|Xp17PQJ.ׄ+:3jEPb8/<<9V}("8A?xJj".A=b|Vmt[kD = Ɣ\rېfJӵs|3)+L$oOJB'Lڼu *<_Bl}XȂS\# 2$̈́L~?gqÎ|ǒ-֐G0g @ \m1 +vYߜ'4}k +ȝ)IQ5KcDˁS1{`u]A'2'BZ1Y"̖Tu]" **۠Τ>Dt"X|jfM%xhI)?U쬘M}G{TsX/}~s:EĞ8fxAERKNy%ꡠTgdIRP\i(Qg,G=\dBĻH)}}G$h)Kk(Xj>6‹uZ$gY7h 3x2.|5PʘBQZ 662~G9txd^#B1(! +4/@ᅠ" xPEa@ONHAGGusT Gi t\^d7 +3\'%iN\F{<2J12BSoa%q;EEQ j51&( ]a4acJecY3CHGbM*wgN19kTIE3J\,)LI S %+KL[ +{Ki' (LHf'U$EPf* +|-E3{JՅ$^:^' 2dQ~@V4IqXA.tĐI9~$^f I*fkQ /^o J*W3fkD8:gf#G}|M9Y)0zb2tPEڬjOWX*<9ZrAhG2&@%ISBI/( W3W+G"@N8 q^|c +@ 2A`=)D*ftCXE `{)O0=G:w9lt(#nbzr f' $^@™%č"x R&D̉.3 D kGW0=~x{?.N"fGB@B{ N'JIvrL+U,%:$}R$|ESɤxO$^(>Fb ީ UOȆC"K|y9ޫsTړ.XN.h28Z.<޶W,}1z!v!tPEKł mRn,9QD>B*!cN䲈}-$9% ߰ +.Ӓȋf,rXLhGbDg-) x*&!up㞓٧G*F#T +^*g *Q,%||1ih ඣs,arE)&SN!pϑp:b{^:F!r +]ĚF +42d1$|, P3a?9ԗ,V!07ǑdM$5.IxHU#a(Z&HD$#'`]UJ/Yo[LAb/YUHY=D#%_XDO#V,1!"Q\0Fwq*/k~\Hx6 fA7M U`qȂTYOD*\AtUvX=A\H}0C,9\2J, T3ECcKȳŰclHh?s FiC2lYH˱.i};T +2U#ǐRex){N>F0쬆SDg?OzKg?Yh۵Evmjw̤kR/:MtV;Wn{~MGr35a?*5>jw4 HNmG>&|m[4_||}зKvtlm=|赛W˝7GgطM[o:h6wuI!N|gj =EI4pckqDmkm[KRm&nm6z?\QPÀQe4/(8rÃ/bA׻d|`}|a~C£SQ(W?oCnaGo۹op>Mjer:W39W k+t%чM-2nrP4lR1( !fV.SowޣPәP5[MM>NT dEӫq98 / )siAb +CN0zDo9X⠈cqp,>8]v"Cvq?0oo>j1sqXLBczC14zCL{'@.2Dp1̄ta̖F}}kA%Ӡ?j[A[絰gk7{7[RsCE{>fC9`[wzѽ!^~uktA¬n7S (2cT6=pY%>o'3X̕D,|u,9GYa~CzpE XS^ƇJcKb^&0.@*Kc10ʓy:fKu:#hL\\3cߨ4 ) 4$ I Ibb +`5>Ԉ}$;v6$nig,GRDzM8+:X) ]*^G[Ka%o%eOTqhQ $0#I}<8斓:F08旟* w陮Eرl׳(O_<} +l?y!c4ODr2X4-#"%ʖ::?츏/77cIJB^%Ǟ|{=ƞk7{ۃFm16y1yǝmws4i*d%ME\NSaoil +eyRa!e}A?Fgo( rFG//~75uj˼kyU'w^ #/d}mf>>->_9g?[o!F7$$YV;zLj] n8v҄Ic[2}BN֦Mv$J lO"谢pL#S:Vط^Xn_F"݂ yAksF)rMu>[JR\ u6\Q mX4a%Gu *HDKAw^943ʲ +(h@YG5)n7\}]*"Xd4(5XCݙ^aʺ*ņeG= $Uq|N2# +,s "s 7=KAj+A˗*u S%)ŵMI, Gw* +4"6 L V'Cqn*e +Q(⫩)()Eet%$W)2D%P ሸh&:*,D1($BLwLe6/'J@ %)CO)sC.d(D&eiQd,na{yT im3##oAt,EFEZ34Z|rbuT +BD +ڙLII=(#6Qxk7$+-yBjۨ䎁LLᖀ5K!yi>@qZp_O0CReĻŐԚLh>ެ35sOy?KAig]t+9blUG&)rgث >Ncl50Ewo.:m0'^kv1j~)zXd ίK4,Qā;2(|;oonknΙkΰMQd6n$੧$4!&m.͛`T@I.L)%YFbmQFE-mde;t{R!c-TŬ(͈)Qc +6u/Ɋ}=Q >,ؔeiV>ԓj IY +zkMH(9N>;Tо +7 rt6SĤ: >Af$DTH6Am͵8'Kж +8BfFgKn'<Ջy((|.9B  9ܨ'"@Nځ1 qZ8=#Ed'wpU 亷hHV~25HMgXr@0gA7|4f4ؘEhnP$K@ljqD 4͑jG^#S`;jtˆx&.Һ#]~;IWZg8[ʣT#Z> ~i#ˑU,wwvnoŮqo9_vH8hvڭF MWNu{-jz1h@z3jמ4a{ ѿڃq \7ڽrc8rrkÎz"@߅Ej{V>Nj:0f{hk] uXI{TC>݄0o݁bm۽nBH@8ݼQvnkV桢kݾ٬S֛`xѫ}=wz6ϟV47_[Smi>`4Rdb~Got[ilwSQ4'{Gg +LǁpE wd:S }lHy|4?6>ǒ'&?=>r⺾j]}$JҸy)RXnQ,/)&ĝ|j/ڝSX J?Hk7Z[VGYݎ!lߩq*si˵FMc_-4Azm4/ ~:N\nx7 veWx}~yo ;ǐiQ;+ 236zL(5sYrgm|wۼK9w7dwvp0΋,P ʜBDfݴVJCלΤD"Ûڶ;myo9MnqPn3귡6]^U|?>Q2;_T$_Ld(>:-_˔@+vm۝ngd$vVo݃n߷c_~^-*d~Ye#`&fr ?Vav V׻^gFl` Hr)>[ )H LϞeb)fUؕLި1Vr+=>~W( z'O|ަe! ="im?LCe>C}hӏeNx :gR>|ځd</ 6z,CNmg}lL*2h\LUUBXyEW+q:NLV5sӁd oL~`fSnk;n ,Ճa0.}i@1vp[)>Q|XI'60DĻ3nkh=쫶4h֒oڃAim7zN4qe\# EbضNvv؆wAqD#2۵QN"˝krL'Fɨa=f݇FkYvԞ1$h0if#OXZz38 0O{ @vw ߈wG"wtSxgEKzKit:PH2$S0fgA/i`WS2ցvĺx*rpVۍvkGwN7P,w8QؾbԯPY&(>8[w.'ӱO䭝wTFד|^Ҁ@Nڇ Gh"w9JQ%,507B,v\ltW󧍀?E5 8uPRZY;K)6i ̹z_r+5r JCnQn7|$z5`ƅ )eğE{Inov5j6zQ7Woj @k՞,9zB>%STM*)46PlWFFd5 {Ú_7[w>Oz l:32#$47x9͍1d9]bGHrj|=|W8 +~JsdG#6۝^(^mѠ&=cvya3Pc)PR&O 8S#vc0<Xhl2Z;1EA,Ojp{aiŞh|,`^7)(frӯFUԹRKZ .. +"[u\ݩjmFUg|ptx/٨Z!N#/j?N^r63\z zbmbZ0_N&?8 +؋wmwTLo:0ԫUDdE k>'zb}yu#gXݎcp7_ {@?qj84=*t0?x,6h|FiKA~CwV|ȇSLc&R+n:;G^j(6T|<3;Ga!G!&[O86Q߱:T9zޗ:0lїcT>Iۣ1t>~+;M~HaGQ_c$NEzPUZ>BRȏqo~bf?,$vc=(G}</~O'D vk <)OE>?'(xaDŽ {.2bʑa3ǯ//j _5.}/?_goo쯂>O~C_?_?0ۿn)P_ͿͿϠտW_ww/ßBAÓEYOa`AgFl ƣ6ƊM~{lg1hFb閚n#]S­6桳tJ+$mޅ4ϓ^Mmp@:Ho4NMfcPMq^ؔrR)c~./M.c.)I7k%ƼYq&t+o6[ӑGq7_m`)>Xp/2 g5hD=(!CL{7M>ї(”'sM(K%ktVƛP +!y;v`5b@y}Cf%6Fs6K7㭶Cnkw byacƍ\-SO]zt7婻k{/.>KF}eJzkWn'W/=;}{~pVWd$'hry|ůg/o9fhqKI{csJs^?[k̖WO^Ⱦ6Z~|1j^m'5zqJz`u9G0Nts{lo_fNg K귻|ҫsO\k0_!,<-v经/,-Ⱦr3^{=GLz}ש7Z7>__~1{Ǔxh0˙s͕7"ٺxi8{/.6WιlEN~~_S/箬^h_: &sWWw/]ttvEeV7)3cvB0m70IUܭ+/.]_޺9ZXy{aSHDQ뫕\=`ׯ\oy>nIygcE[ +6Μr#>%Yي=\L\ ^|ޭ_/^]ڹGRk q1pm^~:OGkZyri0 ̣}wګm%d62ڹ_o]u~tm8w1Sړ7ΰ}.Μqݭb©=gn|fg$zrVkoa㛛s3Օcҹhݑ;bTz1A|`6}5O/k\Vx:8[_dsx4ؚN]Z{"坅_"֙_B@ZjAl*&˷n]]Яݳ=ny{bfTz5NMneogz)o`a% +ka](6zr޾pE~ypԥmuÄӺO +bW 'p5zyy/W¥k47"6Yon$PPovC{aKM7J;Qm u h/WqWf\5gnq/[?;o80֊MpӠ |X6x ,94ivI`7!D2gaБnâqiG.cy l eI0ݒ,Ɏ[#_UifFy +B̼읃Y sCC\g솶_yk /iCtE|ӾX;hn>dRKbpghKBda-qk[j&Ԗ{'/n6_??u#f O](Rؔl@4,bz3O_.W_$S!\9͈3Vf$˷Na {6F7Vέ̈́vW狓h4QnU`oVE-\d/dn_98͸7p[}kûV E־m_j\ yeo-nu֟e^b\/m2X M&8/]]~hk2wr߳1l˕o~uVs7$d}jl}0d#=kWwg\+߀wҋsO:W._nU`쯯 Ta:*Oap7 SW- B_>t6Bh xS-^o-ZVٺR,_{""q-]wg9CQ2`7w vuYi0)MB`&SlgO'ܠ_=ͳ{'{w7Ʌ{w6.iOE٫h3K +\Չ>pʵ-_p[n}t|J\`х^7BIr7+r?m= Ä"ޯ;waa3x`g<ƵK81FCvN,}lWN=ϚP/.\|x#\F%L՞CJ]7uX2{Q(T~ +ij|{*.u._X=H-Yzxժ7٥NUN0ܼV\: +>:ۭ/vwO{ B?[쾺q̓O|M"`>|U>.wVFߚM^l-Sű) gy߻]=޻\NvrFcJuoW]+Kl]C}Ad|shmxP4_XkU`UOT1<'WQK~tuvkQoӘ|'.G.wɼm{UL$3#͹_ؔ\̈́憬gZG-ꅇ͋F2|3<ϒ@Mο.|{f75z>06,l` wZ;6Clm3+G9G7fV[y6z]^<Hfݸ$}g5X^>f/j'rUKi={˴\O~NkCnita߿Gz1ΨIciQOf?B +.%frj_zשf^>&y#p87,lFK[.\|fNr +5v=m3u%?ڊpoKKX!F;#]'M5qTSJKzϧz;:Ku3-Mw5_ף'IU^EXj{?Ϝ~d&;zz{d5v=7w0u4{5ksD\Ư\2Bf.vF̙}4519Ow.FS׳fsCljfFUS=f5jzkF_;:eҟS纖t3OS+Z9}?2c-Mhns*Gm*f7iVYfmOm?reQd,i'>?%DZ^zU3ZZ5ڿv.L["7Ӌ_~I[Lp~_lß>:mFA55}9Z:Wu_Ag|jk(ս89v܆fMy6t6ssPx韛z~}FԌGnrr`x|g%_d:2~փm#-}]?|EL?~lnWgT%r1ɑϩSgz՞9zJ*<529r==𴰥OE'6&c٭icJFlRg3s/Żlg:vtu:t<>:옍t]=OzJh]f3}1[;~]Zm`( _t}띇SfłΏ@3$ƂOK}]"Y,4XNP(Ա 폏ұyߕѩPh4_#>9ia0j_+ڿzk_C mwݱ|#hoB9+3W_r?hѾ_?J~uT&%2r 툞a>]eTDtI}VŦ_ Wx@db"EVz#Jr/_IMl}Lks-^MF6oCPOcChd~4`(}{v7|oWҡJ2Kz{}E;sU}~>q5>zT˟ɥhwg >oeƦ.]SON6fg}Yh~5qc= մgGSFLJ[9])dxs+\reDv!~վR<ֻiq rvsm{pXē:|ItMFS˃P{>ol>yDf~Ƕv]zA~zښheg}c3n{\zO%]+ow/w9s:mn:Wun;oi[ۜY|`}s= =ssZGԦF>j5b~jߎ^; kwle&Y) +u2kj^NvFeSGJ߱sS)>?u91 Ywyh O52:^[Z^?xfit͵3Cmn{g=ھz=U|Sg7v:{i{~qvg3ǗRj]uuwzmǿ^i۱ٓ WV7q>9vxs%5v..z7ϏAr{;;Ͻn]zu!s1ثڍ塎pτ^w{v=;i]{L5oeWu+{~XtUߍ㣉T^W#/]ZwYj/H]-}{ˬݫF +.dypR3<}&v̽u{_Oj@xVȝkYKv+ֶzu^gLDq-zj\- iW#ޯ߇WIwOnN=_qW9mWz{_3z+/ϧ#3}WO + -Ժ2~ g %G/>8j{59Ū'3oL_-N:c[tlq7rln ?&c3UmҬY-N\6j~bߚck=FNA:ޒ6YڷiUU Ͻ _:ض#ϽjYK{dMvsֽ:{lZ_Ҳ׫^UCur;Nw{WIА:6gòSZۉnaG`ϘǶj)}o;Tz֑tb簣UvՅkCזt)n1~z\Z:=~s+z +VF G[ ^oչg +]Fy9x= +P. +䊠3f+Pkv#Y+,Y^pN?;Pҝ+>׹&Bofah-;״齏J +HNp<4_nHlx"t#uI+q$Yv0#\ٙ"96k^P_Ӭ[MNo~8c95l\G@wg/Gws3-(R#^wZ1MEmFYy=2}jwhJ{%|xtݵK#?x_^jH)@{ЮtDbqZ^>w㊌E)ATppTXt 67ο95v$Ζw $n>iv^S}\whQ'0HdV;>0\?g6Z ې=͎/KzY3{HSۑbM3U]BN wu˒ p%U Z=i`Aޗ_u_7B+-9@P` y j*d+'hoO)iRAY[j~SȺ3߫ϒUHY-cjA M nҪ}T6˜p9}fsCFVg ݶkPV +Bsk3àͪ #U?_Aa-xū5uW9SYOnvnoty.n\[^k9ܧg +n(?iZoZjofɫBtS[)n5JnʱʣJ6:S7 ~c~T=wy^2gto'Tn;_*lnKj0tfBm9u@񠫶 +qr]سGG=WN6Ɔ#`[1M xW똍@=~Ou/_wnq4gxZ>j?+)T1-VipF ({:7hXbyEۭF9ƱfMm/ܬi n%8m`C߫q&^G1Sx>ɳq$Po>.ٛOHZZ+klcFwȵε2/r{RJwZIӷ@p68!*uQD}ƼK{jOBŻ2vs^Qbț㊞wa‹2ռWZy?6XZ`{qwq:@w[; +q[[ppg0)zWyy<{w }v3^};;d9Z>GVr>|dq5=-_}bir>|MK\翖OΪ,_Tt|k%T-cB|=+_ y55RslMׁ9Ѭ=1/ij߫sqզ}l΢aWK]K[)VxV- t@W 8&+ @uS=ڵګm|Jq“YGuTRn5t/7`5S7[L {eewF ewlwl/ŵB ՕMnmyX=P8zn):1]j^^/~S6KʡϝAq||N=g%syZ>YzՖw5DJS+D%7MXWиWg++`2goAO/gk% +]d TzTYw_ZvJyZIBk1YTJ*-{yH*m&wLbJ9Oxu7֡}fћ܇j=ktq(c<$rX :(Yިp#.+gɱHVtF_(hq T6}%R7xD@A^p.n+rNDZZBr);z5/KY^W@c2`E^nTV'>~K +nuO9.+yn*@ XߡJg Xx|eBv3o 2Vie9\WyeԴrV Uwe^E7_͡}6TyzW9B*])oeםU^a/z`+/4/4Sie[Kg֩VU|g(4X I2s VTr[o_^- +> ׿Q +8!XUu~Q`bRx=j?_%KK";'Rws+)}7պwn.9UWe^fgۖQmq156TʺLfMPɡo%Mؚf hw|ޱZi\$nr|"٣,M4ȗdήeSdͽA;M~dϛO!vHvZdwHv*dw>) ~tm¥$僮Պm-]gyfZ25麵j-3:+\9~yZ? ŭzR'šY~ߖg2.3ѡ)mw[f'ެׯmTosrx}hs#=;m "ɛul<z-;[ޜMϽ'O/zd_\6i٫c]u>B:ס>kb}Ͻjﵩ9[FWuݼoEܔ\6>!l +r-sUgaPu-sN]7YWpw% \6pY}n Y>ys z׎ֳ ,啋-s[b}Ӫ [mU_TD V ΡqTua_J 6=Y\>M5s WhEŒ +}^V}n +-F#P\綪HWaaϊj.s[fVia_ӭ>On/h߳…}~U\v[b gˡwn&/>B9ݍ6*!xu.-r?47()~^)Gѧ-cF)نk=px6Fc|(zڏ)Um]wXŲ"ǔ 6arQ`c.؇ˤv 6lVRuׇ9 +-Hsp<5kKyUTx_僐+->/G3\r0Q#׽J]㑚 יϭ-yq\ʛ5}]cؾ r,[򼹱ԌZXƊ-i:?ptu`-ZqvKc5oҶV[j4ȓ3մchΌ = 7]Xfl1hpogaCU͏7ԶpKӯ ^6kcf/MjOzT黄"QӶh?$ 6X82h]w]v=7o &:j[*q -#5V'_[EQz,UC- +y)ֿ x={_S>ɹ +/TsNK{wn>h'*)+[ԔXs܃M~v}ϛ7|Gј[վzcn_n +tJ>Z+;:{WۊWwt*yԳpTP}]iS'[v`:}+3ǡ;|F}Tfm8,:}+87ez\.Ph|{^h{jgsG+i!Uv7Usݨ~sݭsVoۢ[Kǣu{7Zf|{ݭV>UUW[lݺF{`ЇaĄzN_U[$[ul^˻~gaR`P-1 u^mWk:åӾxl~lƞG/jRKGCa "?Mhݸukwxfmn=FNu.׹}@sI`k9yȩB]Ȯ?:f +\+yKw#y?~8=t6^9ٹ2s{}UI7ny&z\k/r/kq'\opsҷ:>"nY)(؜7}V''Fsjy d>:Gd>g)#j!sA z?8'YXnvvp*X'$ms*>k%?&Z lȺDE>_ ҧ" ֖z, +P#"'AW`27jlm%ZDZRަݪThמb6cl;sXk\7e/I ,$1zD~yKK.wIbnE#n/oIbjMKGlUђĠEj4e/I ']ڒD,{ +Iy8+ +=:*tce?Ua+ -_Ba>}JVh V\uɫ)V?img>AFSO*>ժ\5>CH9t<ڡ`JY<^a/O; TCLa9VD6 ʪi[+}a)c<~>q3l9OAU၇edO;,#(eԴrx8*+#聇i쁇xl\>qZr|ڡwY+xj3M4Q<,9/.xڡs?Ќ?LAT假^uxڡkVK-Zo.|ڡc7?.n<ފ4kx3\fio<,C};l*|an[7X*gx/87m$ouQf7%Xl@r[0mBg`sTV +o~'9;~bXrz|x?j{ u 3Prxs%20<{l/vg♡xx>>_>/\Wޣ͑t|U|6x,w'.Gt/~?hUxooz:ާޟ>?[^FS˃Rӛt[r |qֲs5˴'{Otm6o-^D2kܢDm7G=ɨx=Xʆp wCC#=êYs+/D?[ exfk7ky^{{ܽ׶vnEb=:boG#g-l޸ZKe8VA0h:b~;VP.=1{y:-ħߧvw {åDwLMP"Lx~a!=v{v*BXv˖&v^M}f wj~Kg*l2hLO=~3ڊj\}]DMkP吸8i;zD_xIZUdxXQW.gԆ敷q 5m?lާ_!?+xg`<6=y29iHr;&coҾx7FGǷ{L _v!y2Oa2wFRgz]Jv~^g$cQh$ &ӗ}WIIv_%o6 LMDӧZF"{$:nGtտ ٝyn.,l74.Ckjrzi!i\*\?҃ɵυ^cI'{>rg~>^*[h)lg͗S=*^#/F7̽=rdWN7mٷ鳕TK|22?qt7rũegC̵z|svxk:3N v1¬Z5޽l{ʍy׼֞z-/Ͼq)z}۩֘No# -Rx;WQ9ּMms'Q559+U.@%1gm'T^j9JNlOqQ %uF<7گՒU =?G4ΰ5g7/h܂+m2LBmú ֻfoQ}&qSV_٫USZ.o8韩aG(a/5>mz_Ź79javDZtB }?lWER{3H>jdRml9!?]~nrسC9{MMf!O +a,mFM3<-a"n^ӝKB?6v nA/ͺ/n^h*d}a&ՠ|ͱd0ţl\T{E DYo:ͻ21G iM:fohP%Gqf|X#ak+ڷ Pn,e&^}k%2c]ف?2Na?FN̽ mHZ+ګwmkh3[y10ԛ|~[}{kWlj!~zμ]_o]͙߱ocp@.&Ĝޮa+t|yo|97Zڦ1՜f(<ޭ7r9o es3WZ{R֟]Z1<m7әS3ju4vXRǶdy'e^ ;dh ̧>`(mj}.NޯF2C-k񹇝ЅuÌD~O`)W/NsaL_8}ofVAüٯF?V5#6SVK3X[/\γi}ahQ\\ٯ .}~msik3wӛkDȦ]F+R|^-S t&wݜ'l6#όgL zbbAܺm}ꃑG[TG 3==FmY&919Rrf0%;3u~\__}ks7n6?[fԼV"_ǟ'fL?Ie+V5՗3XQt7z6~qٷȶkMT^c#ns?e *aɳI>HY}2˾38ݘ-b{awlS흫\wռq"U{+7gQQ {D뙳td3]4Ǿp\tpmZEf:6D@pswvwuG ]Ȑd˄><_[^ n\/̏>.k|s:bYn!mь_ydEi;Yѻz5վxC1s55 fk8eGr5;"ÎF^S;tKPxs cDWc.f,a2QKu^݈kL.R?4f9jfpZMqZwMۙꦙԟIo-Kw뭍ze,Xڒf3b_澘cOz=;A)شl`;jƷOf}h-֝96>mۘo7ߵ`Twㆅ?I5Ry52,vn7_UiKg߸9_i|X2?s7}~NupgUfiCU["[ +9spu-gr8N#rf!X A;h_:|H Z8F z!ùeNͩhys +Sk,FOh>|X7b>,\Ptݐ-gdd8S#hi]ݦ7jmϡZqޚo#>iQ[ξQ-I#*iO״돒QP5m\I 6pnlqFn-MKMz_zdެ_h3z9}F+OzUFޜ׈bFl ZZ46B;{.7 Fqׯ +AZ#t-CGѳ.]:t.ϐ˖f۷-o;[ oom߾~ؾ~b;fG~Cw1Tu,î^5~}Yui>=~A=Ώ[:筏GP~_S}';0MAg>ԄH}Bۘ6z>3uu7O'tsnc#Bcby-8>:1gk/rÖ[ _,˹~r{TC/6N}ܧ;?U>Hͫ}B._'OneQuKB_fah +_ΌGt{?͍Y&t'3jvL{';myvWp׿c"1I;qGB#2=Z_nʭ2I?և@G859:;oQc}Z`Y3wmLva1"_5̩qfTn>eÜaNˤ0甚Qu!8}j?n~yJ^kL6?{`H7OpWxzjfincuO;M}.?߶?,~j>O|~~~P/mfv総Az=w. +Wg?M7==EK"  ZӋ3[!U}VoT{wWw"{qUFӯT?7M~l{S}>E֟DF{?ć~_jP4Op`(M~w0&zj[K%C!Sh<>4~'P[0{+ܛw);m{ZV˳7x{ѮKzx8WkeKEӾZH'O=Z̺߱?חoWWaGO7ڞ]P//۟;ظ~Ў<۵ӕ=%:+dJm\?p֛~ w5[UO<,$~Fڍ/hhhhh<|NS<3ՕкMz*s8P,=~uW,}?wsӿ4:65ZEO"'ZL Cj{AH?Rm؀oEMN hFoӯ_# v&]fHwt@u@VY#>M_O @5I~.3KIF@&"]M$=BJ3*Pt_Nh(]ȐwtB&'=( vIWP)"AA$IHk1o%ActO2N~"ZRҽ +tWIw# @ ]t_JZ'?!}?tq;@I_R _Ht| h49>ݤ9H$Wҹ @t@]Nc +hz"9a u@:iPjt +>H*@Zҙ)$ L:!PߤcdHt0N?4o"xhLұ _K:ःt ৐v2"Py%J:R%M:|ҹ$Щ?)$IGD@:y'@Fp'G:["$Itt%ȓ dҁtVe?t>?t&U J~"C:8 TtLAS?> +SH}%+@ IXF&ג K: ktD:4thҙ B:ҡHt F:=$I`:&>stream +:;:#jtjG:r + ty% O:#:&IcPǤC80t t#@ݓb1hұ@t B:NAHs)4𭤓/h(A[I'_h:μIvo"v@D:$tL:|-l tZ480S-hpa IZ#=WγG_B:A:Tt?t2 +~PMҹ,Qs+q?@H'VI~Ϊ'!U%@:Kt>?t P)| +~4F"t@(" (V2|Hp `n~4_h OMAO.Z"l%}bH<I7t'閡qHɚ#}B Hqn' + 4;H:&}Mxn"ji4P/VI'}D!P +Is@nIt-.6 +t .+INH7_Nt5F PvH+J&]e5A9CDHW"$VP>6|%ꓮSR-IiK _K~tn#IUq.H} OmqAte|-vUhPP#*t#r4"_Wာk H7,g}$ݪH:Tt{~.<P)hҩ"JW "!zIgFH6ҍt~Jp'%n+"4\H7AIM'ҩFY(t0I7ΡtkP&4 +@1L +~:v"hҍ@)[*N!UO$F:G:Ttn?t2 +~P}KH'Y#H{"g@㓎_H:'tL:|-l tr 4,s.hLH]ЀC;μHu#y@J:"tC:NAHs)4p C: F H'bP9$\ t$@}¤1c!@tFJ:~ȓ^Io @]B:/#jt^G:r t- P[3'1H'hP76@͑NnHlZ$@}5J:M: jtu@:T.L jt]ҙ:8 PӤ5iAI'kPӤ4@vIGhZ'@풎u@:e%t5J:< jtlY" P779ҁnH'nPs3@=HGez"@mD:w"t5D:$ jtH? +x P38HgpP+1@]N&Hc$@MJ:yґ^Iq O:+<IGb:&00 PǤS9&t*¤0@}@t oHM:I1I't F:=H`' s:!}tN2/@#@thi B:ҡAHu @:4H^!wC:&wtfM:4th(|+ P;VAHw}#.@HG\F# H:o"ntD:4 thLY|X И<ұ1Igyc-@ÒNIZ% K:/'ht_K:42\thdҹ|-( =B!I{C,@HW'W?t_B:I| +SH}P}ґ৐#+"@IUD:*?t$S~I:8 Tt@q@ +IP':)%@HRK:JIQM:HQM:HQN:IGPЩP'!;`N dҁyҹ!F:jF:=HL8Igt $p''@qґ~E##Pt$tt@Pҙ#8IE@:yI`(t" (t: GRH@N-L8E%tt!Ut¤/A|9$[7'SuK5WSH@I_UO$CJ~:>P>IsLB"}#cH_7 %@6Iw#| tWJI*sI}U#ݽ#]Tt'?te%9/$@t Kj&ҝ4 J H?hk4& A㐮dHEk11=* @tuL'/AjtG! + HwSP7*Z$SA}jtNi]4 IZP& wA-t5GJ'=HcP+k"$ݕAMto :&ݡ0 +Ii Ih=Ȑwt+!ݿwqtJh4ҽ|yuUy';]$NL*CY[谛~˩vaw.VæY\&_f_fvՇMQm{ +Aj 6X7@l&`ǩ]0JSajvbc~;T2&v}]Uh+jW"vInEWTnW8vUjw#ƨ(j#֭[`vCb}j_&j7$֧`vIbjYIUw +=NvUbMjMݖX]|Xvab .L`%;+XEB]X[`u~_vsb 5]`j'~GUĴu]vXoݢ^X-u](j֭vFv"~QKj F](vBڍj}ƫݨv`.U;ZKjU{Uڽj}vU^sվvڡjv PZPo;ƨݮv`cnW;Q{aj 0 ֎Slkg}6R펵ԾvYjm Vf o5]vڷ`nZ;E j7}֎P&lekG}6E#ԾvZ~0fݷ_; jW%WlڕkվvZro/ݺY{ jeVlkiվvZZo,P{-w`wݽS +;^˩]Mjׯ%T&}Kv lԾOljOݪv [*o&nU-7`]–J aˣjQNTP-ڷUlIԾԮbKmv[!@2}]ȶ7څl۫}jɶwڝl{}jɶwڵl}*]˶ڷl}̶ l}l[}l[}l}l}m}m}m}-m;}-m;}Emۨ}Emۨ}]m{}]m{}]m{}um}um}ڍm}ڍm}ڍm}ڥmK}sڥmK}sڽm}gڽm}gm}[m}[m}[m+}Om+}On˩}Cn˩}Cn˩}Cnk}7nk}75n }+5n }+Mn}Mn}Mn}enK}enK}}w`}ڕڗ`]*}ڕڗ`{j}ڭ`۫]쪩}Ů`۫]쪩}AnWG jw:j_u%QUP,ڗ`ynx[ 4vW` ծzI jWݤeXNP,mow}V·j_`Um`i.|Xf;}uYηj_]%Wmڗ`ծ}X~f}]_Yj_WWm`G]6E +#.E)jWƫ}Evoվ;H +j_Nv`/'Rn`g7Rk .qj SB8}!v]pcԾ;Q.1j_Ev/!Unڗ`]7@Ksnعj7]UhK.}vڥpԾx;]^8^+վr;]^8^+v-/%ncԾfp vA\ vA\ vA\ q}j_-&jw}]ס`vM\ڗ +5qj_*nkU:0vS\ 9j5}vY\ jվBW/`}qu ծ}yXve\EJjƕԾ6vk\IkJjƕԾ6vq\`B/ }UX]8_ԮsԾ$I8GKԮsԾ$U9`j7iPDԾC9Pb>{D+SGNԾ[*YԾ [*YԾ QM1jP0F6j_F](5Jv(1q4JF(G`4J(M`q4JF(G`4q4JF(G`4J(M`q4JF(G`4q4J(M`4J(G`4q4JF(G`4J(M`q4JF(G`4J(G`4q4J(M`q4JF(G`q4JF(G`q4JF(G`q4JF(G`q4J(M`q4J(G`4J(G`q4J(G`4J(G`q4J(G`q4J(G`4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q4J(G`q(J:몓%q4J(G`q4J(G`q(J~lT(14J(G`qRFI`(G`q4JٕFTXX'5JK`qvQ*;ІI`(G`jJ%uRQ4JFT^'5JB`hJ%ۤ:Q,kJ%:Q,1q6Q*Ki7I`)FT,V'JeF 4vT*@:TlwF mJ%6UM/SGNԾO9PbV/ }aXIָn}yv_\ i:ԾTLcԾf;]^Kj_<v#/!NT n`6E +j7U,mo7}MힷվˠvjjvrjvojvWfj.j7m jTl}kg}vU^DJjw&֧عj!6]]n3U?o%πeWK5m\~ 3`Z{$/ nQ^^K)4O56j_`ZG~Oլ'j_ `Yk-ȧka&Ȁ][Sll0d(&Z6s%VOVK5?nsX0[-j_'`KZs-NFlIVj[͊6/q6/VNڗ :֗`skUB"m6&X!fl:O- Ҧl$d6`\#me lqվ@EF06^+i0eI&Ȁ[aSCX?fk6~zϲ$[cվnN^ ҫ$Կ6e(d2`:VX/+Z/&Q6/d*2MG W/~n_ IuYEܑlfY"l& ~~LYe+$ vr +nd +ʯLmf([{1)VG0zV Qv DY2-HR[Ja9V RBDt$+rn1QV"l6UK +otV,gY?ʦldR[0Xr|ײ_Q^H&$Rld [a c2͉v$X;U« nji%0D$fl~c;1֘a #,nXί^%]}rWJui,ee`vIFA6 c\Vɰ6a?#Ȝ`]jDWDÝJ/,Yɲ4M%Y7Y cg1ln,X&+2΍.^*, &IMs-vUrj K*D0Wʮ&#}bVNg)nI$Y[vA,U2uaVl`]|=qpҋ/Dk,gTuI ,5e` v KVzd& XWWRv5!u}S~oDKqiVde&K#Yd٤Xc^k] ǰaME &`]|ʩu7H/4S-YJ&&Qv~Mي lSfXW%ưIl#,aM ֌`+ɩ6='ZNgffMQe9ɢ\nk9% aed$q70%~52-,Ҭ &˚DY/bOv8h@ts1f֞a?˰Pa$ "]5 ȯ_^\MT=O|ғ)͋ͯLh<دwygf9rTAAwdi KT,zL *Yư$6`"7~=Y3~ԼBʵfm5%2I6d,Yα +w [5J?*Ya+GX`m*_dW>A3͋ͯDE5qքY3`%dO;׺306:)&۰66``{GE~E|:蠃>Cm9~~MLY*yAr%y8scb v]Ȱ_ΰJW%\EÞg%~ּBZhM5Yfg(Ivb$Y.,d99,lDL ^qNSk9:60ǒ֫i֌a$:\$s!l`)bj++.Ѹ"?o^첈&Ϛ40YEY$Yc_W ;h@IOYαv9[džr v]ɰ_ͰXh2,UPr}c kd8~ԼBZYYi.Q,eJŎe,@vЁM|f!+9cj8GZaNaъ4VyV䳟a15M| š!i)XʯfJ[Ї?4>Z\{m_}(eZgM5a,EYIHٱ}ͫ^#ӆcLry~j`mͲ+.dX|ݼмR-,Ҭ ee%b& 7,cQr,cVآV`9V2٘ $XS\%_tԋc {1OzS<'4 ,,ƯfJOoLNwBr +ȳem$vٌd]SN<ȦsEc{5mcO$Vrmvגaa{ KÚ*yDS%61썧vH^zd3`MWW_])n馛K>_ϛSE5iքYʲ6ʚ$K3YJ{Yg"^/&KͱB?˰| MdTx(Yưhg}n.aW]`%J_?WSE0,kZfd.,mR޹,OU Xϱxie;c,lȰBъQʰT2Uɼ {㩧˰EX#!,`)"nhWNH[nƗWҏW"rE}3mIVF- 7s֙@Aur!eҒR& ɰ|ĵ=Z+a*َaM|]|IG6CXj9"nlj++W_k|}y"-,YdY.b$K[.m\Mece?|.iVΌc풿}V9Y?qQ e]Vɰn +cX$/u~6,O`15W_^)o|xh9J}>*$H6 w\Xe,r=߯nwKt1*16ElksvI=dS s5U2orE_qE#֎`_HX3~E~}=W +n|;3j&R(M4 Y44?cyXZٍcnw hM +Kv {LuIư+uec +a%R+WdWU?S4,kee(k,d)R=W.LM^yQ/z;2oq,Ύu;N\1 b]adX9Þ8âJsЏ&[d~52 `)"Rv5I{ox=ZY +I$#Y/4bC֜cw9K:R+ӖҒmrl_.[a*ʰQl姒Q%zɥy kdDXoKX""rt}3ҏhf%JEI֌d ebC6cǽ5|K\+˖2 Ze^ 0nϰ;Oe^ +.6\U2m\akF`9RzA ū%"ͺ,(k +7L6dd XO8W2^~Z>eKhe91X b֖aFÚ YG;cǰ]7a,*d35+eWqRg]5QLe]HY,@˷_s,'x±ǤX=iDZxV-dž;~1fA,bm ;xhEdX)rưool# #X3JAǍ?t0^h%̚,KQLe%AvM@6dM5rcgSpRz\2VqO|c^˝'11a~M b%~n{\ecVΰvT%/*y{7nM7n*J5#X +_9JpYKm0,k${I}n6˒cWscQ+ielc{ʓ._N11nb3Bl7Af3l3lX2gX[%? !5}~R$U45 L`9*.h^l,YdY"ɺ,٭|)5f ]w9|Ι뱨񴲌c>}'%*z;vb 6 bK>es3baWɰPaM/aWɮZAi9J($ɾo dQ,cAs,/8ͱZO+8+O,V8ĦdY b:B+dJL۰c 'HhmKfW +nM`i9J(I~;iG4n)e,Jʋ/ N~}Rdކ5cX4ɲo#,6l_).k]Y6&ɚvFdY6Yڐ5cqʼO7u8vb߶r,=lO\c:%[8hѩs2,NVST%mؤI"O$`yk]_LYe)ɚ,F6r̫(6ⲷ]jeve/9*x@ʧ<)Nrc.` J,?L~,#wM6$b_2>٦Js6aEK RsvqDYI2lȢXaX7[؎ٱoZezVcqr;ǟO#O1XB, -MχM2l^>.99?XJ6,a.4E ,X_9qE<+Yldy$A톬c)9VcQ+/8ܳH۱8;U>O펿XO~BXjSe2- ҞqɰGV)î!NVuWVULưAe`%&Ou$J(k,d o~˱OXe;(i+;Qec)1fkb6?;څd|| >.y0cɼO%saK=r&e?7.̆IFiG?ec_r,2Iy,b=\cTzG!ψuX*i!da}w|;aז K+T2W6'Jl_]Z_ Ͳagɰ8ZK~閲+UraM""`%zՅTl2,WXOr9vkʱX5{{]Ʊs:*_Z!^g*fB'XL'+O$sCXjWVqF0ɆAdyAs[Wrk#*إ_xg[ CL'b_b>돱oتy!m2}f2 bLwQtW _2]~^*9n ++CX/6cNuQVa52d r,=j^󧧕i˟DZ?ʼ+;'?1=LX|mcc*E-ĺ66b12YLa|# +G+r방1l~oemA dXv9o}k_?cҼ/2/bǿӞҋ{1k +l4=:'Þ?̰V eXa WmmX;u6º_ldAVr96~۩V-ގwUcyǟbqp,U0~~:lau!vrb=bQBɻe#bO.{Yat^}xXdd߯cX/¦lZfSIGde +a9XSq췮i[d9֏'۳c31V7O. +MvX)oM>=5 2,>.Y fɰJy [!† 6L0I~b9̱?Xe;vGb߶ʴv.9_FhQL;жnKe2bou߽3ȰWȰъȰ:i ]uCl~- l:rj d킬˱t?2cqvw*1ݼQ]MOM6!ĢLpf>k3VGG+O%sa`ga` rci͟ke<ʭ''rˏ*gclr"o,eR ['Xii# bL廨gf밶JaslnxfI6 IXW+q|vi+r,Ӊ'bWr͞cТ>KLE|cgДɼޙ%S}vqMV:R,!l0IVl~ILXyXKtt,c b,}k1~XI'aAX&'F, b -^}̱;WϰoL2=Z1Xdo v-flQ Y/E[+˖wʴO2Nr,vQecb,}Ա11XͼQ'ǎ~WBl?2SR&Ӄ}sKvaF7ai[ǰ:*5$Yd$r0}sqtk?tQe=|}}=rMbL\d/ma^=ddzhj\&nqaOgX>ta ǰE3Zp r'9V4c!hwq"Kb!)1ɃJ1X͊Xg'BXjfe28?kJ>clJ-ʲAMdmse=6(iqcXyT'.N<KFjb,!rj b(ɴqbbi%ta1œ(ԏ Rba7)æWcؠHnLdlAƱ2[Gˎ8q1co=)a vy+'fwXtEsϻࢋ˰VLӟʰuj 6/fsMrlVq/KrO^]coc t|key 1XBJ,!v{m= X6d`2}bzz+v6f#lq$hk +Yαzlj+2UƑثߝ{}9]! o5SGA]v{{B,Ě6X?˯ڞӟʰ#æưFJ0[i 4ŒrLoL:tbcXhx|^g&՘by+biƃNF6/E~=T ͜ k*Y6o ce4iir,1v^W*)> }T,E따n(R~xЃG,!m7X+ fX>6gfARz{Vv[8;[Rci1|t?}E|udo5Xe~ꓱ{Ї=r*^YdlĚA,ɴk?l#3l[d+X&r*v9;cq⚙{ wsccr^0c*&gX'R!{ħN\Lb,?4cq?wkAWcBPB9!X= O~>|snCu)Ě6y.OX)7~ac ی[)Ⱥ7?}*r}Ty1vizP{5T6՘N 3헳b(OF>!v^boǻ}uRL_2T?=QruuyAϱZ{X7YebAŇN{K:C׼POT0eacebo'gpС?⨗sb%v؈ ~æ2/en֕cQ+{X7['1vyY^wk^ms!𨗼Ճ2dވ2Ko}{-_ןa#TƱrviX/7r Ǿ:O-n5@N CkPOPv[vK}=' k>~çnLXZI^% ǦDZVY"X0Eo| kljlpjlq6&(WOyZ=EGU7z%b%я}"mb+ a7flqkݎ^}෮.s6ฅN C-˿=Lc߳<#b܉'zonC,VbޜXf|^rdXVǺcߛ{%W<6e5DY#By;u2FXXSN?or]{MAۿ;i!6~;?{Wc/qN,\őAP>usPb/}.mxW<,![Ҵ22 2+ycXX9p>SyC|5Wӯ瞕T `5;nS|3)kʩB=2=lGc}^y>z]b77!beKFc3vt ,r/fc,>Syg_?y?м+w{/)Ryn-N +C=i}V,FOM}w}#וI & d>yڊG+j֌UƱ?_.RӯW\T[GVcq5uo&bAXPbgc䍱+!m2 bmLaY*X>7p_OӯAet5:%hr[ő׶P3=.w^ڏpMbr5mlj}Kaa*rQ}=6T oWcO~cNyAth R,/{k飶P^pd;woWCOs_%9o}w%~8Jw.ұ26QjILE0?xߞhPF|=#^WQ,}26_+_B,WD%ʰ0gv1]}7Xw⚫҆3OVc+tJ`b6&v-'P9݊]kE,ž}XKer2GcϏ?mc췿UN^Gӆ3+Tyҡ1v)-Z7;yʃn'tJފ5X<>yWwKy 4?.Y;fUN=Hp.tl<n5_`_8S)-ah#vOZ}ģT(_cO|igNFO|蓱/MJĖ2~4o[cE=!|"m8߭^_S:4C?E9Xwk~[(69X7-[;ao-n5OTs eMRފ}'A6Ė+~+-ScSӝ>JuJDlamrϽa/<]]xePnx@['onn-gh>>9nT.,8#G;q'ZKT(o|1EN v[ j1O4|P9XScqA}-A"_]l[bG>XiSNXyǢP~;ɶOC7-[c"m{@e_kD՗[!hH8hQQG1ǟt羥]8+G[Y]k[9-Ԡ-ZJ qbw!!F=!wBBPP(ZhЦ2푵^Ykkt:gc~׿1>!6bfIT4j쨹PnW$"XipNH>łCz\ )'N5ob{'ۧVLY1." _ƾ` *m5SczS eʴf_`2QC1o\ QԽߋb|cT B,ohyӯU$љL[YX&lLtbθ Z4 ( 9}B-'(b'5ĂF,9r1c4oƞx-"3%2rSzXv0)%$2Ar9 ߼}׾J֊rߩ8P~ي'*[8ާ'-?X$~gY6)bu)6hҢu.0h -ӵJkHvj0ru8Sr w +.'XVz D)Udݦc{xSZ >Ų͘bPA̸E0S}J)["0,'=ʼn4Kh`LT3 a/ bWGpD ܷ +؊Ă 505dʧu)g"&ҩƨ0v3&XS +%R$V*bzŹ.$(֩[au%% Z˯[܏ L(u5*f_'SF/q ;KH~E+N(RKיbP VZ5J{F'M+7ׇQR +j,0neJ3)ETcTasͲ DA(f׋J }ܧ+?ؓ4hGP'֊e.Ŧ˔ S}J*S~5c'=a!E[1Yd2QF1F[Ql$7C02p)>4<5)qG}]3e~x"c_==‚`׷ Ҁ-*KЪ85Jģyb2(Tl5^t)qGφ)Ki +՘AsRמa>|~9:-Jay(pLU$2ktFbpּ)VVaX3%}gvFgJOivx՘1os,CeuzB< ,? Qz1^iу((at)mRWcL )iuWWA%a[)0V$/ëD+3 D")-(M1{zՃr(VV,Lig_ol@Sz̾f-~/!08@K|Z}7N>($pLӌYXz`1XPXj-*B'"腉tb5Sc`, "#{{ҟ~AY )k妾 +`:b>S+ W$LSWzK$rߧ +%bo"gX[xK"X:frBKȄc"T^GQ 7s- +͔Ύ{ 3epa"蹣Ɯ?cރd?8}-%˜``_3Xgzҟaq,daC&U4U$qP,#˔P{_j4>kȎe>¾0K0!qD,(#9 3,c!XReJoGʔ W3n64ov aք`/ՏP?}K̢HkȄc"P& ź8[n#3W܄bV޸){_-L{_a1w1N0_#¾Fa.`/dY#8KEC22ǐ +2X)6, >Y--)WSCOQ +cg{32cA L0M0u7a($ ,cWLXާ_n )S=?c6U_TJy< #L0&:t~;32D,2/X<_bN()-Lt-&LAO&TܘɎ}+X#ſRTE8E2~~S+G?a`0 +_3f2d!s`u-+py,w)֩4kAe$Ƹطoal ~!.߀~|y XfP$ ,1gc*X1)6S~3]U[@5f~XoQ\i˜p5*v?׋y×&X4¾04a`?%i~!.K@󅟩!ψe2M2dh"9&v`%+.2cE$7SݹMO L*in8ߤ3Y jy*#H)= z)\]z饗)]|v `X(LKYgq`i9cQv,cS"Qv)Pbh,xd=;̸Ō)`j_x/Iú>`n 짔*;fkn,3N S&,+JBO7h3BreD2dlt pLXJ(Vl0"}0nA\8Hc*w1}Vy˱Ӿ0[ =x0E04^ﯾk@Zs]̠ I% Hg,cPX(SڶWc5* 8oa1sc1*.81sw :RH00a*E"SC~\]w_C@whf2@ <Z22Az,ƎeLt*%+> =[5xPپuc*9U%Yfk 0T00a_J(q7*i_K!eDK.%K +?rv,hS(X1*И)iGc5vblǍ6];ؘX[2c Rk,46h1Eagy]H(.! ܗdɛo[n)EUYJ}z4bL%LE2H 2Ȑ9w~e$UH&[ NX\D2)TcgaޢS;cJZ*޽s={n(`s:b0 ‚-!L  nteRfe2E2Ly 32`$Ubũ3%%ׯ*avK chǨ;= { }s;$a. *tHF&80Klrʕ/_B@ʕ- 8S0ȐdX!#ޱI(V2cL;z-Sq?oT:n .# &.(U| otط 7v]XHN$#C~)zUP^RAnbELV2o6$CϕX\R0V2Ȕal+5tP 7* ƚ4 *U(  ׎2kn^{kI2$ a"`0Ыr*UVV;IoYժUf` ]R22hc"X*vh͔j ~\Fj%KZ;ۋ V,w_iWvB7Œ c)WSKz5jTe_OWWHS4S0cPfI d,1'VvL0V0"X Sq Cm*ib=aN;BǯR%\(;vXkG:6hv~ {03ܕzSd˜`0e_ +_ڵԩ[n=OꃺuԮ @LHF G4dcn9&g ŊY3pj~y 1hӲyFԬ^&U*;ve8怌HC5HGg~*#¬ C VMKѫ^4hذa#ZA!j)g(C%hɆWC:':bWSPQï*a`lX7u*1=|?uot ~h_-:Yx϶E6a`DV[KKq&M6mڬY\էM45@ʐdhȑQĆrR`;K(VJ)jiV0ֹCV-5nPv LʎQ;+c X+e_clH1S rLJa;']sCW?00d>9M TY^\[iӶmvmڴiZnL ,Br,!#.oǼT)+ Ŋ_q%=A%1&+ u*6_V;zLq2g@vyC]W?`|;TQAH0a.ZڷСcNJW;vС}{ų6;P$S AV$ҷ%s L1> JXK(VJ)6y n06AalzPǏը+9vBeD|""TqqχI)HR3kW{W]tڭ[wP[n]v颀0k(#)OAvG*! 8vRotbYPLTcy† uЎN8v2~ ԼiEW?x!q| L0`` +`:z^z>瞞=hݺe@2eTլALKcWXc^4`,%˂ә2\aG>al,S9jReh|~oTA^oA/58G$o+]\ +؅i uSƫW>}ׯ+U~G잞=eH2ɔ%5_U X"t^aR0eCRWcx~8qG rLV-);VV G‰0X^au6_c?]'x1aa.S|*W."L0``=~0`A4T vg>” ) ֓KkذG14 +R >lAeL2d*Z6m %s 󲽥kb컩1<ɓP,+ʔj~ܘL\ TٽKGcw?xı2'a;+Yo1&f,$ˎWcA%1|T v]1VLL?7DOA:#9[52ǹЄc9 +5n &L8Ii|1q +! $SA־]4d:6/XvLTJs*cy.X)M5186֮"Q9Xm[ad(O{)HG`$Zt5Dapn 7ivIB2a*E*  R֩K” SL te޻| +J{{]Ll1L H%LE!iUNҨItV)+8 ŲjiiأG:/N\ܷR圙a%JLjc͚4BCVu2z; tu~tMvxS;zXa6aJH0 rUWQZk_^jl)L -Ǩc Ų)0w*=vA)U.[ vlI!VqW+4dڼBQo)POz1bE~ ƛ*a=at9sH$Lٯ 6nM6mm'߿q PLY22-'OCF>wQlJ{ +CiK's̐ @.gL^qIã/"·ћ4W:~>~叄b9 1*R۱-WxN4aE$#iUWz1~LoOU\Hb9LHgSz >>y0{ +lL}ʐmKfӥQ^ݍnB +<0v`,%e1!UG;fcfñ%!dFFGx x PGט_5FfnYYź00E0`/$׋J>y0= A%2XQ'rNct'6-jL2eI(c!lJc+9pu6x Iox1]<9=6U|A!H 2`^/Jrρfe +e OF C4NB;6d!BT@Z/Fkꇳs"X4lAxϘed 2ñ-cУX-` ƚ7mXvj1lé`3Ra*8l#K2&v dbvxh7.wwD lH9c~!>!8~J5|T1p͛4[_L ) rNsRc6Vb'Fi;Ys$COǾ8Oz1_]ۭ ?Y@&קZeL22 rVG;iyWu᠒kq ȔbLBܓTiʿ1d.4 +⋑{_0`Qa0'ԅ!8E4>\3g2 21_6+Q=_b=:os]ԩ ?]EϔbBBTJv b%c!`A$;BOtħS(x>Ư~1 ͦdЄYG3"Zr򲾥Mr :~F ;`pi>-21#ƻvމF?8H:e$ s{7zO;{,;s[ jesf_=3=3*f,b+3̀I +?G~; D9z_|Ec*G!,_aQ̜~ 嘋]8 ăAzQҜSB/f,%iEٱX Z}]z=>7a"=E~1]cx|a9&,DB 9mrbclϟ3}a5[L)73&~%m?wgЊ%o !)Hx b$=f+[׼0a13JeΩ#0qr1Xuخf;T,WؕXF_%UB\WZ;ɱ82do':?S!{բ7 2EؿV Xcǎ:6oy hu5ƙ6fJeRT4 r^As,ddi3~/F:|`}~,D2 w[y;Ly hN1̔ պ*ާĂ-E$1cy$Xx1d+Tbx<F{o; K>?ai ñ!u9~}0o ?Vc:S9ew}i k̘P, c_}30Af,kFoAѬ"u^0.IF 츧x%AجL SBM[KbP>c6Xj%CXw'T}8d_q, p1gzѣ4oyzfzapN٩,~_O[D1Hb Qȴ%':eF{\> A2 BX<$s91]Ƹ{'1l7W?SR_M[X3ό9P,y%EQ ̐H( g^۷gaCբtOzE>,`t9f06c~(S.L!3Ʒ)ό7cABD)C9 $3(sOsf'>FE@X_*1mB{Oc ~ʔ;uQqf1c43fɰE%K2]s3'[a &+¯u<~c8~)aIL.aBJ(8s, +ddfЌk{; ^1?Q%c ^|O+eʵ*S·[D1sRаDJ(@Eq5d_Fl{rQm=!bAi7w*߱L91?L[ަbDBD* sHx<-N7$)AX7 Jc栒2#Gzp̾ИpX[63[8BI(PEį $ >k ,옋1ScO9mi }u)6%㥯DI(XEs,2oaH~#!,0~*L画wP`ΌToSC"<)/Xc!\~E,FJŌ%OB1QҔ2R&R:y*)U򆈑11cIPL4G׸HٲYz02VֽH(&JN(R:w)۷j#eҷȘ;41cIPL8FGDHٵCM-~f~?ތ rTB1Q)#"qR>_nڶ1DJfU1妄b)2RǼK9i!zܾus33c)sYB1Qtr93&5B2>a1d$H(&J2u*RΛ9u/> [ę1ɔ9/(yJ)cޥ\dƍ1fL0GD kW,]8wqO=2}˔A3殶%BB1Qa|c[8f6)yU0ߥTfgdla3sgdJS rVB1Qp_]Js 4?t^t͘7?gJS1&! DG1/RꍯvdL0?e<[}kpf nSz~5&] DTD_ _j"=lƌf3voיҩƨ.c9#(1g~/Sڌ?i )"R* rDB1Q2wJBطK[̚4c-T׺{N)y DTdLGJ|핗^}\Jfl:1݌ռrŲg 3%1Fc±\PLL"exdEЌ1%(S$&SXJ Dz/(J)>[8f )aW[T-T3%TcNƘp,$%THf}s7c83֑V[tN6Q ٱSñS.(߇3ǔq["hh ~ʔ4JT`s,[:)?4$%UHӓmb3ӔL ˫#0T.YPB1QR72F~pަ߻M[ԯ]&U47avk'N /aPLTeJڿofcƍwj +vW?eJXn1Vc2dBK .AH(&JRO:Vnjb +~Z."j,1رZd! DU~%dxfgO?9pj *)TI<$Œ<6WWB1Qb˔o6cg - ~̔Uo/Lqo0vƘIa8ȊȮamb*{M3v͸g,)񜒪1G`K+ɾ*2aYRL~kH֌Mq ~)g_K ;ƨT3Jz&9~?ҌwDlĂ˔[4j2Vc%*3JcXX+#"ȄbˏWL٪yƸc TT v7rFzfYqL(&J"}gs5S?8?쮶g_[~8M88d + ȕgImԜB DIVtאj Z? qq/sa1AvE(e@m؜2 DIV:3fW[ۦ8S9%UcpcFcp *qOZiC+#t_qEPLh}2cf +pRgJ}j n"5Wf=J.Xs Y !WZ"YpL(&J߭TuJΔ81h6ăJ1H?)Jӱط\W[*L +dB1Qu<Ҍٙ1wڂ'wnݴa-Ͼb5֯W.`IOú|]w*T#cȼW)HhŁ,9fL/}iyfJ}q _` .c;\7V2dvQXim 2PfYsL(&Jb'LΔ0by6pPyWccpwTAd;?Hv9:=pC 6zNb+K_q'9%<#&nڷv0sc%Ʈ1*;9AvgR)]wdd.cB1QiƂ4̓[iƍfc8Zk(Us8ȑ}Jg~,d,d G DIW*3fM_r6ovc/s-%o:~*+9WjC NT֋B +riͰ,D2 xCm DIW +3r?[@5h 9-c*amJxJm.s!zG+^>~`tF7-;0T,d1(3c8m̔|ˡᇃJcMԅ)Jʖ.u3Jc~s8\̕,ddNu}7^nFhf"@6d+b+`pS0Jaj _r̈-J/YR%1Xa?f@fH} +ˏP?d(FmC ݷ78m}e DW،i (9UTv]X{XwV_Je.c%rz~ed}?dF].~:+RM4b~Owr]C.ƾ &S1~w1[8kӲyFԄ_[1U^*Vǰ? Hv[]E)w9"P:'J= 4bAiX2ߐX9$"XdjLcl=blclP?8daϩR18Xp2dΌ*heE:t^{h3e֒}ǻ!ñ(ʌLi[p51}P0`lAhQ9Vh0V^+9F@fHvvl`4SօCO0ϘeglLdCfec`DŽb|P gJ[aï10{wGשgʎX1+2&ye3ϣcivIvsC7d8mbPbnP1Q<aa9ָAڎAz 8v2QgJK 0 /Yx03?\ДoH}7XJ(/iƂR7ѣNG*~Gʷ+;9ej)G$tW.c֯AeҐfrC cDŽbPLPqG>cccsaCRiuюQDA?vK/AqutdtBbt%(%|4?Y[dd!s8:VfH'"(O)}JL)Ǎ11*َa,Ǯje#CUW?y]:22] . @j]2_j@O3S8߂LKDҎ[Ex~\ 0UvhJٱ թB9XK@%Q~~Kw]䱋ĺ\ ++Yk&Q h,v-bz㻁7肱2EboRo-,ƶi͛=c*UKvhW8-%ѐ]KLAB@Gݕկ7w\~:(P]?ِ0dg +X6*(_4c:S~{wÇ T v͛6nXf`c˗-sۭ! B[]y).1ƋE"rkAױG @'_?܋N p,PL7͔^Ï86c87v+QJc۴jbezP)UX\, ȐdWPQuwduR ЍgMj/3S}֠/ꍳ +rcA;P Dy㑙ROqO-pb _ar1Uد==aew5i@q reJ,d7w+OJ^].@M7TRf-,uMH4E'g ?+'gpi*bQT5tPi1B%΍ .1H#зw]:oۺef1ǪUQB92$l6ՕeվBeE*UԭJE QBM Y?j16*]мAX;m4AB1Q)8o{vmPqD;ֿO:wlp z~ʐd@v V-_xhv0ss`@ű3 ǂv,PLO͘Sۿ[Ri 2?JXKU[V ,V\ @$wQO ĝ<}.wYv!*UTYRUj?껕*fenCAf Y Wz̷c*Y DyLT0sc?z!۹ 1*g;6zʾc`ٰ>4d5C H!qSάWF]xxBnUV;S:}q539*i!pǰȎeOI(&+OQE`/#=zȡoڰ~ͪK/;6e1+S  zP])8*SĮ +v!Z5k֬T[N@YZ?h`VkdȌ! q̳cy1(RbT>kTzٱS!Vn9֩C6*XBC.Xe:au婂-(3wv!ԩ[nz+5@5dqzu͈eU]!JMONvMĘPLg*^5ݽC ֬\؜+}On]:)C֦*Y6UѲJuTˮ{Bt!5jԸq&Fi@3d1IAF7=)X2t`TcI˜PLohA1S*a%Jűіc,;dBE&du A{|pǝ.ʌw\U͚ݥԼyIT}Y3E-Cd ['KE$0=m1/U&cB1Qxp>r F.m;j% ϝ=869OKed-ɒ=RiOG=bW5Mev!\ +X-[lժUk6#-Κ5#rCg 4 7=w9>\ǎҔcQe!VB1Q)N\rUn߲ ڱ˗.^8,ظ1F 2h@?ezvGh$k(#5J UU..Zv!]L6mڶmۮ]w@u4/ڵm +~0duq +!cJǎX)NB1Q).Q3ac{Ȏ_J #C Ա};".Hz\Aw>aËرSN;wԕMvܩ =2M`h]P=1< ʤaL(&Ce11FG:U>;o|}*ViKed=uu@g+vOJ&3F ȅ޽{=z* >ѣ{wЌX(%U +!1x뱠 aL(&C/1kǠXIsl*C6|(o^`ɀd2tGP]l ݕujm2c]L{իW޽|>ݻ=fCMi׬2'9Vs0t6RK(&Ge1XۦTؾ=ıPϝ=sT2d tQOL Ֆ..]]@.V 0pAZtL5݅ [ Y*,c7')VJ2Rb'. USc+7Ǡ; lؐL2DYz*)Ѵ:d 5dСC) '1>S~ Y?L2Q9RQMld=Av^!TNñ0V^vc~0DaL(&Se1(8Uʎa;c%q {K)C6gl1de)Aփ*޺.Fpkرƍ?~D+R}}ƌ3fRoLp62l5)!3Oiq%T X< DyJ`t۹}M!X^@6ޜ@i9HSvqf$xYv1f͚={9sΝ;4 +Tϙ3{ dx֠@ևozFqL1htʱDcL(&_Ę-pR%ڱ^X#G<rl۶l}B-Z8_Y2"Le"WW +h _uqErEr!,XpEJR-\` hf:My]!d9ƱR1TU&cB1Q+cv1U++ ǰۻ{׎mʐACJ-0fRԛՕɺd\bKjɒ%K.]lٽVx%Kg@2lȆM>Br ҬR1NãjL(&gEcUz嘵c̱.c?6hdkVZܐLl.E=hS5cɌ!v[+VXr*j_ʕ+Vрf3thWsrezu Vv2<ϩO2ƄbV*cxcñÇ`~L]; Y֯lE=c.Ό/]Hի׬YvuJAiWӵk׬Q@[ ?yd$N0nhocǚ5ib%VvZ}Vi:0m`EJ(&oX0Ua%AA.A;*oPLTJ1>d;cDZ`~ YdH=L +kyJ]:3bۅ"r)\S=?y>>45+qs ҄X٫'ر-7m 򎪕`Jd1PL]Ke V{-d@C`|PG=eɌ컐]]Uǎ{DQc,R}1a6<.2 1|be>`లYjׄr :~:T~ +C)0f1˱8 H E=j"?"rWz/H} `v&5+)͙Ӧ@=6|}ж5:5W? +c?t1jL(&*KƎ921 2ȀdQ1Q(@u].") I}<#a16c^!DOiΝ5# X(7r : .)ݩ3 PL(&1i|y%2EK& 3c4,,蹐S] 7tMOX!t?pޜӧN?Vrl܀:e12՘PLT8N q .ȐYq|@A=FBe^.J/^ >U2(Bآ+Ɏ зwOH5"1vOΣnßR(&* E`̵c^=F+q DKd(Osԃ +qfJ/^?TOvqC +S ϙv̤J(CUc &1 DYTv ce8XZ%CO, +bO벋#c]\Rz#D}yG( @Tr7? L؂y`&=Re,pT D(813@Fe?O f6WP]Ev]r3Ɵwh7='m'T\Vbre(j*STcF#XȎq42dT4^椇TW]e˖]\ >o"^vE3FlfL4S%ci#c]s]B|PrҌ Dvc&XrD 9(3Qy)uzˠ SH}Wo WX~jeΟ1c7!.ʤdJX#}H 3 I1G]eJylץ.KwP CA@'mڱE Br*-&A[v +PᘙpAW w(#?! +..d{D Y E+I``VXƩrH7\{_j*M5d4cB1Q!xc r !F&Qs 5+]'}}/'4x}}0U2F GA|#b *T2 +R!r7ddH2w9Qu֛z@d˲`!Anj3m 'rXؖMcr * :ZչeƄbUz9;2M9zVWiwލeK}e>a}۷1zJ0۱!UY\VbҥJވ"L)8hiCLaz=C5+\vil}%C;bk&= ڱ1U] thn #1L)br> |4WrjC1. C|i?> }{0UB9F8vp4[zJP-u]`է14{Y!܏AGTJPf# T֩}jܠN;uO՘7nʔ9fƄbW,BgPQR*}vT}s t;o+T{6]kݢYuSc2̘PLTX!sA̍zh]W^ZLL_,JCܷg-߷vrT0ߵSV-pl ~QX8SvZ1Hcda}FOFf?3Voا4юA;R%c;9l\ ض[Ԫ^ͯƜLfL(& p1ddrF=˳}B/[3b[1+Ɏư۳blt:_]`lI1wϔn3fL(&"9,d; +W1E8y, #c/򑣇blЁ}{5{z܂3eN1HD昗,d_D DL"\ys؟^#aѣYݻdY&=bȀ0ofc5ʔc贅PL$:ҐE,2U,B?/$h9v?b|cV޻.#M?Ƹjj +^W,ik!&p,/}80Te +(sAf8FOJHX!֬w93Nc5Sc)s\/b"@"R,qe.'Y?a5+-?gԉxP٫{`j - SW]Db9A@ڋm#c$R(d>p۱ބr F. 5+-?{8HXfՆq Δ1?_(& )ъW\91H)uW,]njX r2%ާ rЌ DOF *!#;SoU۰npP9iPuض%[@sJS𧘶ȉ1H ǎJiVDtų,`l$;1cc77՘ΔxN ؂-\3cB1(2WQzv(VXc/>,ܩl0A%Tc05fJ[שv5͘PL$**>vA;cs5f3%ξ}J2ckW'3VG_f۞Dyb Wc>h;j2%Sz?["Xp?̘PL$JwcTr@f̎f krfB(&%YAy_ ǃW^#ML +ߚ*iXmJH$:E1c|uÏSc9MY +~7fZDIW5~WO ~f\:3B1(J5l5)ڶ +~g"`Ƽ1krDyh44dJOyTô͘w2֌ D" ˷c>jz3%̾R +~8꙱kCf,dž-b"Q~(>TWc:SSzfo9D1H$ +bLύن1̔8-נ-sHeƄb"Q(tsg'qG_ffk۔96*GL)a/"?O[n όUW[W~2PL$}50f1)霒 +~=m) 1^mqʌ '_)b"Q>)cnWSߘ1nmJXmqornB(&啢*L0ތ~zҹCPL$/17S:?LWߌl)\CDT ~oCB33cflCB1(@o3c6sH;<#B1(ߔ2SpR}ڌ=`Xz̭=,g [DSLi-،=k6%琪 /zDRO[n ӌ1^mAK_95tB1Ht)]3?1݌m\O)'5t`ߞ];۔MఅPL$CEg4fW[L0fwƷ)N|a Hʔf7cfW[~z2v5v +DT flƔ   +'_/48l-b"Q^fsHcGǹ| [d2PL$OY6c03F{h+<k=owYB1(O?ma̘=cߦwƒ5-b"Q*`ƾ6cB/}Jא5$|v5-b"Q*C3{`?#ұm˻߿=7W DWdy԰ق-3"9Z(&Lψ [DneJH`U=lq>gb [a7WoDTa b;lbsue3cB1La튥 Θ2atİEnmDa ,[slsPL$*>#-2hL-\- +A[˔A?+rsuevZV.S +DPf-Sf;ljh7WH}HTh؂\\_loD>o~\\y26W DP~k0l\=7JmDԛ-7W;τw6eʜD _nLY웫b"Qlv.SjHT(*eԛ+DneJHT(l\͗)c6W~,_Drl)ˑ˔B1`t26W˔ٻL) +FHEeʱps2/SD -xsj2e#Ly7LYB1pt՝ڵjN~y{X/S +DRLꑡ%EV/S +DRa?<L9.S˔kEe [DBRF23l)˔ʔYL) +IELi7W/#.Sf6l!D'ETgasuq_Dz( [tՕ6WB1t›2ej}HTXdsKUڹL\~_(&nv}gb\ݱm˻6W~?+b"Q)zsu2e`s"\=7W_̆D/S˔2=t2bL) +LE\\͗)<)B1TvswLyJ͘PL$*4eZ/S\˔B1U6WakZ(&.S.)7x5WfusPL$*8e:xrV.S~ӊ2PL$*< [drlnH×)X̗)b"Q/SN˔/S^p^6W DT&)_/S˔2eϘ˔\- +Pi/Sn~*/SeJ;lQPL$*Dx\͗)3;2e-b"Q!22cisՑ)csPL$*D2eʉpw2e7W DTH_\b/S˔?9bL) +R_a Lr\wL) +SE\Li6W˔e2PL$*LLޝ[Z}[$111Z5S( << +2< (*8,8t:鎝tgy +Puֿoozs)oÔ*ÔV00M)'\]aL`L~sua[SYdUݗ-T TO4n~sߢq0겿ǚn`5^Ô*j)-΄ÔÔ')w9l0圽lb0z~e0Ô[nÔ*cÔoo\0eo/[0Ovs5}\=)U W);\}N~m;\9Z`|M0eכk0e{˛SNznU ؔ7W77lq}#9`=n*aʔÔm7WZ\}~usuÔs4SV7W?Pu0 aʩoÔ*㬿l:L~s&}b6)U d/[t8Lxa 'l~٢aAc*ck?P?L9sxR`tg-kz\b0ަa;)[nxՊ*כS^aExR`u{٢Ô(oxg0a+aӺ|jqa[SW$\0\b0~>Lb@χ)j?caʋaSN:L9[Ø\rÔ{)7xd)=W/[<ӸGzrabÔ*n~ &\Qe98LbdwÔ}gaKaÔ_pr6_P1 aʦ-ÔGSn[˛0Y)7W޸a^P1` &ߟkzvSP0eǛ/[^\m_2{7WPaʮ7Wמ}J}\}oysuaʉ7W)onozGr{\]ߟśU t8L2~[ϯn~r1*n~0aÔS\=Ô*TɦÔ7W/Zoҗ-Hb@d/[t8Lxa 'l~٢a c*~sum)'zvSPa.7W_8esrsuS\0Ô-7Wojjz0}|^4Ô*4t{٢Ô(oxg0 >Lye>LyZÔ/٬\b@^S>z0%0.)gjLy_7W{aÔ-fc_ŀfSlBan\}Ta}Bŀf}\]L]va\b@S>t| )gjZxsua)SştVSТÔ0=w4nvuRŀV}\=0ea}RŀVSmaʖϭnlzSЪÔV00M)'\]0b@on9Ly}a=ÔljÔxBŀ6=W/[<ӸGzrabÔ*벿ǚn`5^Ô*뺿ae300aw/[t8L9-T )^S]?Lfo-oÔ*Laշ7np-T '>naJ&0eǛ/[^\m_2ЛU h7WW)\]_{`*ta7W7xsl7W77lq}#9`=nj:p2e0eշ7W_\0@1:0eus#U)ߟSPT1n~0eՋ֛e?Rd/[t8Lxa 'l~٢a c*tյT1Sva-7W/U l;qWX\b@g\~>SE/aJE/)7WQ\=00]L00iSeZŀnz9L|aÔÔk*t3a~Y\ 7WW)S6^]M -7WW)o~sQ)]qsuy2 cw7W_ꎇ)gts]wÔÔ'M8L97W]7W_q2\0_KuRŀz?LYlSsGn)_1Ô*L'\8L|S0S0eV7WS\=Ô*LÔV00M)'\]0bdz0-),SnSNe &~3o\}.h,T1`R]\XLz;LbvxL8Lyi>LybyrSe &ÔM/[T)r7W00e7Ww8L* d\}M7W0S0eǛ/[^\m_2ӛU ´oSvLU J)k7W[\trW1`*S\ݴ8}l?㛫U RÔ)c)n)g:0SV7W?Pu0 aʩoaJO6\]lzzl#Se)o:LyÔ/[ 0SSNrs SЃSva-7W/*`;qWX~7W0\~>Sxz)U E-z9Lyna}Rŀ^L00ixRŀrÔ)/ɇ)LvrF/[Г)SoO:LY\=Ô* /[?p7Ww:LT17}\]LX0e盫rRŀwÔÔ'M8L9սУ~S~va,T1G,_f)U yRŀ^ySÔWxr c*ÔjS63ee|3)U 7WÔmS#}tkΔm7C*ߟp?τ#0e)-<ߟ#0e ~Rŀ~syzNMRŀu:\~u?iy?߿_~ݷ4^#}~~[no2#wm|KH>RпISv߯)߿8߿|$T* JÔ]oܿ_+c[fHb4L|?Oy~u믌վ[>ᑲzj_rҍ1cI^kܪ鑲7T [n$Gn|Hbt:ܿ_{eO|HyuW_>#euӻ* ֔#Wƞt)O)/泔_{S1`Z&o#e񽐪_˳ߵacLŀ鸿ߚ߯^B*)RJlw-T ^=R>NRRo|𮅊mk{SH)y_kZƘ4qkeGW]~S1`~eHL)eqq=~ݣ]I7T ^)^|-߿׉Z46z~cLŀ겿Hx~=Oyk&%coߤuc1fMOv\xעucU )߯n|kQ[=qc~}G|c{,/+>Xzollbuyڸ_/no5ޫ4#eqv"|XXQʾU /g)yZTߗ1V{c(e^U =]);lw-o壔lY}{U>T1`=R޵U]rc|c'WlzޯnJW1`uzldvUb{7RVnHY~;I^P1`&kѼ1Xu3&nWoO~IŀAH危G?=kv流mdR0Hi+,+W7%}HYAR1`NL18Jtm_t~~Z){Bŀiy1V?Jٶڇ')+qS1`Fϟq~}HYbR򪅊3}ce{vSb~ۇc^P1`M/7%{-?<5GR6lzբ1fO#eQ~!eq}oVlyբբgT k-jRVg+N8EW-^*P#e?ɇc])eݗU I_(^;ڸazyeqOsmW-Ɗ^Wa~m4AR1`t~բQWW? cMR*̭ίZ~ G)[0&yaSŪ#HmG2b*0W&د$#HRN8^byT ^˗ ,nޯ<{+pե*Dh{բsž||BŊK-V,])U +V{y8xۥwAj;R0:ڹby 5|XuemʊԢjZŎb*̦ɏN< ƪKź\0btń]tM؇:Wqeu?>Dŀ킱5e*ӪSN_b@WobuXq;Lŀx_YݨO<^oTzXobQ7 ҄ob@.W1`bRsSŎV1` G߯CʲbteU ÷rCJ޾!U?{DŀyGŀbpVޗ*Fŀ@ŀRR1`ب0T n3.*R1`0T n* 7L*vU bpS1`0T n* 7MŀbpS1`0T n* 7MŀbpS1`0T n* 7MŀbpS1`0T n* 7MŀbpS1`0T n* 7MŀbpS1`0T n* 7MŀbpS1`0T n* 7MŀbpS1`0T n* 7Mŀbp*?U @Kg;p^CT1* 5m*&c0ux*IUM*skV9bNwʊS^1sw&T¸\}!W{?~QU4*O*bԨ*BG+vسMF_ޗ19@O4*7M{vX*zR[hXkt FĿEb0`YG+?c) R:VOU쁢b{?B eE#e=c(ګ1~}b+vhU-7劽u-m%bwébO}K_XaL`t?b+/}T\KZ*햛u+Cb'~}쓟z? Aa̘(jv/}=WӟXbsI0;թbwWW~T_b+3V똒(/UXŪX}_bUSŮ.+v,W|U[bg_p;rŪ jR6 cUFE1>\Q%]T}lث^>+o+AKŖnaQyIT'?ů+cR#Xm+j/?dC};,*SQ 7XR?+oXk'>Jj_6#e9Uk 5/#Gꁲܯ]g>>Z.n{s!Gwig*+V^X+x,3V/aEe~Z]/e}ډy\WO;/ڛnW#HŇG42VudH)xѰ*by((HUn.>N+*qY^}P:C|_̏ŧ){cc9dd\y.7K׿E e~?Eo*^WZ}A޽Ƶ-x_̸b/Ul7i+SŶn]^Aʋ?PjQl獱Haz,3Vv,LYXy}ٰ*bdžsO}kʯ+-^wqRV._MoXVMbc5.{=4_+>{;ǔK!%+[b#?'m{(bCW-Xw^\_.xuQ^?)o#o)amcEȊ!yJXa-"Q@k犽z_+T썩bŕⅱSga֌!K%30ERZ#\1='e-vsq_u_;/^+_NcUC|^_8r{?ACG>T1}_/吥hY?#2O=%,7_}Şc2o]{eч-ʗ^^%?5]Y]]jQA^wVxY]t#Gd1}ٯ;ϥiKo~[h_=FJ:Oo_8E|~>G+.輼ԡV/Z+-/b_0׾y{S<}HyaɧkN9⍱oj+)2}8V,,,Ǭ[`dv^iLX1n׊j[n,;'?*6ˏ(/ϨbqTy]Fo{{!g#ا狌}}?HI_0%zZE~?o?䧋Q;m*6wvEX~u^; k:^k!e_nzy2 c>|:gٯy+:s~5FH}iu\R6, bן{O?حiKyj-VlQ׶uR7Ǝ8+=<ȣ|3Eƾ׿Ա犐咥=g*9``EžK 7W}O>CܓGk'2_Xk|DY]S_Xݡb5M/URHyYy:cw}*3~ֱ0G?N~R<0":~ا>G~(;@Y+7/Z4 E5WVZ4m6+)Ͻ0 c>t)c/}%w9dd~jYYG/ο +ܰ|_gs>"v?F -(m5mW/Z4:USZ~HYmWc#1kN>󋝱nIϔ#)cɧ8;lT%߫>0BK;ԯ車 {67, bO=S>-7b}k)(mjse/NX푲.+>x]~7gє'8;"ddL-ַ|WyZiE¾'R7?O^+.b=Pֶ/ZU cbcl#ec0v+2cO<>ܱ'?tY*ٗ[<[5`w^__R*XNiK ?kҋ.8'b~2?Pm~uXm{pW\zuZ9=޽eXQ#ʞ+EukXH?,>Np'{<ɧrʞRRjFH}iu9`O=c {wU.$=Oqʉu~ e@ٴ-Vuʗ^'V!7ƪGͶئRz<7zNJ}'|2,,{A+=-'L.X ~Mח;?=Ot1GQfͪX_Ѣ犵~HY+>,0)X5xmi7u졇)BO>[O')<rܯ>"am~Dٽblc@xHY3>Ï>O?"cW]s]z=u0#d{я%FRZO~,#)a=a뮹عg~ }!λb,׽-ִ?KnWcGʍ0v;kg=O<%g}\zuϽ@.#|4,q`U <~G>s{﹫h؍_+/初rGqAkNFm6;Ucw-O)7|&i{;w={AyLsŗ~r󮻋=C<+=-( +v]w~n)vNc<=]-߾[6}BYgQnoOZ r7qE0Uvϔ\esλ_vW_:vͷvd)ew,\;n֛oJ +/]x9gV;<˻]<-ZoX|lrsb:=R_wu=;3NO玥y[RR>twFRj;P +X*-9aץ9,74y\؞ӎMXkʾ*ֲHY߯mϔ{߁EN83:缲cW\uu 7ޔSvm~G!`啞|Zt 9aW_uEٰ9SO>؁W~~j7?PeX푲Uۡ)cGS8vc~+Dv59e7ܘbv7|KV`DU<-okIS԰ σ)'9覈]Uikۯ(zP +endstream endobj 296 0 obj <>stream +#eXƖ,_Y6=UzzX.J!(W]{u]w}v0Ҋ|Z_W_]첔viأH9bŦd+FeE䑲2oU[}A~1ǭ):+!$,+ꪔ5Ӣ+Rr. ;?=K [s1G~A"7䊥ŮX9Mひbmg^ co\o%3妛o;v,2taGucq礉 sR.첔*Wy^i_vi +;38-7c:C{m|yr뽱j=PXGaM 3mmն9cg߁zG汓N93<+ ]t%F\ӒO ?+``gy駞rRÎ==}-Glۭ6mopaGv@;s8fe+-.'QyomNcMy+ϔ-ZlŪͷf޹.iK!S,SN9SOKN/r)V옜IsXnXv;lMzL[bY|2=O2b޶ź5,=Mn֍"7j[({HY{g|,۠||˭<@ۻw/JRZb@v`'C.|ZiNJ+ +wKcػvs[n^>Mnxyy|Wʪbma/[t8;6۾#d;K.YNٞ{嘽7,aW}Z)_{ KJXޱm޾i1m|⦈Mjk(xZ.Xcgl4bl\we;\iz;1moݸhX亯kX(ֲ?I:c o⥹c6-9d咕)vRRζߡ#0j}w l[,llܰ#ޛׯWwX(q=Sg앯zuTwylE +FErRr˶J5zdvSRRRrm"aX4W=b-ϓ=bkƊg2c'_TƱu<-YZl\"enclE.Ze+`{^)_mZ,l2aK9oZ7bixy'V{k7''bV鑲3e}Oiˏc7BJR[T#O H!HJKk$lܰ0Y bi2'VĺERʄ5E+7Ŧ1u&fO;ZDJS[,,lEJ`5zsR +RrRVKk]#(VČCZ;CV,,,,lIZa0&E_`qעsʂ儵6C^-bSVm+)[2VpQ!KYQԲlQb`5-r9(Xr bTt)bd?XalbƊqc)dy"%)+ZkrVX3SWѯ\<57:GQlUqx=W!+F*ee)f9g7cZ*V aejϒdĪ]ggʦjXǪ<*YԲuIL6+*X4UsX~,jXlGvZ}[{^넵Z`-\jXh+,Z8˗Z$%+ :Sz-_b [dU6X+/`G\xG\ra6H?h 6XlzK-\j׭Xt륿>wL?t\'\dᲥ߽|KϳtU/?rҕH?%VUͪϷd¥˗c[d-]pe\4|ϴ4 _+Eoxe+VmmEo[{W_%l"*/ +\|+2%.\~OxђQ*J/m/^pѢ%ߤ+,^~W-t6(/]pfV-\d'\\/_j?bqw\rYY֮kj]>ozܚ͡GSl -]xew^sܡG mpNGYuwn !m6g}]т7lE;?t~k:Eq"-<7f|QmZo~N[m`<_ʯ6Xpū/el| +W.XV.HǂkقHyo`%K/^6koq5/:`jڢg +臞Hѿp~g.eXEKFS*0G>K60xx!ѫ(zJ!|/'Sx3) @QFP`EO0⢗8s$z]&E3aLE/},z#z*1`FIEtA : -zEwEό@kdE?9[t6h=!gC`+@=q== 1=":-c'zfKt]K̮#ѱq0w{0ʢg=`EW`4EOy@=#0": ^tFDX )z0_D`EOs<$!=NtRGe>0E `Dn(=]tC V ѭ5`hD +`^րa],+zROt Jg4`(E `މЀ!0y$z4[t z2`D `^ʀQ]2x0:{)zFJt"EbHN@A 5U=#(:lG0`dE `E_ȊQ]8=y#.:rs'zF\tH̅  ѩ 30.k0-`D`EZxn,<=gc':{"zQtfE ^ ^ Xx Rl Rl + FT +S+`DTYt f*zD`)Jtf$zh."DS EI +Et/zhEiEw`(v] +4LG At=@t]GEPE?@WсOUt =:L&}&H^EMS$@&)Dg'CԢK Г `jѥI0RL-zbIt,=1$:SzK)DK%%^E`2ѳ@ 0Y *zPOt5]M΢$E) o,zJ[t8:#DHNv4E]|0Mh=LSt>ZDG]PEEp0}hf$: ѓDG=TtG*cLEw=TtG`S +EDRV)+`DD0"k +i`` +i`` +i`` +Q` +Q` +9` +9` +9` +!` +!` +!` + `VDG+0vW`D?%؉fKt_=̢%zEщH0+ `vEW#у슮,0.YZ`\DO=.:XyBtk=̅/z#ѹF_0Gs y`Dq܉..0⢇]\`EO:s*:(tTtt=̵#+zkFS :hqDA@#(z]_`DO7a  Lt=Dn00RGH FG\,:舞kEgC @#"z]b`DO4Bt==^80_Dnѳ <d`E2Ht!=/UU0DVS f`(E0Qt=SyL0E2 ]h`DO.Zt=wѝC0S `D p50EO+C#:= fW0d SC +.70EO(C):= ~Kl0Ģ#у p80_DO%C/:=s X00:DDFJt0c:#zAiD ) 3BAtDѿT/gQxYPqљFg^ ѱkѿ9_"}#FN>ԢK9W _ec':EqD3x_S(-?FA(8Ei0_5c-`|E>DГ/ ̩1_Dtu@0SǬ@C (.s$ m|E.O`E0_zc$΢|FJtҘ/GY-S%c)ѿL- +`E7u:UPN*+wDП?7!-FD-`:CtY_Q g0EWq>/D&0SWtS_?Ry':KP^ +.GE`E! )^Eie`DL_B/"E&z1U#=0,"جCYу00ʢg=`D`EO| 1=%.c'z/+c*z ,:*+z&:'.z#%x]*у!0# !z6):.D@@Wѣ"Ї`0iUt-BL-$zl z=9.}΢@ߢGH00S$. +LS N=K0S%E*V#"zq&zT`gLGY=f؉^̖IK`E0F;+zބqu#'\:aErH #.z0wgOe9=~Ȋ^̵ FS @ +#(zY#zQ=H^DFatDfE0"2gRy!z,/'Sn+y$z8GSb%z>avwGTJ (zJjU2K+zV!dgU&y-z\X'V+!=^ @2`8Dϭ0EQF +Z`DO0ENL W`D0OE/MO Q`(E0D/JU$ N`XEO0DHX0 Hr`Eϳ0D/G[< EZ`E0/D/DFAT BB`DO/z0"[ѳ-^"E?FJx a&z…0ыQ=Br!F`E z0\kk=\^sQT`EO0,zڅq/̑苞yaD/5F_ s!z0^ =¬^dfW +`D0Wc$zY//̢xaD-N %zm0vG` q=E*T Sу0 X`|E0`K += E'Z8 k0 Lb`EO0+ <^1"WxbD/#ȢbeY\ 3=LE!D0# c 1L_2LSv32LSv32LGduDзEEOзEEOП]EП]EЇ&=/C +L!zdD/Z =^(0J'у3L-z@OgB^E0%a2=>d!z|'z'z΢W-zLG D/ 9E QE QZD/iZD/iWH@ ѫf$zJR`gjȢ @X ѓ5x`DDO֌=\3W LpXAk_0H5+k,zf|EE،/|)1=e3}_^U&XcoQT"{:C2 R޻JXĨ)nޟSs>KG}g0% mW*ֵ6Ǝ+LZ}ubSȺ~e]qcXԲ1.t`Yo:0嬋nu7ƂkLgĺFYr/80}o L+mfvʺGkYtZ֯60ݬkp{ .N5` G Y J-dR6+q .*֯3`ɺGX%za.ƬKr ./2`Ϻ*GKX=m`C0GXP.1_a`XXy֯00,ks6"9F  +#uQeCǺHǨ~sc]c$Y01_[`Y=,0KuwR֥:F /j#uQbCͺ`Ȱ~Uag]cdX1S`X )0v ֕;FK + Fuag#úxP~=Qb]cY(1M`XR/&0zx )=U<[ $BFu!cJʺб~%Qe]cX.1\G`Y"/#0ڬ+z m=<C5P~ 6aZº=wh Ƭ_@={~aZź%hf_=mk|~aZȺ̇h'J_:+}L77h-bZ˺Ǵ~61_7ͬ}Lw h9]Zκ4~1M_4~L  օ?+ Sƅu폩e~cĺԲ~1b]c +Y\x0_.`Xw*o0vL7 ;Mk#>SƑu~1e +`_(`|Yw0 +_mƚuCA~f``_%`YW w==@{ګ6~`֝& X7@κ?X>r&P`"`-&Pf%`_e]&PúQDX5jX7 ++uY2Y +u>X,:@'zeºi@]X7 k;=~Mtg7;w@O[tgu._Ѕ W:~;@#W@{4~5Ǻ@=@߬Գ~/ͺ@ DXwaRNeo n&PfF f֯'P`:8~9wX_eU ~LuWa-0֍-@{uo1c^;Xc0HX u1yfd)Yck0x}8L VcYu1vpSź;_8bmon8Ƌ ` +Y7c0{1bUZ=ǸL9c,Xu1dh?o4n>0MzL嬿^Ǻh3nA0[ֲbL7.Xͺ i'oFR6{JذE`ƺivUL;V2XH`̺)io1릤%FسK;0[gȳ dY{u2ڬ=CĺAa_bݣ0pQF`X){0t۔dF֝H #NeXcu2b.˺_1_eݯ +PnYFw`Y,#0쬻aEv]he4XKFu2"w_`ݻ ;Ȱn_`Xw0C0J;e1Mf&fHY-Fu3ǺF d #Hne`TYw30¬bma *6fXFuO3,#Ϻg /@Xw6CK֝=o@KX77-a~úduchnj6]mO@ Y7:6:nt X?rd~ɺיn@kY;yh-vgZY?lmfL' 嬛cu3M3{c~}t~Ƃu31`L9 `\Xw?SԲ~ƈu4.1bM!G `X@S;mT~Ǝu4%*qd M +`YwBgD)fh(1e 0~Ɨu?4HXnYk-X?Hκ+ W0֍X?BֽX?BֽdY??ۣɲ~~XGb g!Mu4qO +~rP`$Mc2>i"԰n&@ Vo YwK}~`PϺ[F S4n`랩֏ +:ze 붩W nzb;Ω;'=n~B ~<+g}n:~6XwQ ǺgTo֍T=}njX?^yYSe&Ⱥ*~0qUrO&źY? *~ 0Y}U``*a `[+a `[+z+-AoA{AoA{AoA{AoA{AoA{AoA{AoA{AoA{AoA{A{AoA{AoA{A{AoA{A{AoA{A{AoA{A{AoA{A{AoA{A{A{A{AoA{A{A{7ފ +آ`oE{`^@^@^@^@^ 0h` h` ^aOW0W0yS[^CW0W0W0yS[a7W0W0W0yS[^S^aW0y[^W0^ahihLtVtXZ +b+:,c[^h+<ފ @VWZú&˺Y? 8뎪aYwTe&ºgT?]T#:~6+;'YwN=~HЅuGXL~ZPϺ[ge}Y?9YwHe`0֬[~Ɣu34U+1bM9 `,X>Ih-vǀ#B֍%g%`%ymp6$VfxY3Fu2J+CʺYa_`ݚ u#r_/es/oX7aRκoY8 0}5`YWȰ1'[ue `&6d *n#HstFjYgX7`fikX70&7\1~OyS nH`:7'%}^Kt%{`|t %=O~624gO~BsM1J؃5x7pMMӧ&y:$N5oj¦.o@ rhS r-5=Zk71 Ti_MS*q +Mm̼^]DOm;@8I㦒3Q%i +rh8Iw +DO<;@W#85yM1d٬Ay<0zHN7yPyWRɲ'jtb S_)M!m) +eOmb|H}H"_eFO<1x҂C;0)r8ZhdiFc5'Yeѣk<ł;Y09AN]hK8!oY#'OcѪ'K<=w`9i'N NIhĴ I#d-hA>}4{4zONmP9:9K787yhH|X~iW|)$O1x0dzP䄥*8irdi_9Qҿ˿(DOwt\hb0R-sj#'9Y['{C'6!gZjωk_XdO%yBdO^];=;0&zȉ$qqN7765>h>,|!OEHG'DO<1xRhj;JT#'U$'qq%p4pҼѰѠY%\M>\VsHgF&<Z-W O)wxrQ?Sndp*_⸖* 7ZĴѨјh(_}HG'DKy|K<1w;2:FNlRUTI77>n$m$j4bVXZ}4$}4{4z\,'O(xjsfu첈`:49 Ve54URd)7.nbHh̬J+;z'_XIHGGzBHHZ--xBs=Yլ7Օ;5cmթqmq|,!K8 +y&DϘV[mug oMa }!$#U=<ɃGf<2[͝6"vQ9i伩!rȑwU +%NNi޸fe ͘Zkmgo]aw=q5<>xBV;~=+YreUbPΪ!rB_V%Yd#čd [o}goCawO=Rhh*)xPȝf˝REӦ9Ϊ)rIO38Niqi#Y#Af6v6Qf?'mď=>yɃGrk$e6l7| e} I =R %O䎌w6+;ޝNC ^CS쬚"s䍫n$n\Hl1V[o6ζWV[m% $#Gʞ<5S?WmVZuYbZSwVDN8qy㪛MBHHlo;(vJqG'&O<͹;freUcHCkU +bdEN5qq}čD;.뮻U?>ygI >=RX<r'_J`zմVI#;s06r"'UIT7Iڸmwc=sϯ;{_wɒ' Ir'freuRw}9ic*-r9N8iƍK64{5c{oOp I  =Yd +RT*tecR:@t)sJ !>=>z4y6ZIԷYĎdu,v4`tշVISV4rb_劜VʪI* 7.m\Ht̙|!*K|̙@>.||~kтG,wt;PeN!uZU:0̩?"gUW]KW NnմqaFbÏ8YfVsOrGGOL,xF+Y㝤Z w|i;YCZʜD$GV_sđG*87Ji#iFfΜ#<ꨣΝ{t0o^O#9!?.|${|$ɣ#3W𤹳֚k*aW|!vt!tZ2'YreߗDr"gu@8ZlC(q‰y3ۧ I㏟?N8OrNN?~ w Džd_#O(x\kj6++w.+)َ߷dCT͜9~*Fk_Eƛx8đJ')n9VF̂ N9T4qzp)`Dd+|ɣ3SGZ-WNi߿ʲ]9Lubv|;0][8 |O}9W/rz%T8!p\ys|M54pg hB =>zB/x>ktNlT9 ÝH9뱲bG[,R.Z̉X#gW]}^W'9R8OJG7.n\e#a#Qsgusι⼔}pguK M=Z3r>{(jV.;~X -VMXiȜrk.0t"Ky䬳U[l)EN;Uq%Npy#3$l$k\,Z/p.I3_J iF̕e=Y;a wʱz,_-L\%s8'i_J9]j'Z:ʑjmj=ę5ȣJ4iFFFR/KJo\rKq#'WG's;>/,+2EUZ丶j}9zk4pNI54_~W\yW3/rG  =!y\##%\q#eOH<29lܑ#Xlejj%+Y=;<:oC.srhgY2/a&5#EU'/Юs%q\捫nnwK%jt*ܿ eO[nNGZ-_H#ys +-wt,fI%|e徸d[,?) ПB伾aVY299>r6b$r#sU 88_JibH޸FƥDC=Ï<ȣ" @>==wHu1xrW'Ε77Yʝ=vwY[\;yS'uiʜ8BN92YvV[Ⱦb举JgVsnHPU77.m$j\̙ʝ}\㻬SO{ϨOO%|y@.<v}fzB=tZ#;g,r' h+;bUSmoK:]o LUVJ9{|}}(U2;>_ڪ+qM+q/捫m\Hh|4z̖s92ޑ6KV,ʱ;ŒN:aoraSHJ@99l nA^~_5+Y3#9W^uuK'7f$ I=>yےo$wϒ,HNwfcg7++vjJ? IsqVZ+)sdkV;۞{H5VK_uˤɱtU.qS7i#Q%o O&PIy4x7ZY\q_$mYgr'vYIl/vb:r=fN2Ul˜M7raG̖q9^,)rndp%N87765.]^v~ ~X|Ih%O<ђܑKu"]:/fiu!!vd]z,WdG['"RvO`m?V~9m9YxbUh[N$q7>m4j\z%|IqVvڑtcbgݵt-v||BSǟâ9s#PG~CV2AV̑5+uy?Qf9I$9wuϽĉ)76>g|H'yO6K}sf!vd{KM7k_~#IP:@2'.[Zu5uoNsv]֬sԼc?dȹB#G&9ȹ|($/qbF&F$̫g@>!z4y*r,[u,-w.KcGFz,)vZZYkUя05XP{r>պo({s|#kV:O93U"_< čdϝ_~gOHWhh ;=wN(wt1;Z̙u!3OweMdR YꄱЫ2'[*^YզoLs9Ys:ii q:YҾԶuU!q|P฼g$/?_cqEK)y|rG~xǵYRbV;d}=we'bmF믛gX'ΒK/"̉VqW ;*WȚמּqֹ.!|Xz8~r8>n|ڄGAMjޱOts.$rȉENhSc#yq_jG1~4{ +IrGֳtΝ˺kdh;?\%,udXGKR=l +l]*#d݄,n 2vVdu5ץF9q#3RyMIߨ' . wxǗ;#YqMgJ5yG>µXYgV +4Xn^)uVS漹cY9l92vVa~\髾 JǕ8&f- 'FOL j'?Wm/w|ulݹNg;,:Wz,)v\uۻ:+uTQ2PPpU8Y9#0sdJ[>92Y}[o_,9Wi&/qbhɓ'KGOy'ϝ +Σ<Ý;W]qbO9i~:2Mvu\/r a)sR`M8'kU(s:tV9{o\_U81pI%G'<.xs';:) ]z,)v:nQ:2M~-77X_Y: 3/e+!KXʜ+ s|8%iIO,x'ϝ8WmNw4vعŲz,W\3橳=wi{ktKݖ\ ӸXX͜T.;9:ΐE+_t}92>#'O_'&N7Yd1_US J:zVhԓڹŷ;]ra:3w=vq7dC`,9:W_1*3GuGJ&geY0 Y$r!rdr%Np|ļ)F'Dy)/bdtY!v~~鱴عJuΑ>{ VVHtP():be9=Gu9ik‹2'vV.rdJ#U~y8Iļ)e)O1yqO1w{E;;/HlwŎLv\uiLc>C_oŦ:(_:7WY̑.E+-st,{y+P$Eί&N81oY(OL,x*̕˿d㪝2qtuy?vak| ֍,`FɅȅ̑,ʙdܝ20KZ-sd sJX6M8Yd.I,y O1wd㠶Y&i\ucH3zc>\ld-uYK~*%+BI%s>Z9qJ2Ǐsbku7|/sBgw'rJ#}91qb7ョ;r'Y ?;kbsSN<~Q2{vY/u0RzKoH֯.9q[ ]ku߼628я 9YK,pJq?FOVV;uhbK=H#-V:.:/8ḣqȁCfRet+]b5f/to]qO`%sU:qu7${s2wV?+~|D~9IT&͖S.{I 4w6;XR< vB\rygquf6}j+W~`iC`u"`ѥr?BZ]']Ï2G:+]?#71r9N1qyS6S j; +MXRH1u =k)'?OVRg-7pV_ŏu$AN9_"9yY +#stC5zBHg՟9EN8yS7NmS?˝eI# zbԹk7p핗]|9gأ~/u|Yc_eWɢ9d m!.O/%Y9T.Va,YG/9~S' .Y)|O)wb#ei%=dt5W^zᢳefRg ٖyͳNylV: tr݈,w]i2Gu*q=?Lc#kV4r9n߲I*R|#g;Zeiy{o^w4Xu:;nf:JUԩLxJǁNp3g)͜\s#Kƛo#idJ];KdMO%wr?'YyKu%w+utktu-M nU9r<#K̑M2Ήlq6@9ax\,rʉgt ;~;ZlGm|_?&co:_Ꜫ XqV__) uI246W@G٦/.'wZy9~܏O6jkB9Ih_U]k!ys')wŎX!us<)c{v Rꜫ X:Jr"&ɬ NqqN̜bhoud{_|2Vaʕ9Yg%r*DN5qzS*xb۬;c:/~;n:gqj YsՕN>IfzCd],}Xk \C!q 990?rJS&7MS͝J##w|#:<4X2K]uvq-7EV\> |E*J:_Mkݤ[m.]e΅yrhkU*sȩINmrfiKR՟|_:O>K e|±sgz{%CSG'rL9u0j +Ɓr5@&a9G'#K]ُstsOtoNsΪ9 3<6+N^hҧubwI=#|+Ir|F@tj@Gw"!rX.!9rު9l%#lUh9͑K֠i4v +Ŏίc_{7ga#;u$9_jX3i:uUaCdp%t~,B朡suȜcqO_UVa.S)rJ^CS-vbΏ~K[e NU5sn]|Wtvux=:e.[9ٗ9ygU[tIb;1uW~Jo=2Jjg@N0IWrBng'tKs tyE" :1c9$fN!8ZeNșttL6+Ǝ;Y_d V(uxBud9Y\3g +N-0ilt\?|r\!3gdqNZeNF1x)voJ{W~3e3c?IWr{`X3O6:kU6Б:Dx-e|}8G3Sه˯6f>sY6!Z+hU*s:FΤ)wjʝ Se,b\$CyD$kBȕ:\#W: ;hlYG= g%ses|k'Me&NCc')v4u?,_ߏս~sѢ&{_qi6WqN!;YG;S/y6Ϝ\6!K$U]S9NιS(vB V^#G +C٩C~\N_6:{=7W~NYb N?/3F̙ȩ˝4v|N^o=\q:I;ЃdOrX3/o!t)r +aN؉Cdp%t>d9ه0CېRϜ|*k)uVӔ8r'/v|䥎,`I_CkTt|XkFB\|Ȳpuɧ}E]z5y+ٟ9a\ +[Jg51vbR緿O^Cݔ|m~{_ٚ3Ow:@IȅJ?0y7"ɧʦKo#I˜i쬦#qjr:yt&ɺ|uf!t݁WWB'_Z"it謣/j'gΓWʳTL_Tr'Iԉ~;udWg-5s9}%uyqU:tU"9\Ct eJ˯Q s嵙ub'N+IC-WrbF;pWO$gN"Ǖ+\zaDWp%7|( KqNi< Sȝ*t9l^~< V̩VC9R'df.uo^wU r׮;nKUu[BMÅa[`hf*tm•,?˜eNLj/_*yts8h z\"-:ɶ:g0Dօ+[Z+NiFNCL:3'tTmַ-,a?s6Wɑ +9q¦@"dp9_/+ݨC믺LCc u{#WSdB\+9Z8D9<)tF%ٟr̼C\H`l:5SdEG/o ̛.lCdp\yoc2eI-_5|w?suDJ_`TO]B';t"-:zۦ͕_-:w`"Dž+8͖:Ey 91t6%t d6˙Bsuյ7ݸpt.Vf0VE.7Wr|SX%sVqzysՁRBz*tr"-:O\->CG:Q͜>BcEz)tt\\8y"•?W!N:roYae ꏗ (?t8E+W\=czSv!rp5z!t~#'>Bg^L[ښn=9ʚ+]-c@p՜9Ҭ!tC,"tf:ŽY.ՓguG,sn"tU d[t.CsW?Щl̩ħΏ^&t:oSWIg}ry>EN>Ys t9])tBRBB N6E[ö@݊rl:qhd Ru\/ l.t}\Mouq-0iҁNe<"3YG%B獥B'.O^d"˭a[`\:@g43 KWyrLS|[`:#90@ 9lёmYsj"['J +?V5ÅURl.N/0.]a΋/ɶ\eGց BRwUW|Z/)Y. +U\-oXIO`P: +/[H#@\O㙫U@:NzCRW%x>ݣS[dOrqW9mFk,`P˳raGI)?s+Wj:M.tf3D10/txy،:~_`\M[\:t#g7#gre/"'˫#90(=:J" (f HK|*^Tܝ:^t< J1PoFfR]]Rt\N>:@ԏzyzDG':~_O^{e7z:`td<=|kaȕBGf=+Ur:GB8Fն;*q<ꪰt_NX.oGsEzx+tCW)g D: czᷮ8p0PW :+ @ocl\O@o]t謹ǞߣX7# r7W0{i_ \/t`6dZ|{{ߝ}'|ߣnFnUCָI9_/!/=:ȱ)k0yMUy#]zM-NN@腁xyM3™CVI|xxlc`B:>&&K-1/׋tλ+ō:0Y6.("{YܣӖB&&xEd#奍+t`:o)\j3#+cd9_^\/6 +iEC鬧-nұzyX9^>ڙCSIxSKpߍq\~t=LNt9^jFcdW14]/oG::&&;VYc 6?0F7n #t+1׮nzȟ`2ճ5c3=['$:$tz3p~EՅLFcdֳ8F^Xލ򶭗FjzƻåcVF1roͅN#uZcd9Y#YOE}k*tj˳K-d7+o՟|y1ЯNNe1#1rz*BWB'_/?ݍFή |ֳ.ҩY/Z1rYnyִG:ac`^.Y ,U BSCB#˗R^Fw#1g~ +xJ~b/ލyÕ-ޤB'n z?vw#˥ctS:@?::D1tߍ,Z1Fn&?Gt3=_F#zkЗrsU7Katc`*܍\ڍ<&cdB늅Jk ͷB'[/ןF12B'g%ǻ{1#:@SN6rx*12C`+?ENɗB'l 'ڕpU~ gknBG.҉ɥc2F&t54WfxE~"XZ/12\%NO]U 9᷄z]j:@Oj|_:"p^>cdBM}@=:bo ?_jzҩʗˋFB'9!^>.cdBISs˳\B/ +pc`X]/yz*BSsaӟIW "10-1#:@il¾@3JlN,tg"9_ 57WE'"gP Nzz쪝cdB!s8E?/ i^/oowE]gNqN>EkSWGT/ +rB8dN6+W^8E^ypӬЙ=W7#+_<ձi:͜p{ʦȫߺ!Gϗ=:B1z!t0v̩ϲ*ۋt|q3rRԟh:iȜ@GEGN9 <00?^4:_/:9jy\顫0EsiS=BU3'ӁN\r 3{t pN Bh-s3WU܋M>\*-t{tBz:@I.s}s::E>a B|:@:a[op-ɦq_DvNaN BXi]C|%͕Er" aܣǴ!t:)-\!_-'?tFEvզ[nLr֕ތ\@A蠳9ɮ8Б-P+E'ʦ[WfU]41kZ>3GȲCG:\8sl/ rBAфæMC!r> gU)r/p BѠf'߾fdN6DցNht[4W~Nq/oR:~FOOee+Wisupbl Bg3&y:dΛ WKV[s7l+-0o +S'y> ߏkC茱AdMc߸JetJa#Zln ,6W9.)tm +BgL >mz93Gy!rj*4W~/rq6ܣC:-3Р(3og6D^7[-/7W7r]),GC茛>.e#zDU5s4ryC8eU\%{)B+MSIE3S~"5g V8Ul*LKǪ!tF/5e=<2l[e#'t* 7T?āNXn\>F3N/a󆊞kX??-sK'•"8 gJoHa<;1>3NsTS3DSy4YsyO9\X2gȕ-/\J("$<n=N}CMӧ~BseN̑ :_^kpf:D>E]v7@rrye_ C茮S )˛5%P5z:wj#'-sp%C);ttsޅ^q zo ͕nѩLC3CV)M%l: TJJtGfZ>jgrZB>Zy9q\fw!GȑlZ3WuN_#tZ)rJ%N5oJaۚ%P=ϴNIZ|=kY, W>G\:~#a[4WaNaL:#I'ɛBU(J E4DNYU1sgMlݎajc|ߡY-϶*ߢ32'-qʁM!iޞxGQI1ɓ'x3Sʜ|#s=k9+v]fuN=.;tdHN8D:a.(7W5SdB~]#'9N1obdA yɫ)x*<ޙ Tȩ)s8'.[-ʫ2gd.Uq:m_c:E~i^jI7IdI>e'DOϝc_g0̩9 +㜐9-/j3Ge9ߡtmC "U7>mbh|@}Y'&OwaN^_J$r:y#VZqdW4s֩BeDCd" d[`"tK%N8Ѽ&$GbG&O!md@9㙭[sX-\!-O:\:#g=ବ|{|gڞv3"I@ "9#Q ( AEs9<=f~9NShY^kL rs87M#Pa>3z## D=QOw2\gžFl19\8"QǺGԣ1OHn?VWɬLdZq9^[]2hx!9rYt"+P+H9)9SxơG#77jӔh4 WBuSNJG"i읈x-&M8]+'ȬCaIN>M9rm3e!ǜ :>u+"t Hɮ-Viᘍ!TN87F<ӢEL+`~ӊ@؇c#桘B' xrNxRw&Q-O?jt[+ZcO3ҟ~mAa:NYŕ91hcC Fe#Qɴi$!}Za4C1O Cw'rFbzjXr{gV0Ss:t:K9SϺ筤?94eD(8 "SV|gqp(rݰkD5SN9SO=M8C?/JB1P1ͭsA'tq+"C:NxDJN8H|cuCaٰiv֭['.O_?{X=jyX$r=8"Heē;=6'/d|xj[aS̱9\A7RI#V9v{w +Sd s"S_) 3N T8n(a۰k4{_tE}K YBǘGsOwYD$" ǷGxzhŗ}!p1G2+?1VA9G6ޱYyp#QpS`Р)RÜh1'rlZ`@8 نdêa .*ؿVC|z +|zI1OT<^y稈w/qq=ؽM 3(}r\fŗV >j6 +JnvO>y:pN"NSo+ZWɑ8q<|ӗC ɆM3dСÆ >|fC~;>"|=6OT<6Ix'"`OvoWwˤv짞#Y sJS+[k<_bsyRw"[ &90'xe Rᴪ(cql#K(IJaհfF=zb2n8+6j;C!Ps<&ъY~xzt+{۶$gcO9Z,IdM㮭v>'09("3NYO͐r:WrLZui{Ƒ*Fuòa׌aŌ?.@L Lb|=kx$Dˋwe'IkCu'sYc<УgJœ)fs̵އ}gw3r99'N +b|8!#+67AU!G8V8 ˆUÚ6m3f̘)3Sڴi ɇݣ ̣ⱙV;ZWߣk]9L/6կk߸Yq\}]ER>>Cͬ.2lq6[+Zy=ؓO{9V M NZy9vn0xW8>OVQY$UpJ1$ E3kٳ̹>3g}-DaPCax⑈^pWH?$v,zz<*y,J4D+a&bcżsQjpUn-]'z%сWӶ$g |lW_wϞwVYXŽ9l0灇 %d5cCH)2sLjU5 i'NqC]:rO4YCI8oD7,V )λkw [,;x3};Y@,rǘBZ̛{'ZIxsx ]-Ӫ1>q Z`N+B&ռJɜ6pʫ.v1T"nD7,6͖-[n{G[Adv>y(ZkCF{yx8բG-)w\53C 6}Wyd=(@>9Ӭ`׵fu|ox㸶So*[+Nr^[9tʅT赕WB[+I7Dž9&bN~?P䬸aMq8G) Feây'"oscc +H_~=PCWx(ѲYxgr/,2b +|H?@IGv]lV@ Keى"/&~X@Ƭ`fuP~u1m[ŕc2+hœpjeJpN6 99'(XIaFyܺawpc)^ FLCyxyG>/>RGb' x(J w={'GcOwVE~{>ƮEчǙmI[s$z78+ȡrNPBsN9sKlo96JyL|ocq41‘ F<:fb{X=7 +rr6.;<&76N(z<X񘀇wU7,3>%GCȇOYV 3^^f8mi#YI {0ǯ '8'Z9H9cnpngJ6JmUq4Pc|úa٨h%c~B>z({(yc yD<Dsg;RWցYةg/,K3 TWZfu`}F|v]ˬW#כ%r[t~vyy\ZyaIb8'H+ +mQN˾:?J 硽& +񍱍qP!%[,HG#u-үWx<c_l'1CpVY>[hw]e^cۖL깝o|H1'ȬL5' GR+8' NLk+.!ԪV:񥕄9nWV۹iÏ<2 F\Cfiz<x4;:'V Ynd_l~?l L3f`׵Ⱥ:0$q\-KrMD9ά0U@:%%GU\[=𭕤V}96JYu +r(Ҭu) }cmcT3׌~=yxƓw69 ]5t^N!LgY3tYU-hH$8]9-[ 6w@w٤6)S q$zK8pnj>c>OFfccw> :؁u+ +v^,{1%mAzŐr5̉VpNv Rrqs9'2s:v[+ 99mTL9:k8Rp7ٰX~!2 GCR^)R_r~aSbst*!3Δk+[BVhjŽ9A#~s3f~'qL± O'"Iމ$gY۴=<b9s]n"#w0%hWNYrH4$%Wٝ#9ڊKȦoq oS 1qޙI'kO87aW"x ē蝏wI]i#~X@Q6j5Zd:Pw ِqI9 +aN-tJB$αVõcR+oZV sݹ[/38N87Q9}|X{xDG^>'רld-Ձ[>3+V9销Ԃ6w4NtNéխ(cJcC+n; chY,SW~#x<=~b=]?7+u-|,uaJwq"ANT9A8Y!̩%N HuI=o~+ssl ٕsLjŽ9~/2Oy# 88DtDܓ$ J73v{(nV۵Ⱥ: ^fG0 r~nSh8'w ⓵sG&9GL Y9rkũ0#OED󍯖&䞐xz+s f#"ƭE~*%)UPUMa+')'R@rjStR +:fױڟ9GʔyaVu9OUY % &MlzZVlܦRo2뇞q\AP_]8Af btYr!s{_k 96V\Aޜgm2rLZ'{B& 'w9 nG|X?"(qݬE6ݮD7bPo\Sd +:ZDtityC9|meJ!p]A% se_-hœ'/ȉ'U7:yѧ+˺LKգu{:G Vj7 ^f4WWz̪@:E&KA\kS:[:gyzm9ܜC0Ϭw"Iw~N7h_1ѐ'`{'|5n"@[Gw]q>/gT9s S\tBǝpbEs\9ZٻR+ʛ/#ƩnR'W|y˼aOԣE?j[;ݮ PyE zMa+C9y)*P4s$8g8GKws̭0dVZI)&I0Oݼ[%qE?j1],э?=8n>DeRS -9ڻsJsxhԊ/$̉i'>$$.1d8@}SE +v],J7pRWŕ0@:$9t wbpK9;w?4 +;jl"]6Y;y x"q˴t[(~C+:G]E_2 Hȫ,~pWp#::;Gs6V\B92VG3I1Ow߯"{CvQeVGqBljʁsj SDҒ",FfWs.Wrm%䧞SP]Ʃp2¼lYh_QE/f+rS{(PN>tGJr:tEd,gtzAϋ9#'0p:|))HsV O0N$Zxϯf{l|pǁl̦ς:0qb?ANx~-reyPn{hu`%),N+"_a~ rC9gÏ:ǤVmo3\a_9M)xbIW>vǨ۞n|3-/]^`('@:"Cre;tLAy/wfW9[`pcSPo駩6K;1&}b/+ؽՁ>QpA{HXdJd*(",{CF?i*xr֐%-!s9'Z0'aT3w䝸xy"'8 +v:ۭePNށtD ĩCι8Gʭs#iL[3HeN<܉%ZV,*w]8PN~tC*--"ŕ4L6"֞{}瘎@rO~ aN,*qܽ `$aٷl*cL8i#)ծ<$NQU+to^Oył~9;gb<ڊKZ*+`?_O¯,{yny#UQ) +9'W^AGI7دsҜ'ZÜbtD"_='Ս_|-j( @: RENHt؂)"3&,cJ*bܽOX=$u'ߤS N<2#WAAs{^Ed1t@ι[59$x'E<6?c?_!Dv]58PNt@\y30j܄)gn\- <g-w ǗOš &X8)<*rrrܖ{ACGk|q% :6~g1瘫rSSpSӔwb VLX6I[*7t +OmMlA!Wڠsזm9OrM9A;SKNx-̄lHڭLƁrSp2TӒ+1~#Wڠ{d%䠜S6a3xU~5% )Nn(j*UCG +:L=kŕ\s#G)*S I\i \8p`BUdn %W2rգw蘂oZW{8g_xg2:'ZӁWܓA0*/@:&{ٵjr%Sቫ׮+Ӡy39r;R މrO*ѿ<"ߘ*)09V+{[.Lε-"\\syPjUg*;duPLجߒ),rl+tꌳα2)떭4Ed{YC99'rJ##''|jTߔ7t +K*xrŷa99ŽWFR>Y^m@:$ܶ|[[tA n 4\itl97t*JKdEj_&:7Wm9\yWrU:G@jI6Nx]iѱ3W(r[.yJAL?Ed,~Ts MܪȦEī"m'Zfm9'W#WC :jўkR@'ZE>ҫ"w"Z$'WfS :A9Oꜿ9́t +E4 _*}bM֚jއm-"W +.P@:"YdӢ\-s:tUsVP@:"/0z].,2HruUԠr) 9]-BUEGfBɕܖSr3,s@Yľuy«"_dȩɕסPA@:!u/ZUdEGg*v[)9bt +AJTE@'VE͡ܖ +:<ޠS.t +ANhJ{nёvhA'岼?[$۵TEG@/rCt" HƮ˛4m[^dEGHJhyz?Yuir]~A*Ib$W:rt蠈 *H'.-BE=hᒫmyr;9˻r[E=WڢZH[` +w˿ o}81^?̕\ *H'd tܾh"@ޖ * H'Ԣ/0"ˠv~KU$J. +L@:y&@o^*--01BAT +N~ɵ/04]_{~٬+$WtKBt]~td<.r~"o , p_l4p |Qp_<Lr3t]Gp@ |D`\?u/ZxUd$W2tD{=z[g/lroʾh"# '4leÏ=.] +T2N~u^R +N~yk_ t}i" @/^h7]tyu"9ҀtB- c Sˑ\u.]# +7z/0H?EH'dtB# Bb}.US3}Wxt9A5ԟ@H_l \[g^xU/06]ҩ79@7@s_@oL/ +tM.Rs\<^`}v@:^=v^T N})ȠtI=  T@:H`z @P/ ZSK0@tj 'Nҩ@:H6`z @P Z; @:3 @:9+ /@:# ?@:9 O@:9 _@:  o@:9 @:y #NV0@>t @W ,`dH'3 @:y 7NF0@t2 @w `dH' @P T0@!tRIH' @P 0@atRIH' @P D0@tI H' @P8 0@t`҉ + H' + ((N @PP @:0@at`  +  + + + +q`bX0@Qt 8@: @P  HGE0@t @P,  HE?@:HHHHH/ @P\  @PTt0@t0@QiEaK- @P|  @PTt0@ t0@QiK+ @P  @PTt0@it0@Qi%J- @P|t0@h%AJ, @P +t0@ iEJ. @Plt0@IipJ& @Pbt0@h`AJ% @Prt0@IhPJ$ @P4 `rI# @P44``ʃ& @Pjt0@JH (t0@)ieC (t0@9ʈ# @P4`rH/ @PV4,`SE (=. @PfTt0@ ʇ (;t0@QG ('Y: i(eBK# D:\^`jʓ* (7U:Ln`Jʕ (?S:l~`*ʗNNbbQeLJ3U+ @PTt0@YS @@ @P$N:Y JKJ'S1@62j?q`DW @PDL:ܩbĮ/N'(}Tt0@Si> (Ttr81@)>yb (U$Z @1@:>? '"8/K! %\ FţJS(XBUI'KR :/0y:5Ttj;ѧ @|EUH'1@yPu08 ( @p_`BQmq7D 6qˆ5y*N}B+0@|sb@<+DZ_ @gڴO0@ީx08}».yJ0(k3u ( +. k.r @P C:о@p}DJ_ OK~,~_  7U$oQ:qRB @P\*[:F @M}sJxNp] @u:.jF@|@Rҩ)vNJN-F@K'Ksx @P*X:y1@x}b @xad @P*W:u8( (.%@̨䋊N >L ?U!;dTtr=Xjw].]OJ'ۣ @P0*S:Ka"PO*Y:i0@Rҩ^qeDr_ FK.#.\E@ad +C%J'#H_1@\d84Tt?qMt_d(2* + 4*O: @u9 (- @c ^? +BI'@4yb ( +)z @\x!<((& @t@-g*R:؊JBeIdx7c#( @Sɱ2j@XcbCdS~y^o =蠊 @TjbX.?s@HQAҩ}DTt:JN %b +N n%RʒN} crB + d*C:j<`"J "*G:*m @Pz*F:yx +N> vbRS)UBKT% @Pt0@QIU@KT- @PuTt0@QGHT, @Pt0@UQHHT + @܍ʇʐNp]~ lV:؉ʆrN^ va!$t W` @\umڤgNT: t/k|"L@@1)o$ @ + ܢOn@tr@ơ2ȁΣ&=!DYK'$ @\ Iϔ@0OyJ'Kyb@,.IH,ߑt~i,ҹp @Oz &F rt  +8-I:?VUN@Mz6 +:]BWe 2:!,HΛ,'X:}L,tRIϮ tnp{t3=Ёt(s\Cr =<_Td:W]=L'X|NWt~2ŁA@'aL}"tDIN'-$ЉNzrÓxvzxv@tDiJ:A÷WuH;;<B#s8@+)iH_=oG >tڴljo|Ms@ t2eW|`mj١jמ#udOI:Xv;zFN9\qEdW\+mH6N$ҹmS:i0_ntG 3gE:8H~ֱQX +81)s+.O9ߵבMOAs:ƍzizt#qjN*܍dW%#D:u>wΘǺPX-+G9䜟ǟ~]qvC29t`*St}uN.Ut}rٕ)ȫV:\XBiG[*8G+ +tz]~\^]yܭ2'nѴqisЗ҉]e~zjg t6ߣu'ǔ_Yv;,@qSGעz7_}RҹC.MGtjOuy9ՠakgҎ,ud'.$+E:w~1PPaGƱ85бt6"W7P{O$tk]'tr#e;݀"yՂ!['kG#(v<~ʮssp~cr(k/3v]-]p>בǎbnu + G_+tr(x[ L^^9ܳc~?a?xv+/=O<mwՊ믽z铹|I޶7PVA:9tB]:ZGpއ}) u:Y;~)Gc Ƈ8֛s^:oet!#Uh=(X֑]kGtv޳+u:aQC{O=@1GG8? 8G?$ΝMv@J:JpCwe=-`WuS#Y$wz}ƛwX<zX>Oǝ8>p*œW_~yvΣڳ{:(Сj馤#ud +>t2 ^u=5$n^wmٶ9y,˯F[w{EN R+/✽{{|wEeK:k +7$P:8d_* IgƜ|e~Mkm઎Z_`u;$ +y=l%8n|d{FضMpy]ْ֑ݍy0_ZH'~@:y˞s]hn\#Euv1ΰ#ޡxC!mя]@pG[eVγO?csvs6~oIv5Җt:1zs8>zĩ3fϻrWZ-:;vyǟ`GCyU2<›E9>H8bY9<=[7Sruj,bKveJ:\^ե70sӦKg&N>{\IC{)ȣ?SOw^xCa*(8s$13 +sscՍ7,]J tlveK:1χt«=C5_2xqLuCMwn޺M^ +vT;g{yRü (| ϓp8Or޷v߷c:gM+]w9йl ]qvŏؒ#yt́{grQgr;s<$y'Hz$mvwNv2ΖwAʹRW.̛3ƍ>d WtidWGnK:^N15Dg=zJB)fΙjVDh$2;>eؘ'qǎ{ݾ} wy&QΚVݰ\Ι6e#^:_ \ +tN+St I̛4ki*ɜ_]D^6isu,]ΚoYzs-[=df^@NC:[nrMou-K[s9nj:9gqI\kI'ZGtt Bwٵ|ɯLC :W-vv޲q#s]-§]wIaluגrVXvk^5la9]+:49US˫4{:μy+_PgQ`M3wU !,[~U7wnfܺճqӦMw(wJ9|7mڸ6 6΍rQju;}]@G:zI'*wRʄ:|5tdʰf_1JbvVwn|-֭'~"ׯc߬]bRUsfM|8gȥqrե t\Ϯjyye4!7i+\ԑʅ:` :Cִ\y5G;ױwDMC;odW2WP,'Ǒ%߰pfq&O0^3h}zrfhr=:~0t•/E iҬ'Xg%֡ E}s#;2dgYI>s`ZJ=|"dΞ=kL$I);3J.y[}ܺeML㗑kWبc򫃿(SNoks~993^CzH>g3 D"J:Ӧ]NQgNQ+œw;Sʭ9mZ6+J7WWeڕt:ܩ)%kC VOtԥ[w vD; #R\6aĉH>L!JF:t:'MȾ!ጡg $0{.=9:P[qN+*c+XjX+;\J=3nxg+gON$d f$ g` +rGCUs9m\et Yίlb3lwιbu.ӷ?yg3bQ>cdsȧ'ёKPӧ7)2ΔZ9"Օ:~9*u8 +s)u8Q\س7y3xȐ$aÉH@1ǑO&СCoD88ك.J89\бUUJQ'|{`qYGdN(t;N/# 䒁,b03$‘xPἔlC!߈pzIAN{N;MZiJ{t]%u8 +BK:l&SEYgv:vyGCۯ_d(-0ɤJח}Aơ sGrj+aNjd7(gBM .8|H9l{:)GJN8X9\I trWI u8sq7E+ig=SCyE+< sN:oX8gqN=6p9#KrV$H u\dΡqphe'Q⡈gC!ہh(Iǔ+|LiQNHjuءDJjqU4q^C;Hv8jRӴYsN6FtTO&݈oH8qep5GSs䪖N8ԑ+:59JQyH=G8P^ǔN+ٖ's9ZЩs꘲NT;Gw8!PCiڌCaYZJNp"QKaߐp8Ʊ9WSS@'ZJN8w491Gh(/ٔsZöir"F +'9_JsN҉:.N8hC񎈇s<#Jw$qS{UArĜX6 c2 sS@'$h%;N;P1!{ +#q=uGc+ɬ81=yqN,u(19'Y;,cRHQ @yTpf{WN tj\:ul崣{LjGGsNʺaߨpqr,U9u t2Y`Gr,I$9FcX8HbK¹U`cC*Ps*;Gj9N9ΩCr8)N;"2m# wew<%ݐoD8qJ':ӎG#|PƸzFSNPɋs2[G;$cV@2Ɲ֯m7*cO9A?8鄬Xv$!xyX=>_s +/S!HC9qE:YiG1Q +(sq{FCkXœ<9':Ak'#PSe +G8'N:aa8z}ce=r7,qraNKTَxw`"*ZT0@)g(PJ\(P_Jm@9ȳn7p}ٶC'N2;ФQW4nݪM-Zj٪QF7iݼYMsE-jѨ@UzO;fM[4nӬEF'4o֬qVMZ5C4n޴M+i6}M[nܪYfaM[7iѨi˦/ϵiܦe6h޸eMQ b5_ۂ[_۲Y5ؼi㦭nI5iѸYkӺq&mմiڸyMӖgZ5nݬUE?m!V5[nşjݸEMMF5[5n޲E3?ѲeӚF5MkOhҲqfEOҬMZ҇M4aI}ӡpiṯz_9Ķ&1h҈qcN$5i^ӢMcx #kt̙g4hMF_޻K ;ktRcW hdNntL5MߛhOBރ<Ǡ9h!k?$3b̯2lXsE!pb!SF r~3S\r'i޸u&5_~ՔowVZ c 0׹_nԌ9 }y#?ʧF͚4iުU /JWu@kš'R$A.-#o.T<4J]h(3P:R @w+IJOsJsRߠG 'γA))OPkJLr?@2ΘAQX RgƠ(O1E`PG@uR|4,J)uj Ss(u @2>ʔR'ԂReASE?{woZЇ=cTB+ʌ E2(3U@/ pxQAAƴjvHlf4k{Zk߿qZ|~' +Ǘ;gM-&Ĥ8P %H[I}JuE"LLOkI/ ܤ/f.'0Ow{pYs~o-S~?,`ހ0^wl`\Ҁc / tߊǔNIN"-~\:f/N 8tM ;I9p{)`,i(`tұp;'`S 0 ؔ~LI:IJGMt+~t(Nt$t~Y:K/s<$x'{L+.T,'>`M:)IؔE`]vJ$0vw-Ig$0^+K`toSL`\QNM`DoPN /poJ*@FqH8t~pdX$$ +C8J,p*wZ$o5$gO:qcJHG/p  &Rc8\(8DX[m#O=S1Jg3p+Nh7 i:w ci` HG5Edؔ~0%֤"LL:IJ7PLU:.`)+n`Y*V`&q(>`>҉'&`Vҡ%`nҹ$]f(p)`!]f+00gKW~K<Y_:`MRf(].H:`nತSf%].N:`>⤃#.Q:`&B .WKz>`ҍҥtJwyi.&)]t`)}&Ĥ+<kLI)}2d;[ts`Ӑnl>`ҵG]p). }Px:7H0^gTp+(.!}h:{H0.~Hc"}z(9H0 +b[9K!ItN$8w>I &]8a&H7q#}@@p4#-8g.STJp,}7Ǘ>[LK-p& I8tT' \tp*N.]8!nVJmN+} 6'>jT]sH6p 9O8tL_ep&/ݲ8GUcJk*}15>yhsK<p4r @@H7k2AV>ҵwĤ t )} + 5an"8\M>@* @^,4> XO$[D0 .HP4#>`? %C>0.s NhJwg(}:3c>VJPptk`,ݚ7HWfF-}Lu}QKSpt_`'.L@M HV])0 +Hd&#}dtG`2GlJwd$}jtA`b,1ӓ>LO^0I t/`'58\ҥ1Ӗ>h: 䥏2.W 0 .D@[0>8 + 52<6@QJ,,O6,@җtI`҇J?8H_3 ,]FI/*pnl86%N.]7)wt78t`eII.҅KuÓ=>f(}Kg+}c$}A +endstream endobj 297 0 obj <>stream +^n%],so7 -W&pҧ4[ +`Spx 7K?#RpoH?5@^0LJ_{#J襏ijJ_lN"X%J&}0Vr& .H-㑥/'.B҇]~ `G= }T'} >V җH?07>9W K?0Sds8%St.G03q2Z~03c" +`8t1IIC Ӑ>.`5IEA ҝF*}Dp+c>C<Of0"c+$EL@" yå$b*( &}pR HJHMZ^,]0|ҧ.Ǘp&#HL8y &\}N(}pr >c8tHIxOW'=G+gpLst Hd{(A8 &]Eg)I6 +w>HKR8\ /I@#t'PF!]KH7S[`D>9t?=MF']Qg&cnp+JUY`En>-tWJF-]W:sK7V)}H0 +ۥOH& ]Z` 4{+l>tuM)IWX>t{5IXXJLO@/}$0I E<`5yT,58\p'!.\I,-} 0yJ JL^pg sn\L-(}0b %J~GpqG\-%}07 IzMpA҇3.\ K."}0O EHwV0JW]/}0g ̥:,vḀ /s>t`ҧV`ҝJq\t`!]{H7_f(}p)Jn\t`n'$]~I_&}pYYIk\t`V']IW`#}p-Hh\t `&(݂Ja }pE9Hf\t`G+݅QEKa-}puiKc\t`.݈!K7b&,}eO00kp f >Hb&)}|@LR^0= zj c/w +vIc8-Ypt?+*ݎ8INp?#X.Ȱ1%-Gkn9ņJ`S#ÚĈolM (J.A;-5K~-}\gHd.Hay.ݔ})~`tSfJy,tNLd3~`tYf/I?GY2ӓ~fOyaҏ0\'ݗ~xإP)41=gňWTOS~Zf̸G'1nn͌EI$#1jn%]IJ?}B1d&J8~#Itwҏ~<{HgN.1%駕QH?t}S~r K?ts~I?zthҏs~ H?tptO~9Hh~vǜI?kptfoG~9SKin+p>'~N҅(PJwjK?&,8tfMq_H7kS7Kpd +&]/Z~1MQcJKpǑ~o5AψJ?Ap|=; ǔ{NҏDhVI8\SIwIO8H?5pB=kcoGN+ݸ-} g~ CwOOAXOJ?)p&= #sVҏ O}Z.YsKwI(7H? c0?VvJ?.IkӓesaJ~n eC.琾0c6t=?uYIA&8KѤ/$V#wx0rzF-]Zpq=Y,}r/]t\၅T 0z;\S<̓oչmHſD{~q7f%F6MIjK0Ow!}`/B&l_\̥YVVEH󔾫p) o)\ 07 %JfeI/pqc|$\0(D6JOspҫo \00m-= L[Koue@5o@^&)}^z$z`zw XJ]Rz'֤)I+`Sz-6ׂH(``0 l !}қoSz6vJc?uopr0j =W7K#-Ho p+ a0F{VzE n+"N{H 㒾C¸0"[-='E>{K c!ҋ(op0 +(=*pһBXK +aIzZHJ_{NBRw^bU =0d:p! }Ho KMzf8&=3[zǔ^*}cJ/ gdžI_ic4pd|W8p& _zo8eN"=9C'!}SI'WK_`i.pBW8pBK Vz{8N.=?J'N%}]sH/'9H_TL#(p&W8qd Oz8*=ESZg")}-sKG׈I_H =HG*A8WHoG@Fz8%bҳ]%*}2q'$;I_< ,=N.}8qāҗ KJ_6`! Dq5"R-}H{K_0`DC~W P%U!}qIo{H_*`tsm0: bq+QzEF*=Z,}J7K_!`һ җnqF-=]\'}mQKOI_`N ]z)}a Hۥ +0cU!al$47-җ)}=H&}1)I/kĤnj&&=f,0== ^245&)=ikLUz0kJf pf `t52ke&ʬLY(0]f `t52ke&ʬLY(0Qf `D52keˬLY(0]f `t52keˬLY(0]f `D52ke&ʬLY.0Qf `D52ke&ʬLY(0] `D52ke&ʬLY(0]f `D5:֬a̬LY(0Qf `Dqְld&ʬLY(0Qf `iX61ke&ʬL)f pf `h0kvYòY(0E'4,52kuYòy6 ptg5,q5):a̳e80E4,Qf pMìEvְlIOe'gҗ&}1H[/ 0 c%& =`씾0/0^f+QzEF'=W!}I{K_0`Łҗ Kw~@Fz8U-FSZ!N"}QJoW3I_fKù7p!&}åw^F$}+J㕾3N`w XJSopҫ|$\0s 3~*-T-;H?5~;Ι4[4l +l⛥C#YL1CYH)CYFm`W%q|רN_Q9a&wP/ N]2:}mXmx{Θoee#L= tq\]&[]J.WnקC;*Mh ھ|m&N]һ#Z>t`E򿱗bz{B h` +v%M}S@.n m%wyk;zKF J,_ #=73Twz*_{ؚ!t`^Tޒla5[z="-7TE[r%CjD%f@g`bOJ._ <K_K6jHFJBU`ޞX^ @^Ͱ^I镐^F}s>@v`^T^!qpiEI eF_Z>#We \^嫩}?kaL+eۧ2 浾ʋ@kVz!"z=Wzm&g ʼ#2WBywd/+a=tkz|N*rܘW*[Wyk.E,P2y5 ; X}J^荄y2+<2LCoK׬r}Lnk 33+njk+z0oЖWSrɋ W|EE^t EF]zX9Y|m}N8`n;*`n"k]<"D^WV_߯V^>) |93'je^2sc,r+T^drȋa+ZI}"^tѵG-z% +}5 Į-[y{e̋cQ[,׮\Sr>KmG,,^3Dv 5kF/"z#7 Z@ߜ8m|c2_2c,srLn<#G5ޢU}ِ-)]2˄ 5u8Ѽ=wV=[,/BEr㒽%|m}NL`.n-UZe+Wcr-[ ~|h/u-7"zWz5z>g Ѽ=*b̋\sj,T.\#q'vTڹxNu}dפ1Bz%kDׄzk] bX|p9ol8[DdVsWr>\BFr.v?{w^V^ݲtIҋ#k+ *"±>p\|uݐq*w$2/F0!a+}˫\BDr {3:E>/捫xJm^?͛|2oeF>8y%۞q]2y2s)̏|j.wmr-K&\C< W ?+/{n >[Jא3>=Te@] +>gv+{f$Fen[Fj0Ja~crוk*P.\q/꼸K((]tI5Etע ]VZmh GY+[s.S-Fsm<\Q̥0cҖXrM>K$@Yҗeo+^>xEU݋kZנ1݇tG-%nAׯǐeZ?ce4yK2Ue1ڔт|W>K]nmt.kQ2$rM.o/x kdפ.1RV]-OhCy[  y%J2oTe`KF\rC*Pn\e^WY|5_v/^Һu-KD=$PWz@t0o\;Y:Z<,k\Kd^mh-~ ҖK,w]r %kw׾u߽EEyE5KNw)]CetףQ.]ӆ/Ы\_7Y<q5y3ܾ+}0sc \r0\r %k oxc{:7oZ{q -KH&]ztE/zlj>im(ye~XEi.X$s33axaˋXSr57._w5Kk^n1BѥE/z#ży9}ׁۖy#Ki.XM6f -%z0?1j.]W.Mr%k +o;wnQQ^ѽfvI]Jw!]tѯ.SP_|ެ{ij 5ټW~knX3=l㿡2o /r˵-X.\CfrI|xݝT~Z~߽{q ]LהBen =z5庱%WlpS6E} ئg|qdm0\F![*wE %k}{{߿0{Q%[Lt-7z-Wsݍg<͋\!`++;d-`\kW.\Cfr ]C?Z kd.9t]3EzB/N@c=8⼖äͫFWy2/Ƽ5k[b}_הK(L~r }c??#W~Z~߽{q )݅tG?P[$Bt)u(+f<|Ap͋EEi}e^l<\F%P.\F'?O}S?ZX /u/q]ҥH(=>P_uycXE<;mUMyE-Bke#O+]6@|~"ySVRg;m#Qfs6/uϨy3/>kn[my0/r+TerIǟOOO_7w/^\u%KH.=ok N}/K_?O=O}Vuc[\njEe[Fݘ7y#brWPn\f>w~_UU^ӽu %*O~֡O赀{6poyY>?яZYyuep.o^d_Z74ڠE#V<|7|/lÿ:e`^!?Zs+TBdr-~;P Zbn1ݥt%Kne]&pGߟϫ_75scszV56ml>\Ksۙ[2E/.+s_\6`^)̋\m'JW.\CdrI]/__t/q]t5Kn]n];@ׁc`1o][7y3pK<_m`v{lF_e__U}i{g$s[Ke.[z0r1Xn܅r5_X~V~[^$u]H#z(]B{V/+߯kFúQZw]l5@sbިs[7w7gk'Oom o8/l&/h~˿>/׍:>os~2}P-vߞes4?g<|i%s3Ze1|̛\r.KQ3.{7~?foUU^ӽu >k2FtY:ZBo~裭@z%7\yJe}^{c6ymm *NWs5ꇁ|4jm~c O|Rg=[R'ehVV.6̫RXn\BdrIƿ[_t~/*^ڲtK.tҢZ9 Lm +t8\>|k>?yuϫ\ōmCyvR^2iO*[sE4|"*C[ecny\6]WRy5:u)-KNCG׈_-]t٠k<:o/ou㞧nOv9hIۊsߡ볹u(O}Zݚh~aͥ4-z`eX|ׂy0\u5P.\N翭 u-kPC>KQ2q]E>:oe/֍g|SōmJy6m媱V<|y567͵4od~{*|ÿ֘sRK[.\Sr}_;_Wi]t ._/ +-[@]6Vw+}xnjpōOgભy1jXC͵6?YE-[iMo޷\njV?Ooe)\9ri-Tn\$ K9]Rzˈ^$2 +g~+\>|o?o~e[7>\Rbݎm~>p.Ź4p_g4&6Ds+o{;@M:f ̫ja_},\BfrM>^`>kN)]Betiѿ]BfM赀.t+uX}uh_~ݨslpퟥ) .Mlڀ˶ja`w_> 첹e(/|K^![i~}j2*sVF2փoܵ!K*PD?zxaIuy]5kJ2zZ[B@?Ws|~m:=oCy,p8~COz=O6}ǫhn,kFI:f\G1_ c\YrI5[ Q?]X`}J2zeBzhХ@.|>`77_׍~|^sٞx.źR`{yX +Źmp^=g>9jǀC4u'ѾQߕ`_%k[ܧrCo>??/tM}Dw-zHrz1q]e>?y*~yOxkWmjy>mܮ+Ź5_%e֗W^o\DsWG?V֌nj2-j0K~?u5]JtI>6p|.g1n\7mʳ.QQfW#E6?ejk_e4?Q׌}en[ƕ`n}.׶b}"A[!RetڢKBWE@>?]_WVx.WY5s|qc}z]y6m%8O7˨_G=qOx"_W|ǫ=oz۾4?^K2-c3s)}.wuy5Pn|sr][7sWO)źy9gj,qP7G>qSWu]m޷h؏|S??ٲ3dW2_ 20;Fח\^r-5D^&~>kH*Մ3t e.Go_:?/sY7>دXW?\L{[ʳt[Weq.4p18?yC6;_7_k>P?|>d+P׃,0+G"_^>2Fп{z37~JϟsF[7yGRW ڀ sX)m(~ Mdkoz{.[s;8;k.zkPJ)D8qw!J$HRܝJZ^}3sf/s/O49f`~%˚ˀeeQ[}r>ƂR ~eп-3Іlro}r(Yrq9m ͈vkh8%$@{|qvg7}F=7ång6.%DT3gKF67pȰc ј1kL[h1[0+Ì~a>S>p1m͈v#@Ѓ;W|x3703-usm\t sJ!tʕb3uǙY@SʊVj5kؤeQc+xg(o,|pCo} =Csq2g<4kv.(цH$H5\|yrѸYu$6=" e/s!4cLd`ˌÿ#\6XPv Ym(͌ֈր3d7+:x3܀ EϦAA6TH6"QyU,j80b!hԴEt7lcy6Xf݆MviٱXÌ9fe²ejif4"-4m ?h\43 77g6y3NΉ6$xʱjPU= ];ppfEKmDѼ{gFˌ!3 <0arlשڇ4!rh} 4&gȟ)~AL߳uMs{tұ}[L\lh "QPb> hoVB ;`QKۼeWhO< lnYSea__cE@m!͈v-4:h6И@;| hq=[l&-ƈ 4xCltc .6AXK:x 7:uhGgm`0bFBvD"Q)* +g9;Y oБc&LF6/[VwAhV%3[ s eefVӖьhAcW90n@wC=Cn¸1#`Nz y>Wg=9DSZLƹev ̀Lؼi6{i4+쓙,&rnVҖQB X{dݻ0|3e{4a֞1z y9g۹mDg DGq87Pt@jqңw'M1{"4``4ivl,s.P8┶v4h8b|fr|W7ZM9fL2=c{Tz3th#< Ey E~Qzj4ms^9v”-\b=`>M&I`qه dD;& ̀f3>S w=QsOM;) Y/ µ m`k !C -gq1oY` 2Bs,sa}*Bh̖ |0\( 1D@C}3g.o@q1gunтyT܀6`0H:e #F4x҆HT:M5`Xn&l 5n/^rͺwo#6Clo@Cf2'pr:)D3 m 3Ϻ5unn`qclvRZ湪1~ "QR <-_zƙnQ1#1k¥+Vl~dO* /Y׬ 3L]3f,8MaJ{hЯ q< B <1$4x ZHg JiC$*Gu] H5`غmGj iK\u׆[؉˯:Yfp 82bGt1>s&Wѳ6"-7 /0:X0DWBYu騫Qnæ-ok߹;T5Fhي56mGy76C\1Sq9Q).]@;YuXsL͍-3e2KlqaД0<Bg) gDn9c|MorR jLD|=О}2!m~-44@Ef2Qs!eiB &ݠj`[7,lzÇyA:5b悦"Qg[p9JJ5hyn?z fkIGfegX\NqR 4:goلYgnpggXxlc*6S>}C66_y٘ç$6+LhN#sѸb:@l }Rϯe0yJXRx )<۱ Erk e B#gj< 7ƙB dsiq9g;xA mf򥋩TFԩ3+u:J;DeF!8m^tIױk~8VPh3@5:0~8stBxvgmD;y.nsw34XЖ6:Y$*;18iaYcpH3t58Հ6[6g rSsn|f6 _|y$ۈ=k<tZ-a,X:6Rt}_*"QQ({d79&ٌPes>}Ntv2yA r i, : +r Er"{|sN2>vP|׆A+(v5(հ9͹p<FNo3ϺT6JXX +XG:DJ18G.Q::۸ ;(3#j=zm"q9ΠbYGϘm3)mnJù36|lCu:x池GxY8t?^" +b(G.ltfhR ͹mѕ^m3^{`,@d|3ӹf"[BgL(C(|n3moÙ6r\XʌgeՃ3=18e2aIix6\934יT()t?/tʠg~e8y{9h- %9m ^3XtVlQt=:,2HTtγ4(] ѲFفsxl#fh;u<:^GɆ΁UA +DllwE82ps;T8(A0cA0[DoO:ǖB EBU1=WeHTTRp~79xN4nA )| ƂP]nlpA<~ \HTtpTQ7\gxCHxNy _xӹ"lMgg%P8D|k99ۈg6B +z,Hgϴ@g|EKtUA[wHT&T\8O*sRR&6LǂTp +1:]rU+t@gEBDyDlK (thGәF5L(ɕ ETPR_BcAͅ$:֪ycC̆_ "QI\RJ³ zцn<$::zlPP$*#*m89mX6XPo R١rXMgzn7P[wHTF$p.Ae0naNiQ[}:$߲Y2J;7H%"|cVN6tnӲY#3ـSpo :u +REs; +Ӕ0H`';ԕ:ZGA:t plӲiv u~eCbg%p.ie4H篜KD|háCmZ4mdV+PPbg%p.qemcAۉt^tW_wЖ ٺIY$*$ KAXgp$p>ϦLg|):eEgF0t6Ӆ\'$p>2J_#t+HS@g\FuYөW6PNj^Xg(%p>BʎΆ~J әXـHpec;cg 6D RsxfPƤf(fr:$ +S#CzUЩl x +6iEpdI!GPYM=:ә \FwW6an}LFD8IeCgOor;(nպ5f(];. +~`C$*X T٠ <[ǝ9v%*HT08YPwօ:C93M]Ȇ "QH|MDtB} )H(|lЬ "Q^K|_"y/Pp28Ё\v Olu +@#t:5tBV6x(p‘[kU}:((HT8y%Й 9ܼB CUiEpd]tAJ!3A$p΅Kg.񸳎]XN %pΉBtOgXFq*v(Ȼ(:vOFW"QJe3LeCqqgR̷zhb!Y$*0 sd:YW6]QOV#3A`$pΕ2ٯlPЉLOV :*3A$pΙΦ7h(ǝM mg 6FPN/ +`WQUJ!ιSʆ +.n;/_t>]Fncnl(2 +M*3+)hcg:M 6Ɔ}Ef"QIKlbg>`CYg +6d&(ιT|W0^CAȆә` 6n*JV3\s("8T.љ*&v=;CyﮝNnjgcd 6DB99Rوl +ڶUnѬq}}SL(ilE<9<_EWQ샂[ܲk(Y$ʱ>]$љ>{ŔӃ H[ NYnfsl O'tBSWSv@ +?BeHabgH/8U[v@GQ^90sd(X0tr?J$:L P ŭ|ɛ Eα`#;@NRNJDŐ9l(؈>b`ÉC|Z,y _vͣ($nlU<;BhQIJ 6eg8D3%GQ^mw:Т9?le$W=l*JBwt ڣB +[?HAUgQ` +|DU.+@#CD%p[s&<t3AQx(ԧ92LVf0LjߙgQJ*L7O:zΦq}kt>R9 IE$pc` 6* +|s2'S2*gQ~K*L@xcCtYӹT + vH)Z,3 YE &>Χ $lF#+0gDr&NYE"Iײtr&H 6AA]_Y0t|O$\2ǹll`t gQJ*L@ھe#mqm-Rδy( ;F$(y}\;(lgXv^`Cձs:xdN ]r!?6tvgmCx."b`N$c-,{0>B2u)m tςgQ.%p{%3wLA(ܧعiC3$:@Wƙ-;3:ؠU<jbj޸@Z)Bg;  E99LΦ76O3q(Vl8tFpy?g55A? k ͈fY8t(x|If,d*t2Ɍ`p > Ӑ[ӄh#|vY; B)3`Σ ߻;V6Pg|CSNg<_%`\&,3'~~d41|. +sVT$p.%Z`ACO3;r~ۂlx\@G#wd(~TH>E_ۧ0HhI|Y̳I\ +6*cܧy¹WY+ Ei9l<̓:v0MAC aW╗}a[Иgߋ b9x(Df +3<0\*gu٤ski@!gρ=m K\( +-nlP;P +.[ ( $7P5+\Ε:6(nc%BJ\0J `Éݡ T6͂+ tlx]kX 4ϸ''*I4gaee(Ǭ2sHV/] ?S߻I FD#&@hώ}΀gH\8J z ;7mFέ[4;܈+)06D6z\f|%fe2@|e]tJ}" +њ`5OTsa.#Hd +*\T|SQ VV&BAq3?kcx,:8҃ acgCPΆqW)wFka[`.̳6N- Ԙ; 3`k f-#D$WxW_s5ׂ*YkAVfB@|SvycQEacg +2lK@mZ6Stmym0#>>*bL10#f2f2erE`2rUTD_OTFH+D3/D|&?Ug 9׿EeOBR:;76;;CA8pE^Lg(m`LslCٷ{'FG<}l2;uf 3cAYfYa H믿nuP Ҁh墑Q>Y[I0mJKR`Éi(Sun ,0'*:Qtޥc;տV 6 `2#0Y*5jԨYf-Tm}>UT`F@'9 l#`sYT$p.,EYEѱ35qS +uLuLΣν{PYmt=g60zY'?wpN=u#<}hl|%Uf7YVXVT$׮]N[oR=+N@bB48MۏY,* LYHW_=n(EsvQugKgF:iMg1@|u1s)`fqؽlm0}E2)Ys5,ȍ7iҤiӦ@YkY&M7N+H+3}kpъЮ&醇gs3϶!t΅`0t*Xw6t^Ot=<*ulnڇ1'mZ2ٵ.ˊʊɀ-ZlJ+e˖-ZҊ E&@F>Cls&z61,t`=+:㮠PC6;Yʫ<<}6|yInCi&w_ufSSdvÌ8ˊʊɭ[ism~mAXkN6 + +ҊMF5@kg'(̳YTZ8x=TW6//t^t93&ڀ $5h<_x>[Jg{$5cEwO.f{9Mfm=0_V\nr6d;tQ'}{ thϕտ>_zq<;s< E's)lxԕ ;:?*u0hklթEن= +4 fLk''YSٖ 1.YF*+&wԹs.]vn_OtYqZAZ1v h0o*+}1fw ΢)vʆ;Gacig6uIu5YRZ?oSIV}yT}g.3d0,3G)w({ٳRoT%g=iB4 7`quEL7܈dl%`ëlBKg;ot}zuESmOw^}D $NyDߙ;7Jf^Ɍ3f3srWrO r>}_i+_}LFwEB3Ak>תY-ot΋̳YT8| +wبSt ti hmy-1۠ +w\DFB@i_!}ybL3 3C terd !OH#kN)}"jd! 0{WF* 6|#FFÇ PFGB3A+ |nҸazu!ި39gqOz /:JCλvw8#Яwn]:b\\,e%"y: |OLoEKszHdnڬ9g5 +ˊɣF3fرcǑƏW}>=ZZQ̈́@f>7j?j-H7 a4׽ga<цE sa*; ;G+H{w=xz,6<߷Wmp xfKI"Z1ZAtP**)sglKsfeܥ+pZ k3-CQXxy@ >=!PxnIr*AKa>t9鳑$JAYO]3ՙuim۵,pe@@)SN6mJӵ;M:uD`X"4z4hsh@Isvq*ө`6G\΅ġ-yt]g:c@nwo\GǏ5:ϐmtZ12k0Я>| +Y~'9ʥ[ܡc.])ܧo?3eeE婀3f̜9s֬YAs@꣙3gPVF+D#Ѓחܡ=- |NLAt,L<;tYT8b$:g:8V x޲i+\p4FFgʞBMA+Kyki$"xOLcf`Js4 fe֎y4s<]Ayxy͟?+yTFO"@+ [ +O +0ө8CmcA$p.Xδ+D{C4|ق ܧw?)kMsyƹ< E"s*a(֝Ct}w پxgB /x:JG3 +ҍ:]P;90G3 f:3Gޖ̣nj?,Ye0˫ +6lܸi͛m!g6m^V@h48ٳ՟GY<ӂk[mYT:8Hwzmyh'gLW D04xDGaOSV]8O=VN6ݵkC@V 4y|O +g_l~:wMVt*0ZAQÆF+d0ˈě@q8JsAd0Cg̊,{>}=_O~8 !4:he˖B1g3g_o6<jN3΢ғFg} gmX[gφY`G{a߹!Z1yf +MM 2M/`G34g<{fev2PG/g;jihMBā||cŝGu6Z6L m낺@otosQ!J\ʖP lm8!ݠBp n{;2t׭Z{N6='`W\u7evL\VX(x≃J\s5@0]|^?'ij_w<㋷4h!te@t;Xg6\32 + atpyTD!Z!n#۶(;"{13:8)@쀙 T"?SJOAѯՇO>F+D?V|}߽7uŝK<~w3={HwSu8VRtWPѓy^}0 V>IІolڸyw~,;sm۴ 6VvƂ:O,*) ˈtv.hmhLAq2xy#V}f>OÞO"(JJ}>UP4_di23gq56WZ2o#2cAق TF$+* >RAL|~x/:iAgqcF[nk sujR\tN($p.+Js<ڰ׹)ɠhi_c! 'h|; =Daړd~'{>G3Li12k0?ee2"_+D}1 B~E辇>&7IƎ{N0hkpeYYbgaH\fD8tg/O"GAY#9V~'{e\2cL\*z뭷Qhїs40 M6|~cog3n@y~yh $:7$p.; +ٌͶ 6<6\tP6Z5oڨ>a%JgY I\Fg'xv[m8xxf} }bŝ"3Tɓ&)N;R_+S⃬"w1-3XgvɬcfecÌ\f*+ +C-D#l?}9;y;?yD]:u8:۷Qd((* ˒6>cm@x>O}`:¼)NgLWVVZi*2@ɞ \vLG30(v_~Gcw4  4hJ*mycyh+ҹYXڀJGS,#:8)ytJ;g0ޣ"yyg+LYb2JG3hll_݂H=34  4U7{4cP^|hg͘6m@ܲ6Wt.* ˖btcA6\W )>[a> VVNZqڑ d;" +2: 2C3p0 QiD4u7^L3ц36'%veL"ڈgg=#<Oxle̛MA:_|x :E'sSNa̳ 2 ZD|qO;h FxliOx%2r2aX?4`F.3_h} 2_iJ#A|A쯛өh1y Fz,jyLgLCAE#sShÚgmd] >'܃nTxz +j+Z1yy'{=_r-&)Y2[l\T4&DA3Ò<}΋<6`Ӯ' +)w4ÔdߒdmIR>o*ݳe3ϋ̅҆OgtJ*9{6vXgQ$p. +7A<KkId{^I| (0L1A"yb/8d4Nfk=,=,Dh_E8E웊Oh[ gY:S UQuNX8eE()^>"gNEF+H"Y!`2˄e)lR4*#. h4zcP&mRLVPwg.;`l~l.cP(5]lUda̳6ڹmwSiҹ@.PP`CfI\snNF+Hc;ٯj.S&j-Ȭ-fC!JY7^ڀA*m:C6tlۦEӆxCA;{Eő+hxXh9Y#D+F+H?~że9Zl5ȿ< qqǐ:pC-4 mӓ`C8}'<ڼ}ZA5tDl>]0[;AQB;|x> 3G1;\Ȝ !D>YOdMܳOzG h:3b@x=T6Pcg?H (%p.TxT6h(H3#XgQ%p./O -}NFH@iLl_dhg t޸n +E3N7j`lthkb l(sQy9g8<@FFǠE_d>1w4^g9#OhZl cthS peq[\uSryvH7|>ɾ)y:MfP;O?ƿEϢ*@NR2֘?/~9f7'sKsϔmpm  t>w\3LعgNOqpY +E$p. +2+d]>km fH;1ɾehl$N4&g!U7A:?kug +rN A ZE3tw:$sT&Kzt*1ZS:(+,S:s&2tبyS/!߿ ukW/_6Ы(v&R82H\^(өҖӮlEDbAqW)3 ZE3r 3A]M:KYWa<9өSWS& d>̟5gkMl۰7Re;s nf&hNlu] "tыȑS]J'S YT2hǂo1D:ܱb;`eF\ 3 (bEŒ|+ϑ{۩3&_ꃹta晢 'x&:t~<$ uO A eg:]: E%p./>J'&s :2;sltp;v 9΢D=<!"ǟ#s/<3QWPCA7}:'3A΢YRsө3O+̥H6t;\{Y +by: +6*;4uu>ڳgQ"TA>_0K̑6mҙ;?p߶Og o&Xڊ'QrQJ,bŨ v t\>)'&dt;^W6LR(L&k iӉYdgQDg#?|Q}: L3٢l`zujbE%SFl0D+opRctk6 `c2;ut,(,%pE e!FgQ#J<39 +u;<:6x&t5n)Yt8 +3|EDr"?%)tơ3 )v~E8ך[tu66M'*΢L"t_ң?<:;l* +v晠ŭ3u>!`΢D EJa:5?b2i(mW^zbXKxa:"8RҢ3:*?`xAv`WQ 8$peTU3b:8O~m 6<3A](: $y;ަ5D((+efl Dg[p jlz|?aOtZgZ<ܳI~[D\C"({=0̱3`WQh&u3 feM'*΢,a> B.n |E[giӉ * P69;:lw:q:xE?ĝ`ήYT*H { +YκaOpTwSw˻u,9Y$9tCg7؀ƆOuϱ6utpY?YQrY$BtvbHN'6"έ讳~3p wrhHD9lLN(Q kt׹f!njӕ#\X.W8D鬃 :|a:צw6]YMV=*rOhHJ6LМؠ%n묬3?R.m9IhHlLt!N7t &vQte/EUDB.Q E"u:8(du>_nQY,L9],plfz%bqM:O4v}zng/:dx;AY0Y,f&co 6SƏ>_/vQ.sƳOL`Ύp:sw$$p\eΟx֙ѓ(7pQ:t*OR],p<T؀5AgO<~4p(Q/9a,`mRFP ],p| eIKΝC(]y uN!s* "PYguΏ\<6/E"JΉd9( ;ŗY$9:t};ܱEl^D)`뜑Q.|tY,EU$qn?&"JA[,s9N&*iI. x8DQek5A{QF',"JA94r9%*iEsfCg(T6kO(;"J"Jٓ9(IQcgHS6_4ݶ[Dɋ(ub/ r::~%ta>2"Q\I=N..\m_Dcֹf9j -]$:> => \x8D%Zgθ_D- /u.ΙM!2<.[(3Op}%k1@ϹW E (QsMGf̚ˆƠ HRZ# 粀gHR:Xgo,lW{LK1A:Å }Λ /?h23.*(ih&L|.@< EB6("!^D-Xkf!3[f f2SفG4G>9#Y$ +*uθ;-i[?Yu.`48#Dff2CcO֘:ƳY$ +*:Q;EZgI<65&r =tRLih$(}\نY$ ++nSQ(2n]뜟t.0!沥2~F2_fJfB[@9 Ϲ{Qg(,:gZD9.̙vYΙiF2e(~LP64>S  @[>< E%XgMZD7S?&Y.8FfCf03L_~JbP>ctssgH`YgAOl*J>9{4LqCffe2Bp|&,,EHD#A>t# υ`"QlQ:/ֹ|`yCT4GiF2eFnj`\,# (K:_whB"44hEs.&I,%*:;/6c;ֹXgq_`x/: ͔48C{fm ̖ˀe2| PjїwiB4T4F@1f6"Q;qᶖ|_u:?؈9shv D3d p +ee2"Ax{jA"4Zh8@|V ϼR8Y,%+sε{Q:w!n |s1ѬMl̖20YQK/LrW_j`4# <4:hcO n8xN6rw9"QRQ>ut LyD"YG;i=3ZO'0+X*W\yrTP߸a VFD+B+  3>9ͳY$JVVg|e`:Ӆ  ƃP07t.<12c0drŊVuW&ZQ\4xh4h3ot#g7z9,pR-3 qV!no&6C33i cȬ|Eee@kRJDo] J_EV <6pRn$9<I,(Yg"J:cn6Qp& +|L94|&3 P"WzJ7xO7V +VFD+}h9gb c<y8Di"ʇ3^7`&xMmWQUL4s mmAd6`F.+ HonYOƍ7"CFC#6݈㙣yS: E4ek_ZgqS_s 3;tΈo'ivl|-e2P&rjժW^C'D}Z55B]ҵ|(9݈9h88DJ;λum B3vv*q:&7Aqbf\619Df3 +Zj׮]Gֈڵkժ@VNZhEh9<@s9[l# HXg!nSÙ 6acg +fKGhn?M}0+.#M6kּy VJ+Q͛5PF -MAFnas^Gg(])(tȷv?zt#tLB +t>ڵuG&KͮiL2` Dnժu6mܦt#Z}ܺ5ZQ_Wx z-f9,p2(Muw5Aeq&89ظ ql*:w>غy.1t$3s':h<Ø++\=3Xf̊ˀe2mv+uuD/Gڵk@ VVZ!Z 4kxC狰a690,p2(Ԧ)l<yσo߲љ @ mg]و9m4CdNGq hv 4_[2-3rYeeEv@;uܹs.]zR;uT+J@&|]*>c6yFGgHI{a_y6uqkj&vl$ѹt|h]@uaLsU(Pdˌ\F,ݺuޣGJ+aݺ҄h&4 4n:Ϙnh<~ک:zF:FY,e?E: !n陠6Ѩ}_~>ӧw޽݁ѝ hp@#kTx3  84'zĿgHIgοyЁGN3A?؀Uu9vv:;\LzmAf3i[U4Ȭ,3rwb2x4h'x`5P! VZN5 Pـg9ҳ ~'%/YRg(UYg~M mۼ^ BS쬇Ny\d~.駠"/++iLsjCae0}C :lpVaÆ28= M 4oZVMϐnhťԅs#$;0|BBU8G⌺4ܲYf2@e`#G5z1,bQFH(=M@>7kڸQ`Wt ]Fv+PsCmB{1>gH?b +5+4i8a#&sveڭ;LX(Ǎ?~„ Q&M_LT?nz40z8 K#7ksZ5|347.A6om|$4H3(k0Ы(;7mp-8be xN`I𯋘%}Q)j + 2g@ c'c +ɓ&M>;'a>o U +ُ6g( Xg7#66Lv + 8OBAs1|T ]yFzlֶ}&3Zf ̊˄e2y9sΝ;4T͙3{6z0z* 4kNڣ}nAJ(*Ft4_\&MiةK={A2,q9(WPV@^de˖ Z/-[t% njf>N(i|i6rt3g(:_xll\z; T6t?u;^&E<_"ᠹu8 L4wѫO!2+l|+W\jjOԊHh4h3׬6yh$O(IgHپ& R\E ̀3M:cAxs->Iͺ;f5<f0} 4d(y@03*\AYy͚Zv:zzڻki`4"1SÇQ #$,5̀jg* Y:47aҔ̋/}pY{YLVf#o۶}bg}mhєS^2Y3OֳLnH 3aUY1 igB]l >w_Ώ,W2ѯؙ7ԗ,>gw:QsZm?ۂH:t[\gI:4O:mƬ91k17I;wڵ{'|r_K]vElh4'h +sgϢ,HghӪtelss_lg @!ޚ5ņ:cCjgvEyM휧sZ@UmFce-fc`!fvHͿUs[jtsy Ud1/`+ݷocUwQfCkA}l hE T|vC'7telC=Rm(q 9PXblE9~䠚v(2uj;U\V v{hҳ}?[I:_̾uh6UsMN⩹fj>C9s/@2GWSdLb6^f+̓zn>s?a,3 @a  е-?G6vV3u8y uhgnx~ւ+:BZ3}DٻmQs?gc5Sh;o%Kqf֑Y^Vf'=zرǏNWtV&CCK~~t)>Ks{tԱ]V , FvHd5A=!w{y v>w/ +ꑍSy9hz목eA=S}'vl=A-e@l$J +f3i:c6nȬL^Vf%uqcFn6TxnVkvN:s%ޚUlص(#2Psm[5Wݼ,X-G{b\:Z(:쉙fgD*5J[j態i 6Kf~r,$3IX.\xg.z[t hehQ;m 3/ N<ó6\;;Z(Q98trlvFNTg}s%[nUV֊-]Qb9gD*Ԝ5>C,M3fKfVYYZ~N /Hd iq4)C437|ҳ繳gNܾm+Sm )7vH\"Ul36fQp>eös];wl׺,XWu^x݆gn~mm[ڻ>,13BкRsM_Y:4o=6's$f +beQK/3K.Ѥh69IЖ,ˍrvnyip\=Or ZeeQ[&_MДϳϜ>3/yr˖,n3mjC?fOvv\l@M3Ξ udhc;=%^yg/h1(ZK"ffh3[}3AOپUռiVu$feֲ8TnxZ) MZ Zc7䆬 r!y4?u).7>tgOvߘ6ٌ;!gHb#T;ˢ lbW,3OW݃W;U==YgZJ!˾uCfv.|)Kf hlVU4:C&2k1+/I3WEdh%hN:>?Ygׯ3y Ym Yvu޿(k;Cxņ}Ȇ?;)שW݃Wߙvv!gNT^TuqqufYpxWBq٪^:=gWngS׆6u?6V,blYsMլ6D֙FKjޥl +^!fb^6RR]uMK3$hк0mzz +dy +so7Pv(L;O8{wn۬lg=P{zUŏoP ͎VF̶ilFqEQj>$j303YⲶ2xE`?K~VYΟ#=K7=AeA5(r߹*0vHXīոsbg; Ump3sm[܆YWvC&@KC|ԅֲ'f4}(d59Vj6a3FŬ +?Fbh4h砞_| ϙnC jCm&Cv6urD(6 gCt- +kg>yzMWl>3N6SfK|9-Mh4GhQ49Z,/ި,^bug4׼ ?5*TgX2%fe?FiZm/>Y+<l>gիe fYlP;C$.@]#U7O.p+G\{܆s{Ԯy]9?K\-̍&[˷ze;kЬf-Z _Ijޫ|ZYUgYbfKF_yI] ͂냶yr68<ԅ휛wod;˸(VQrX3;sQ#u\~VVEgyf"fmur܈3x+3Yz3ZA)%Dжu|6z~^AK<˃.oEܵsG}o{jqJEAS;C6Dgr%zQ0;IUxs1jsWܐv$hIbhVtU4YZ t#Z&/sb֑Yzf13&4KGZfv_ &4{f#zHZ ϖz5%ӷ;whۊw; vv[l@ǀy'76ΘNt(XWϢg^@v߸G ZGhVtH:=!osYFK,M +ͺ9L(5ll(,C+Ak?K|Y +2\(>q-cgljfq)xӳj7}n~75ԂVfEY$͚fD _NV-=1ۘ m掝:wFFq;Ԭg F1flj7M%Y6Іogލ§ o3z98O :C\o(fYP:QWbܚr1{ƴ)2Gth߶MhA)Cת)&Kw HVY2y}3ڽG>UQh5?X#/TYA3h 1 g;ݽ聺ɒEAS;SlMt +r;8;|xu% zf=3jİ!#UʹДˎ]=oU2k쉹y )3PM3fψR|89ϰB2X9=AYwJmHx~KyޙoۯW@wޑSժ})62:C\ ڹ;gu|x6Zx9u|޵Kgs[TfCSn؀M9IWo Zf/1nӶ=}8B3Re0gfBD:gzkeӏޒ%hCśQPvr l9I %)=|x}ﻕ˗,羽ϔ;ݲ3th &]%+7nByYeF]̺СY=Zͧ"^X^ ff+帎g=W(x;niǏ1d`_w v6,ТvmYҭI +Im;Ѳt 6,u gUO)>#3C~'={{vUAɽxSy3ʠ<Ѯus,mS YVc3NaA6~ Ezv>{{gXϨ?gƔcedC- +_lF5ҏΐ3WMYx˄giW\ЃKyİ,Фhvt<4i:]V&-k/KAyQfСyÏHm Jl 8RfJ$qmг?v'֭~d󸳌lkg}΢3 S(;eA5³mxzA3g~7f4h-h64)WO4YZ#oug)EZ3G͘>,M3G׬8?UD5G(3Gk99MddfCItԩE]ulb#pxhٮ Ba;[Ǘgmzޤ&7ݐyqcY#eIlI2kY{y$ˌSIf:Äf3* jg!h+>=9P{~>u'hehR4;zljA~MI˞L>C 2-؄捛8Ps $<b9Vq'9Pԙ ln>nzw摍kgv*W ' @P +Xy@w|==?ϝ=zG1|041؇$'>|ĈDgϙ'mYv~M[0q/MN~YWѡf9翨z}9a>nFEA];w܁@jX/؈e3N9P2ij_XJX;8<̳WFϻvlۺyg ϝ =f4i @Yye,f.3If:Cf٦W渡9ڻh?{zs9оSβG6xQk@xņ 9PBD9,g 5u>'qg(p2tv[Qkqҏΐ3%EvWېȡ>/j?S~^ЃK籡IMeIO&M ]#)OFq,^e\gpӬBSUs|3 9&yؑCy7ϫ}d% zghR8$MIIWgI˾b1?5fM!Y +v*Fz3_=z:(W(eOAzظ^γvy.bC!f`8]Gg#O&<83On8&^noe?S~^j +FlhR,iA\e%f3+3K!YOCW%УzCρm;u*;ݽ}F".6vbm+E*k? ]t(Ab9PmNƯ_|j7(>K~޴,5I,fI/$M/`S kFR^2i6nޢͼwUh9>\oUmg=F6 uW._+6zq58ke!gJ9CV fnC yN8m[lh +q4I4ei~.+xly*3;uƱzF2vO}Ź8ۈݓkEِEAU; >c#jM+ 9Pısg]=k=Szɍ> gϻtfA+C$iAV^)V&-%2V|4<+SR59|s\sj.Q3W(vygz/G6ڙ@th٬>c;<=ҋnp|>{`Pl$E?.&Or2eJ6l*acf^TMjjSQ\JrTcjdëmtvae!gJ_t{n,=s󱠠Т͛Hdizz;yME尘Oh j9 + +9v3`)BY6ddC@:)[7bCmEKeUt(qs(<[7Y y3!AE; +]')o!Z&/{b1̺ϐsɉ[58癈3/ +>'ܷ{l֚'JEg';>gn(?_Y -fG"Kw5]).G^։f 0gSe0sA;9Nlص3a5waD{ @rkкugҸz~sAK&C,=ia7MWYS\>xf%怙`0s9jvlmtvnF6 S;["sƆY}zND1w* 9P*DWf]ۈs~AkC;J!͒&,C).K^&/Kb3ޱXs©9a<;vt\l q:>bCv&nҎΐ3Ccg_Ͽ?+AsVfEY0||8k"f/23Z1sw#~΁bCag&y.3 @)q%B_v^ll +>?{VfEIdit 'Oa-+/sb#6s 4Us>79qo +kg?jgW<Ȭ Jtn<8Ng6qmt(- ϱzsϤg.Yh4Y9ePoa)Ye +Fm3{ٯ'fq:.P;ņlE36԰&hN'r9uWm=톪7?kA bhV8$MfOKϰʬee-fo,uH5OοYM[QvntMe!gJ|³mh=A :@/| M8Z$͚Ν |Vx˗^̑{fF&4 5`Ӎ=a;[#^ņ8zhߓް'E&N7r4 9&K~VZl7Тhq4IZ4 eeѲZ*2k3uFHN|5a+6^ag&FytEG۝DgJX϶-=`|~m MVfI#xM2{fx3+ osD ;[k2NDnX9rfA{EYҢX=oEF:2ǚ9P5' oMl %&};:{Dg2 &(3 sji_E·Utus#nOIGgD'Z|Ң]ut%!gz5*Cqsh@Wr i-稣C s2:C$r\{† 9ʅÖss-QetHn c`FgP9ɢ3 (/:G߈ێ7rt"EgsKKtn‹e!g@89x#nkլL3 (ߔLtܡMttRrs.:OUrw +/F3 (#n r{J#:oEgPss7DptnҨ^Et埸9΍ΐ3':Upt^\/%!g@ઢY9;6:_[rT"LtJ :C@<܋7:} 9*BtE~t^ZPtIDgP!(rtgEi*:( 9*=bGK):CA2GmtGʼnν\3 `tn?- 9*?:Ϙ2atdtYGptK-:CB]~)GGj!g@!::):: FY*: GK):C +C~"F!g@!;?nTt~XE\znRΐ3Pѹ_ttYr81:-dtEGgP(|txΏPt3cΐ3"srhyw(:=!g@E"ntFAe!g@OQ2:C +EDts|{vFDStSҊΐ3bquyؑC8:wl~sJ':CE!{5ѹE禥!g@y's^Ag?+:C +Fq֍&:O?zEDDtBE7PtnG[(:_J&:QM FbFΉ.g+Η^|Y_3%Wr5b~UWz(:pt.=9e9hg+WbC9:_3y̩ѹn(:B*99xD_s9C2J !97ptַz={ҎgODy GvW7P2ѹr弁|H95vX5{^p)St[,EEbZ 9hXo|9DBr6YDoD|_ϟ=Ё}^ի}wu+:Gܯѹr^hG9k@w/i:#^Θ2a{u|o5utCɏèUӪdk9Y<.B/^~u$Iaٲ3 Hr5%Aw~UgM4vPիD*:gTV9VE+kݣۓ +i˯;hאY: r{ .|QV*:ק\UuOÀ簜nز|9g@7fO$oD9HWեc͚ۖ{~pw˹q{r~ras,7yÏ ?nVr5}i:>t?5"/ GCr~^x_?72V%:+;=CH9{w6]p7;D6+\w&r4}΂+V}bYl5 wUkּ5Ԓވވ]"Q^9 k;9gfW9792ryǞؼ|SDf_:LvVzYY+Cu3|pb7-Fλ:v9sft^CEgmg(Jg5{ l:;MWL"4M#J˹UNz2bi,Yc땜ij +5==CDYYyr6/ }qq^i:>5##N6{Y~6}+޿-נll *_'9r~5ֻ%%$˙%[nO"9m@rnשk~G8mq%gE5dE{ Zk& +_#RYZ<,>k=׈^%xr[nrYAc#c&N5C+}YVUl{ k|XFr9WWrn1ߧXe\ȉOq!G,3GkG@kJY3oB1rIt7kı#Fm{bkDM7ߖQ5\QV(|2K'+\:sqκPvVz&?+C+YRdffq<9?7/zN׈wC)OIPzAtq R:=)K_5lxv=YJpHdfVv3M(^Z|"h#zf.J)7[L**:cgZH~;3YݷߌjEP~4bHnUQ7z-j\9JrT2HBY>Պ o^n|ѳ}!LZ-|yLbLj~/_zs>Rkn5XT:=(sTcdU;qyts~ϜK/_ߥLEТO vb-?Lj6nx鳧x. gs'ntf9|s`ҹrO";tc&L9wR56l3O; l^-g4+Z $N>b1fQW^~sO9uy3,qO: g`͸=~L:|t::Kq|+IxV~&Aњ aĞ"-wE͗^HO;rpߓ;EY55cVU|9듏H)7R :Qk{7psv|/rx=& ww @"]v)-dfR+_~|ؽckWi %g=\k̊`PrAg\+ .8:oز}מϝH/Yd7bDE,EVf/:ef23K/\Tn>s8}Oھe]҅fMܺyS#J=qQq,[z\CVM̽؉rt^i{Rv~ FW_#Cu 7 Q2yW)3_z]x|ı#ݽc ?a!8k$u?_#F1|wY:kEД}ט2+VYf^Sgz"}R4KZkH$<;ƮL^Vgyiv{98oz-^0wIF/g3lfB.5Wu,ƠaM&Ï>v>v3+lx>,/_z̤s<ԙ'ڱ+?xS'&Gٛ+w_ԥ5$:O=у˹vCv>J}‹KK8@κxygYO?*n޽sۖW=̕S&9lP?5JWr]A)5^5j>tp'_"n5&=bȀ=y9͊'hڼus)e#}{ܵcy5q<}ı Чgx9G9.v݅ *ujIgCF?i9bӖm;Xd?;Ά>yI4m8 iɓ'HX]b +3N?fA<ѩ}7iXO6ėsgbkκרU, rt7h1&OSv^֭ߠ}cHҬi$$*JS'X$G!1RjIy'7?t +F 2o/^l>>nپKHq tIg=!K3 V|t 獤;v?>t8"分u|,f +ͻvl߶u =fyygHp6?۶j~߽ SZ](AU:Gk%uޫ!G8EdW~a$'ˎ& q9ai۷oxy7ef2V3e&O_]:uhӲL#C74 x':ۥkAѹ~&lӡS :b4yy ?Њ6nڼc]vY^HXvwܹLf޴ RcW=eKL7zPݤոO yP}F YrlF;|}[عk>'O9{ނEKDϏylAoٺu۶i.H<|Iv˛6qj~=ĸK̭T2VV92 +%(] Ϊ׸[+\s .6v0yYs/\tU<M޸ifb5$,-l. 1?fV.^8\jHpnߦ%uU嬆5ny࣫sTPܴY6=;;aҔ3g)=/g??J&C{$iҴb#$4ZV?uk˗̛3kƴQÇ +YIs`E5̒ sѡSbƌ8y%K| zcku$֒`ˏ|LyɢI3O:bԘqgJϳEKzh+ 9g y=DV&-/"3ϛ3{֌SL,=b$3 +H2KyibGfգ{.涭[6wsCn54s謋 5kSM=бnYДу<j1 D^$1R@2yܓ5sf4mX*́[b9א%Ay`C ZvUkЈ܌ܦN}ۯiD idևL^f1w!3?С}6f;3LP )gװ6 Ζuw:sznъsEl=={} ibݻEm[jٜ̱n5rM7\F5tpZʹrz 3묊 U;{vVF{sznz?VۈФhrt]vcGHA1/,/sNes2sԫKܜ,\VC9kxYU9=jgs ܬy 4}vdi&-v#Yܮs32sƍrAxNø7pqo5 +-8_ԵgJӹڠ,z[s&MEdVmQt RP苔LNnۦM֭Z1)4ק\wQlɪ,.5Q jrs :Kl*eHx&=רYv{ ͚[$KbQ+@`Z,֒ܢyf$Fl{֮%j]JFzJ?́rCY?N-ޞY\"{'M3C#*1C.,f63fn33*W֛ 7K jDGgoM0d~qӯnsz&9Z;ϵX 5"I74L֘FVn@b%fΩ9j&f4,7sW"8GFgSl|oj4NY;,h24+I~$F^ d$zd{꒗I̹9IͪҸƠՈ EPvI][nsFs5f-v4Q.ZSO^l2Zm2k,fmF*6xCj1и9$g׈*6RmPxn\3 ͊A&K  .\㮻d/ӌɕЅrUa;K!3$h14)iC H*|ͪV-b|R4~j`s̵ogٍc=+?Ф4{Zm1ZX9+*%f9fSinf?8Okz3 ͊BfMg594me222F9Pj#89E9g4M&Ig*hi"f2 +!5ǸY~\$9;:==)?Фhr4[IIWh,b&3sh6j69hrDX;KxL~̂fCYdi$7f5h_ޤ23RfwpxnÔIhp+$7f7ʤeN"fef.4X6slusj`lVW)>stream +SHJ,)^VbYrs>v׳g28%1qJe6suQBn:<[z~VfCE?4;Lb,fxn.v³gg68Z[ژOk"9ֲ̾\n.JRnX~fAYҞ{9e_̖\R#zV~ւfCE OoF"搙j6Fœsvxz-V֖.$+ageֲ6sK;-;zY-EI{7ek|Z̖m5GTvs;l,CkGK[|i)]cل栚KͶYZZ+4#,)-=1G$a(=} !i,fUsI9-?[ֆ5$'a__eg[϶}GĬTsɺ9`琞}G[Xy Y9J%濋 F!?=g[A3.:<~6(:P*rK!=I@y&%氝-=[+7%Cۑ_ns϶ 4/B_\js1=b4KQzt!, (ƚϑ唂%Us<=Pd9_?C +K|/ 3, 8²5s! cEV3WPpe $ GZ…Cek@YqMut7,kԿj6ډ4:kir5ï&-)OZj*Yܜtz#JvZ\EzNNFfՔ6ykN̩R)+-757-#3?]MOKNIT5 +]LG2Rs2j՜TjY)}\nUQU>>afvՔ^^5-*}JUSssrgffdWJͭY%%nZNfUqٙ)iUT~g\tWfeeoMClԬ,zПSVI͢ǀǧeIɒk^deG/I_H&#[`K*efӗZ5'~Z5;> +=ZiUfCŗҿ[FJ9Y9i{R32!g_EK^ӒoIiZ~}S5 ӻ R\)35Jz[R*76)7תUk |K4e:)Rn_5өJn[RHfNCoД6ݮ&1RF^FuSYYU;}Usc_D -O*9VTGN/fdbvnjft4_ ;=5#+}\EVIk]̨~cg.?pE?xzl'Px•Raͺw8[n7V. г_w-:[ww{DuV~ހni׿{a@>"4r-FWJ~)u}HnV-|&WS;R*80+صC__)h̫r!L`n0ymHހaWU]wy8q{wKTZ~,?=-eTM;{_ސC;|p44lTUlg<٠ğ >PVv/:yST/]|m| +S_/ި'"r?dDtD5 )pOI7uQ +OGz6*<7|sS9-5~.*/4/Z{`WznRO]7W+MО>mF$ÿKNV553+#3cJz87|^m5ENJ&?eK[%E>o?7wR2fӓFkio;w(/ *_.](?~G$K$_\@W0$_cU\\@qpZ +qe(M@(>w/@  +Pq: +/q\/h@;L~ߘ>$_dw.%_b@%(._sq@ E\-_U@q2 K ׯ(,V>_P\Pq/(a\HP!p(E\xPnq( \Pp(k\Ppp?Y"I@$ul q +@:I pH>\שO0np('Qp(tq(Tp@qpjqvuh\":>¸:5õ!uR +ת (2^KĸH@u0*c/pmPqvkr (;\\g[\$7,1%1(H&\W@ZK pZk?uV$] dH\'S@RZ]1) q09PNp-3Pk2uO\ .&ZrTp3׶% Xv(\J@ŵ:Q*4, xQ |ڈƵ@p v:-@$uNBZ E2lEƵ8:@1qO<WkT\\'A(\":@ڦJN@~P6+@EuR\?" PqtqmYrekO\<(#\:@ZZױZיZI@.q`$u61@R:@ɇk$$ Lnp3@r:@"Ɂ k=$#$. иk4@:@ Ɂk[$"3$ ph46@b:@Z hɇks$ +s$ (e7{\'2Hb\+1$1q p Ik8uku +rk8urk8uk)+\KLqej(#\.(V;@:v@ĵJׁ 3PN[Pqxurk"s\k;nښ$6M4MԨH0P1BUfQ@fyH@ĊQijbvkt}ι}>?ZZg?G-K'=,EH=Q,EH=',IG>+eI>!g+eI>!g+I?+%Jg?a*%Jg?a*J?G*J?+=O,W p_y +`{ISK~tJQTm'{2pӀwĕ ;FF¢7^ҋl #J/-˒~#XƤK?(dN0C{޺Ho3~_01횰0mWJ?"]z&LRuOsޓK0S~jp\a{V,HJ=U.|QVqRfM9J?C ̭oHݤǒ^W,}pҏ#z^H }~ +/ ^9/}O~p_'ݤWJ_Za'7H/'83CJ?U.JISH?m8Åq3 +gķ"~pt"݇/Y8+ ,CJ?U%JO@Fy,WzO`ң~S~TFz2n ;H?4.JGV_zJfg҃7H?(N)p~&H?n+=7pQp (F@ @~tJQh')K?%=L,Z!p_y +`OHT HOUK~IV~CJV˒N}KW |KOXK{HY{cIYNz#JZ3yJO[sxJO[sxK\xSH\NwI]3vIO^suIO^suJ_uSK_Nt08H`3s0,Ibr,0mHJbӖNq80aKOdSoD0U8 ` p.s\2I'7Ifm$%=LI:Nz@t`08G `i pcL4 HG5JOj.+=tNp! pYK4Kk+.=tBL@zd8Sxp 0 `S9Jg3d7fHng'SK:$=t*LIzv8/TpFґ 01 #`zH1'8scIOp"B:&)=tLUzK'1T8tLUzK'1G9t LXzK0G9t L[zHJg09tL[zHJg0:tL^zI0:tAzH/g:tAzH/L:tDzHG/L:tDzHG/|';SK.|';SK.|';SK.;J.;J.;J.ܤ;I'.ܤ;I'.ܤ;I'. G<I- G<I- G<I-<cI+'>cI+">H+">H+R>K'+R>K'+G?K*G?K*?CJg*?CJg*@I*@I*g@H)g@H)B@HG)r'AJ(A{I(A{I(ҥA~@*TG:;C;K'nҩ xpp[`p+`ptRpptFppt@p_:pQ:#YzNA@8 ,Z:8Pf!8yQz=\p1Vҋt%AyJՆK̓tՆsK`=#' . _O0J`tQ[IAn pfdw.#tQ/'XҭJK $}G,B6(]8 ]v0[[8t`75p:ܤh-H@F0I&/} aR„o^ /K t;az,pFI߰I&#}(T} +t_ܥPଥ+ g-}{.Z8_{twJ`2%)I7K~'c8;t,oC`m=LXiKww0fCFf"]nHt| YIWN*}sn9N^f(]t8Sp + tҷ0gq/`ҥ#J\{ǒK%}g>E"~8=,Hq` +Xtw8o%`q5IJJ! }˕CW-],Zq/Xt+_P**}hSqt7Gwe6 I/ݤo=J){SHW%n%}nK,}nK,}\)]AR0q ptg:ĕҷ ҵ+o   [I'HO\#n+ݟ(}GAB#};AB#};ME&ݢH w.R7#ݥw@tJu +tB&,ݨ.ҍjp/RhtZWW-Wz+ݫ+U˕yHWJo;B0j{pvD=8tZL`-Nz)ݱ%X˒mCJweI6kւ5kA[ px馵}8tZ>El-Bz"]!G.[dcIK0wҕk pD5s8t嚹WuYzo+ݺ,G.^XKJo,)%}4Ji(QGF @7>%4Jh(QGF @>%4Jht(QGF @n%}4Jht(QGF @>%4Jh(QGF @7>%}4Jht(QGF @7>%}4Jht(QGF @n%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Ji(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4Jh(QGF @>%}4JܾQ*ݩNji(QGF @>%}4JhkT*:Q%4Jh((J뮓%i(QG}R X%bi(sFT,AF @%}4JQ*r:Q,F @6J`!^'5J(sFTޑF 0{kJ%Nj3Q؍RI`N(J9YT*uR7J`"uR`(&-(JJQztHw;ҋm%fxptkNzmN5 <^$.J7;H/#fK^<J7H/!!`)(ҋ +0w\t;2MZz b 0mVI7sm.?(&&]yf6y 8tKo-Kz+ݫH Iw&&}˕C]*fJJvgyO| 3 p%̀Ӻ}$k;Dwܺ(NPu4K(u4K7z, +D!Me&vE>{>pI[n3It1n__m$K/pnJkl}WkWMI^',:N?{KW٭,Z6ؕo^8e'Yzɀqۓ^Qo]He{L{\ab]\_u+"b]d us]H\Gn]dWYz#l7vBxme՟ƾL }Qv9Wg؅!l;.\N,d Z'w`[^cBpDe(ۗd2b]al`[鵛[Zf(ۗd +'rv1vl`ڊw.ٺh0[g:d6'p`ۉK7ɴ0[E5If ۟aGؘ`l=|mk_NFLR\7폰 +12 J6fcSIvec0V"lHk^-nW4~ah[av1ʆ$ c(Uɫ"rlȯ157։6ِeQv!vbc0îUm8} 񵊮^x}ih0kYeId dr 6c؞[ a[M`-k\yLlf;QIKAY˱q 2Z\`kH1V/>o_mf-ˆFY+$k# ?12lk aaE _F7TxvyiC4el=] +LL]a{ǰ`Ck_-jF⛪oBX5&Zf;QIU} }1o`WˮRR<+[C8kaЇnRmuumdr fnUrga-Cؘ`^5[Wh˗D[ِeld#*.dr fV3}j k66ml`5j|eW Gwn?W뷆DkqVl̲u$g6@)Xz7qa!U l u|R뻾뻾{ C,WZiO{?,~|br|Fg5̆,Ne-Y;l8#kY;orO]:cpaUǰIDZ X篚_%jz=ӟg<|OT?}T./\6*J,Q6e$dY{ 9ջ9vXzǀm7fzpiJU5jn=Yz⹗Oi5J0+Yj,Q6&cۙuA7ds8Лaq׶ ۜ2l;.$X U㫥W>y{TwO(_VY eXv1H q ֕W+.V i5j~@M?/x _/~Z.LkyVҬY˲2[&*Vf .vkq VGoeغInG8l`5j|%/}K_r|%/VYJչFN#Y V-fV9W96Vn11;x^/vId`-*WM]5^ٟ}esϏ˯xEʹg5jEم$k#:f [Kc]=U52lJcXm8aG!BWI]5^Wկ)~a׮~Z.U5j8+iVGle$k#*J\Ձl;{1=v KNVM{}cV{dؐ_5Jz׾u{_ʥl5^5٘e-VIf6m챏y,@:ʱs]11Ywΰ?uUrk +M{P$KY6m'X WWI]o|7-oy[_>(7FZͳfu6Wl!j#:~f9 d-Ǿb ]ǴJHϰjϒ*YOVc?ڊ29$&UҫdWmo;w6 V?Wj@+qVl̲eclVA[l'd;VwfK',2lWR%WcXkO'ֳUCX\z׻ŃoOrﮩYJl!j,#Y;%kAyZX,#1VǮǴJHopU%{V_ga+CXm-kzzo>X|Y[ g%lVE*LVeAVkcS:y!98UB2V| p:kU(9aI?xv# aulK~*UC?|X-r\k<+iVlȲM$+d gdO{jk ٥o=ح..cZ%).Uݟ%k a*K8#VZdM7Xɯ2{Us'?◚O7?OO|Zͳf5eclVAgOrWڿ}FZɳf5̆,[GYM.kAY'? 9=:;Jcp2ɰr9Æ%7+J*~|VdEr+VZdMkVk^5~W/Xr|Zͳfe6+YeCljlA/V,cZ%<þ}Ȱ8lU%4ll/~^am-%:Z~*U~K__RFT#YIfC($Yim$^6:bY9?֎V+/cb :3_u}:qxO_aIoEػ߷`c} _5Jz/QhK 5j4a6 Q֒6AV~66=9Xx}ḻ 9oo.vƱ*V) [Z%ڑp6VɟvVǰ$կى2`c*WK/?Oi%J0kY֢lL: #:׾?W {&}#wu.11r _a\gK_%[|1U׽C6 3ؐ`CUë&ZǿW\yV⬄Y~eC IVe ŷox0 9޻c㯕qV)a}x?*٪_2+[|2La{?~`_5Uh˵˅rZͳf%Z(dC\;Y֣W|_ՎZǮjW0M?KGïC|a}lECG!l'j _5jv???g?_\([,Rs5XE;9Û8spLq\bwϰoej 5*YdQrj?<a_/!lHWͮ[oiBf5JlQ6$Yme$kd->fzV,X땏~\cûc1s8&8a VԿh2lUU4~σ0c_GXek3XK`Pl̯!jrɟW}TDҬf?g([%8nYӿɏ#@[أo<!ob R$ÆW\WV#1öj +Mԧ?3FXek-rH`T_%J|j?S-j aVluՑՉGtk,9V,W96=jqluȿrs8 Sw 2l}_3U_,6aI~"6 6L`u*Wɯ^-O.>WZ i6fٿsdm$/6O֣bYȆk}r=ӱ}K_*cl[&m ֛ad um +Ur8 '?z8F2~W-Zpo^O!j0kY֢Ne$k#d66}R+> r=+囷Z3~1w -Įΰaz)Þx)a*þ_u +"l5 _C|*QWQ?[iVe-ơ$YZjOk@O}nW/zO?gD)j[ 37.M# {Nmu!~ UWQkүX$NR!WˮTOz}f-6Q6&0mٗKY=!!\Ͽ%ZNX;_gb ABSտj ~Ugʭ +T(=% qwwwwwwb@ =A\ +bR[o9粟OHrY㟛myy1ƚky  SI3Fz1^W)FL1@̈́e2L&dd(ɐ!rlЀ~{vJ[;J.Ǥ +:hRv˰K" euԆ {Gl۾GLY0zS-۞3|We*`>K,۬!8\9lȠ}{SߦVSmǸGrƂN1rc\5aaJ F0a[Ff="r` +`\,Q-A̰LL2C2X2 2d|` cG 2?cm֤ctX)g;F f׏aͣ`EIbGIcvܵgF6a`c_/]$2fe2ʄdؿw2dԐ)`i96y1Fq%b%N+ŎUrrw9Kl90t2 ư ++Y%"J[ڰ<ALY0%Dѷ4f`BredܓY:CsǶ-PQ:y1T!V-?XUtL^t  +:!3bB{$ΰ۲3K2t|pa;)IzĄSS%zyF0e0e d#d َ[y!1c3O4a1JVsOjRTy٥;XPЉU"#bsIa5VX]FbT<|I0.\14]~-21̈́e2 X)Z>y2Kd1gϜlpXY6J~*Ņ?`,(D*b0)"ʰ2指JW%QI6 lN$)H:& )RLF"hF"eLXF(c!]jKҋԑd Cv% +2+ϝ8vQTiʱ/G` +@6b&;^9#XaoF0$I~,M`*E +0_B/˭R0iF,,ؒ:L}{wq sΧzL;ֺe3Ti1Lx 9fČ +1ZK " sGɊ%Jrla0a`ƀY|~G}{geed*]%cqT2,߫.VqOr̨Ck +%Nn9FGz"B +]K5b]\50LVTnltcc~Yv,feD2`48YrՏ`i9]]rE (VRˏvGozULs1J&säüFaaRۯ$UhGH&eGџkp, Ē >ǸC>-?1̎QɯR%UR913σct)I Fi1S?,j; sK1ȱLV8$0a 3#c|1Qτe2K2d 2.uCplpL13MHfǨTyOjL\coHPP Wq%Fi2&7oÜ+檑;Zb؎:S2WamaB0ᗥ_PIF g1۳k6(VF%U6jp/1Q%ǒ1yXhrUFQ7<# ]IKbKf.9gKrϧ% sF92F0_YK43dd2DK*~Kͱ 8Vvl]R1t2c2(rX +xF1 +T{Gf0z\c#0Tg&feh48,cW!] C/,ʱGgb5ڎMIDt8àWb!ƕIڈQR56%ac'K&Q"L1L$!%ᗁ)B3e֓%hr.ǎPX;6u򄱔*{Sl㿽T1,Asi$I.W˰Y%iB[=IF6a"-\|X#EQi$A ḏ}#{MbΟ3sڔ*l49_0vm1VT%$!MҝI2b&`좎eI3 öquDIkDҸ01a\|gL 83(SLEK$Kk tZI-?۱\SrL:jwQ% ` kSƊ_ f$5b0b&`23Ü+<0LF+aذd1+Y442c?SǸ-?ٱeKr/1tkUw0vuXPЉPNIId0]q[欭wXVn$IR#ς0`WV%% 2$K2d.p3XIv+/]JzujE9톆?((by2bRI +kt!VvȌkaU`na~$0m ¬ 3K׿S3dQ ~r-ͱX-?c׮^R[qO1^cQ?((L .4bڈUwF0>la=*a`(a"NtEHƖL@&L2cE=S֎mXS-\U%`TXȔAAٕ' fҤ1b&m6{;<ẤÞ9l2 'O)f1 `sJiy%NT ]a̾*rTZkG>.PIc(La30̎Van$0SW*2,J2EKctAf8F+f$U.]T;~sT AA+ɊRb5 1M]#fɘ>G+c\`;  +JWzLIjĔ0):aR0a:JfDX"ᕙfq 嘉ڎ1*zp5s9?M\D0k c-ƂR'Q9Đ&WFac&WI̒İ ô $)]X̄_0sI& Kl$;&(it ؒE񛉋WXhr y]=Q%d*Uшkӎ + {2LVx%5a`q2cбRZ谒J~JE9*1q$./26lJbNkG}7;ʔEy1 t0% Þ`UW Jߩ\%qʁddQCf9Jώ=vc[y_Gcҥnk13  +J[+f:s1@;li6b&og؎(xLG\ߍ2̩RmXLl47dcdxtlN?&.c"0vŘ= XPP6ebdbwC%FiiVʈu6I:}( ǒ^ڰ8> X,jt܅c(JLn19Ű5H?-ǢR؛oH/{wj06c>jxylHEƂrPˆa-^9^)"6,WeWN0d1'VJc(_TI4qaj8Xߡ"نWcbAAbVPk(#qkݮ#I4b$J}vcM`X";_'ҔcaB%Mc5UX"y nC +"Ob57R4F,|!M=F bRa<Pkl X&%27ҴT:JLQ=c4O.Ě0f-l,bPSD)vͥJY6ޒ&ш)#Fa +1?D2,>%@clS[or ?a bخU&ůpPih52ePPLY1ϊk% G4IF^B2,iL?>V"1ώI``p0.Sy*,a4{C + bI+j%Ib'M5wbvwi1. +ac;J7s28f1Wñu3hl*jƼqLX魴Z W\y ͊kҼuΔ'G8uρImmB`Ŏi3. 6ݿ~JǼ*vH\jf04Za 7\(k֮רXOΓSf̞hJN +Ğ8rTI1b&ʰS')͎y=ݩ܉|P W9!S%+F1b|2(o,Pj+0y \M*T;#ƥkt +ntyJc*r,1ܩ<_7a-ƍ \^%Kz2B +J*M-F#6P.SR9m|8M0欭H(nlŔŎy?c< 1~]*W"՘)SLAAŢq-JժSc&O=24oپk/:1$1&wò75U&`ưkW934J՘2((}SaUJm[ XٶsCc4)د>aᘛ*ݣ4=~jZ:S˔ah,(Wb\;>ҁV:i+6cWݸi֝{z0}֍Gӻw +adcY0=]hl**WU\Ae`Ƃ_zŰBP"PmФE]za+F}ȓh;|)1W Ma%1G1+13on 5S'3XĔLƂ微xN(%PvonŖ^! bO<3ϿB5b& ac_{Ocdu/^3Cej *i")Iʔah,V +L/M'ͨ0dnŔ$cO?˯~)##K7rSz”sp+FV'=R7_b&ňy{+ +aPj9؇.A%~]Mj-R2e+b8}'(_lڍԊSy~ 4h[>)~Ay ?_gL}1nѲY#^BYgU} 2(*B1=hNxN(GCdŚ8$+W~R #Č+D}+>bgȼӄ1SԘd.`?)i﫛)XP;.{G\&>Ũص'P@f yu!Fa2ÊGǩw* ?Wc453eX;zVJp(rn-v֫`:D\wCl߽GȊ7o~!71b0(1F_el*M5Sc|r)9%ɔa{uP)㠅9t}0dIpB@uǞ>o O=qtXa1\1&^/(SʸE4S^{5}52\D + +bRg9]nYbs,@n(ъIGKXa2 3Wne1\LΔ|x  ҸZ#rD[cZl0bs %'z_}퍷`>`+&6bȰOa/*j)}KD."eza_ [ ʸ\|戲fQcZlby}h %wڊ|RIb+4A1[PTcPq ^dJ}H^-ȁ^fAR)}P rDy?x؉fZl c+~/+n@%c,2o~Ǝ 4nfJ}O"y- 7 _eA%bѡW=.FkyҔg/Xk}qBt܊)+&X +a$a_Vc25-ϔr|,Sf}e@)PT4Pb4hAG ҕQ-W +KtʓQ,>IƘ7 ?]Er1=n)]ɔzɹOY˅M +( :B1g\-#aOr~btBɁ׿VXԈ7rN\[Ī矕qL=u$S&.sJ+劮drA.=rEPoݹcJJkt<)WWB;R2ezkTT -)+g%(ߔb22.&GN-&X1#1q 'S$%0[2;5'_YvJ~SžRzmܼM=1htDO=k1 ֊y4X:ƜXd"=S6f I/>"d*b\@hѭW!#%-舒.QҴ?ZL(O?*qN9&SngJO/pGSK*2vֻӃ>j}]yҧXq3(Vcf")qfJ,L ndGϩXeEW2,,(U(f. H `/^Mq7#Q)m-%bĢ5s2K:S "Cc LTc{;ѿ9,ΩǕf@vUJs\$\@R{Бz]tZEA QҔisJ LɳvG)˸SteDX"ȕDeB/F(|^@sҊ-z Z%@y:A,c[xRv,]8wVlabn Xc'k̎>>0K0#iD,(c9 3,c;t((Cҕ)Sz;zTL]hq y ˜McEYn& &|Ev[geL(\C8B1xQC nbb[7nfr 7SWs~cznk@"%LE: :;A4\9$3 s Y ;Mub Z["I-)W_GOq/ +cg{32cA L0M0K7#4Rtv )R*&)R]{[=PF $;If@%s ;tb(vR,qXqӤSv}J֩Aec|ҵc_'f K@0&~}*D#1ؓ9 8ǂ;)f˪@$%`,{)rN;zL5uÏyƾ3\;EFJוt})0``/f. ]h[3a2dQCNJ+x(/PȊeLV.q ztek50ؗA"OF&&"xY)]>f2d!ss@"iG~;oT*1&gǾ,}fu%\ +]>T߼p 4ȸ#s9رTbH/H:S{_1cEc:Tj8*v?Ky×&X2¾02a`gi~.+g2A&22d vUةR&3\Dr3;05~T򼅋1pqIg1 "6UxGS&L{0"~^ +WW^yUJWGϮR#fe d*] +:K%K1Kc;tU$+:(&04d2]fbެi2 oޤ1̍jT1;Ysg_h0e˜`ʂ_W_s5*]>U$f2ʘd.Đ`XcN<ؗ#>0[ LL900/믿nn`fPF$SAhyYXi@SbrώX_M.T64oa1Fsc1.Ǿwc2wt;3a0a*ES#~^Do[n5"-;4E3bP%!Crc)vςNN ?H25 ?Tv؍QJcc֐$pK)&*F ~ v*Un*mE_Kf2&W\%o9;VܿhA'QbPƼL;zxVR?e˜C՝4߅H1J׎YimcG];.0ɑ(®` )x.}wyeXw)˨O@#)e*a*!] +ِ9w~dB< TD5o!P츕E$sR[{~ii;;0V-7T;׳F:;0Ee0M080xuWٲe˕+W>*0S,#)Qeᘉ;Ri@S3%%"έ7m䆟*1oaJY61n4ǾNnނt\W#I̅aBI:i/Ů +*VXR*UXp`ed +dD2,cˑՐ /[IR)UeJуDL5& 8t0.#U( Nl.8 2F} ysMaׅŏ$D2aD0r`Ur*w}wժUE>*U3L.20$#ϕX\2`tP)U`m熟*q`yTrt\;veܘi7׾-hP~z`V LI #C4 Yǒ[NgJ[Ԙ4y 1 \tl׺EF֮Yn*ys@$3W?Md aքSVRjذQƍ4iTP5nܨQCٽʙʈdd2-Ő9|cqjH'UqxjnLi-Pqï*1oa06Ba`;~JUR;~ߥG2.7Eg9 Va7& 2`5k޼E-[lJ}>m޼p֘XȒ#dI ٻ v,c9VܿrA'\bZY2_9 `l +c=vjߦe աTc+m.;!շ! ']Xa7r4FL)պu6m۶m^ _mۦMYʝʘddʕK 51+})`tP)WLWc* F +cS q9Re̱˅c:W?7$oA:{C 3#Ia#Ʉ `-jաCǎ:uI}бcf@&,rHhȘc8/1/U +;J˔,AO26&06ӳ*[4m:zLq*gA=D~ ҕ<Ư~0bv0H0` +`/.]v֭R+UnݺvEc2ʈdʒȪUE,W̝13cb2* +_b^3c4oA Ʀ)6x@_)Uֽ&ce+cA+_F4 [s^-bMG|H 9&fQy.W={ջw/ ݻw^={*f2&ddjV 2p1pot ;m(V ʒ)jL~=odl IlT+c7A+[F\yCʮϗ” SRׯ >߿_?w/fP)K%@V2,]#cqƎyҔcc@bPb:Sƫ1jqPy/ cGaw-Ȏa%|鑮7w/mм[,`$v&dr+VL]F02^4x!CY 2xAg%ɔ'S kܨA},c:/[ +LqtsT0V ++fJ]хJiqPS&J۴Tvu(VVBD7Smc?]'d1aa+_R*UUGfL<&X_د@aÆ1bQJȑ#F  d;p@ּY0dUvp0v)PXd))_->zC1̍ݷjfcRډX+cwA+sC-H<yyGք# }>vO>” : R3fqƍ&@'رc(1()O SѲEs2 +1víW3cNŊEI2Rq1J}zvk~)V2ˠխ+sC-H-y0ҼqYvstZ€0ʑʄ06R91^ +\'N4y)ד&M(kdlf=3qcRMU:bcŊG٫1481T֮^Tw*a:whךb Z 4sC#~0R^ӴU_.| !L< kkʔӦM>}L-|1}iS*MbM$SL@֥sG2dX}u$;WYGc@bRb4՘TK{{`c1Jر]:X)ĨL{幡)HG`ZtT a5iAM5oي$#L0"F`/f͞=gΜ<>={,Ӧ@2xCdzv'Ck9fc%۱K5r# ++&f̫Ɯ_[#=A:~JU4/++5Ȉd2~;ނ4#w^ 0#d #F#~)z)p͟`… R_/X0B`6SPH%l@{)Cf8&>nsKuwSDbťX c*TؾXŏJ*ǐ*'=rؐXi~eЪ,o[țM0HsamEF&  ͝z-Zx%K.SZ.Ÿ-]d +g +w6g,"d ϴR?d^:~cE=tb(VlV_(۳sۖD/rcG:x@ވce򽪷y4<[յdt.0ֱsƎS)&,VXrժU]W\BML (3ldؐ!XI13j_r,`4RXj,ƞ{֮F7ؘÇ _yb+k n#K+C~Ȯ:a{ L04kwڵ,ڵݷfJbBH%LEQ#a4jXҨI|V0v)P\9 ?[{ؓ;&.zSs`pXXz9ֲyS2duKPeix +՝5ڑM.:u +<"`0 Z~ÆWz +_nܸa`(S$';@6ixej޴q4ZWEXc_`,Tc@bTr51'cplm<^!vlc+bkσVdu +UAY$v=K-dS3۪֣W8.lf̜L`` +`/Ůܴ!]7m♂z3&Y2ӧ!C$ϭ[6ӗFOʎr;1VܿA'@bŨ34q%w*yǹTf%Y3"VrW{2d zBUPFo)h$_RE^-ɦfyϞݻ4 (#Ȗ.aC%ql({oGdX +EbūԆ?cؾ=;Sɯe5htK~; OAkx.I"gclp*0:C01a` +`׾}?pADRf +eB2e6GI p'wxԿWJj c,dTX0㯸*AU[fb%1clȺ.dDb ^-+[;^`:” sx:裏)= +<"bC2ٺd4gKdyTtqؼEXa(Pa&.T_1Hʐ62oA ~;ɄѦ +g0$1T +0# s Rz'8|'O<=̙BL@Q%Նc0N2XvxkӲYJ~T:(hnLŊ[) hO\0TǶ-oXi96yx\57kix +kWӽxS`w$aх `R =vSO꣣G*)1ʈd R%ql Xݖu׭-Xn8b@bW.1>41o2d* 6N!~ +RMپ=]svNÄQoG L!L zgyY3iB\"lV24d*/ Qހ˱ƾ0vZ(PqNHa KG9ڱc[62dHk쵗:S^:HZԕ^-b bHsa CFA#SRv=/( +<_#Aab˜`xK/I9pd*ZQxe2IfXEDo7oҰ:~`c%كJSJrĘL\HYc [WxfϚ1m$c4z +R̪Wa7U*0F'ԅ)Q4SS"xʫJ?!ߟO^a@2 !ۉKeKQYݛn=];;`(V3ƸG|󧯡';fcVñU+!C}]^{zcނ쏷 A4%A xk>N$fnY& luaa`ʁ`uRf@ًd*Z!Xj>S=;<&0ɏr~ c|XHn52e)PD(0fS%c+=_Wx +mУxXOA1H#ѵ#3xSG | l8E`ʀ`x7r砙bBُٓ1`si$cU,2XJ5( ++r)cLoId^z9TIVKLOAn#j &6U$n۾sn` +aJ "x~/ԧ $'T$CL=N~*cک}c47&TLYp ++8+rS%VX1#5W2Ȱ쵟X<hrwNc!v|}$k}z1a/#U/ XP$S C<(;<OFi`4a*12yܢ[b%DY1cRc+{H<. Mix Rl"^Ix1Rk*\9؊Mkxǩ sFLLw!|)b{`?#eD2K21ḏCfXNkf11[՘d` +@b%Ei Xߎ!VR=9gL?xJyA':f1H< HWZX)OC`';<1̍N5Wy iC,Hcv1;J84;HV|@f<7͙ ͖#B0vlvvsat"# &LH!}8cdd24dN^޻[vxё*'qǏJcenkX (Vr1sTcڎbϱ'dj~:ud@b` 5HZ#5Zd&l7J4T# E!R57V5X$3 `矜G2;o/u ɼni)+ e˜SvLb%c1e]%myPAIJeK$WKkVɫP \Xa ~KH1dl~b4FGgMƆ'b̝0XLYܿAǧ@l|uñgdJ{df*YOA\i%^GjU :U0JL0fʈdSswxm6::~ctRYJؘmi?)C_ ++Qa;1?{ Z)C!Nd` ‹^-;]w$taaʄi1~O/aF(sAFe}it/Fm>07V`ogu :.,}q?~Oҵc&VpU;huCr6n':3E|m#W(!0ad˜``@%41~%?Kvu'S&+WRpß=S3 ++aJ*vL8$S(i)H4Mbe( Cb%NsRc6Vb'Fy;YsC$#OϾA-_W* Eii~Uo,f̀jQ(Ɔ ߧG׎Z5o\՘[ S3V` ++y1*Xk79kONHxVH/F#~1<% a.N$ #IdiMZsp( yMR޷;u.ݣKǶ5_ ?_EJϔJ2b̵cR8(?8=vH$[蚼q,<4*"G #f <1Ȓ.'/[ +c-ƦO0vAzwҡm˦l3My-#TtD}=UXXdbd)H޸=#hi>/ Ʉcp9RMcO~= 0p1y˜C՝-jɔ|ǽO2eA(Pd*L@Ɩ= ނ<|@:/FkjH7Up$,˜`"2d.ĎGblnj:o/[7[P+J2Xc2,H}ni~ +oAz:vyt_xIlpg[a5u~a.(ed.~ˋwS^|:~W,Y8wִGʎt5)C_h ++JƘᘉ@&PQT,{߂|zڈ#E/ӣ? y2,01a`Xe_̵c'c.6]|ɂ3M7z8*u5VZ'SJ0&v̋`A̓DL?<IiiѺ0:Q2"s }iKwп7k*uGh=a̙9uQkSc:Sv3cb@ر8~N[#ˠix +oAG5aLweίg |;Y9潛^K07vߪeHڵ1)1꙱`[b%Y)v̉qCf@&${[ h^#_~1`_'IKDqy 3^D9bloErĐ}{vX*SsJJX*lF-.מ0{tɏ `x9&,Fb 9mrb`l׬\h5c-t(ʹEČ~?(V c;V,e;̠XOA-HOoʋl\N.<(Q9 wI<c7ݿn *gNDXnSUJrdƮ?6jXX*P+Kg[v)ȘHj/ rE?W +X cO=}wl݌y 4LY2[`Ɗ2h ++b,c 3$#Ҽ1Ќz1yHK`1Y.rؓ1@?{LQl{j}J*iڂ^D +f(VqK1d~'+Tmx<^{; K>?aY!ñ!u9_c O>[PO՘ΔtNYn-WfLό~?(Jcvpg`TX2Cy;߂dY9E~a]Ls@ǞAc*0v1؂3L)Q{Q3Bd`AFHfPN7n?"Ev.IF|aƲnj{9[7ojl>[9eXH2ca"('±HtdDLHP>K A2 KBX:$s91]1Ƥ{5?W?Sr_2O[X3ό9~X)P,_ ı e~7EW?|%ζ!,; 3s7urO0o}_/z?&X Ab\8r OfhcdGؿc˙`i?c.č] JTc۸3̾v41=` +Aby_ O4Y\Py(s:aI?O'1]/㆟1Δ+9Šm3XqbAby9L̠y/#b_i1ï3%̗ߚ f,2l( +;s, ddfЌkvRJ] ^ɏ_WΔL?-H2c62ca)Pby$ Ci\$ζR(ƴ;7?-fnSj` +Dby !Y4E\G`'a,*}JΔO}}1;mᘱwmJgpLbyYd}rqE~s1_KrN{.i1%ݦ=c52(JXd6h2g2~#!,0>jL2%SEbfjeMDd-B{2s,F2ܐK43¯Me؉14N+6 ?1;oɔHq3cJYm2l3~?DʼTX+cnWFRv\cneJ[fL;jX˔!R +@Q7d1eofu3a,)ubxf )B1wB}od,DTXa(f@YVf#Iac11ɔ1̌mJ3O"eqr@BQ,Q%,bI׼OUc3-iiϞ>iܨA-loC{'Yn8KaQ e?X$SJoSnQfnSҞ1>GJY"e+POS?g +Ɛ)݂Ƭۆ۔+.3cp)XbT f[NQy?O[8flܦ\z|"e!(P`Ay?Xa ٥C'Rޔ9Rb,(vZ)𥕀1)M3oSc~WNm[6HyGB 7WbJ:*P,(Onjw2X@<͔ƌ~|5>!RłEf&_?|BF[4[t6H + ~[H 2z2[\32lጌݹ͹rn|=#DʼUXP(So+)g)"e*P,(fd~ߋ2ҏaX*P,(7#c)wmۜpJiGD])VbAy~xf=D`BbAyHsn!EԍHX(P,(1c~;#ex @|R܌ad̽K#Ƀ~?`d+P,(?H˄SU9FGDJłJEIBL}2`,(W)cw)7HIH{{R3 + /eIw)u?"C + + /O_Hk]łK"GHk#W)#R^x{?2X)P,(ϔ)R:1R}#z?@tFƂ'r#"]Ju f,?(gT2.%)f,(o)?)<˗)}kX0c@|Szl|MZ6m +-E囎+R:w)oݜ"erwȘ'R#e#"Nյc_CO7cc%TbAyHiI{rؑCީ]fN6c^0V2(wJ#)RΘ<~԰}{tZFL-XȔ%YbA㈔-7s11o-"ǔ!SłO9GJȃ*R.?{q#/>[)KłO"eʻkW-]8wƔ<2f}3Ռ\塒sDJ} }lH5c^ + + CE7SʣO<ǰ7ci2`)P,(9RRyeʨsW[łQ9F}edL g-3t͔20Vr()]JeƞvFƖ}H0c?4{L4XXUXP>*>kһy~0L13o +~ɔb,p)P,(/Q̋z>gMa ߷ffpқ𫱀@TBȘ\ pÚz؂&_+'fKיҩƸ.JłR262eʉchU1."eXX QXP~*ҹ?v`X0;jư-LR7{N0V(Jӑ^t{d~V+fL7cukURQ108V(EȘߧacJZmQLi.Mt +~2EhOcJ jUʔPD54q y2ohf|N)5IٱñII\bAyHi}'1SmXm)y1>L؉X2uBPXP*)~_Vzuώ-bh`zR)Z11KqC +0*P,(_62~Č=1M9t`_hT6OLi1ig(^eZbAS}}[3՘)cw5&9SbcTٓʘq,#PN4ʠ@U~|(N31cFVE$]E1&;c^IS YLbAy>%ldf쾕Kε Tc45F*< <+nZ孢R}{fѴ +~LSqw%05& c&U9v +"rYq)P,(͌f(έg,)霒1'`K +>-raYq)P,(}{ ɚ1n2%)i7\i0vwdn;~NQ}6N@2GbAy~?ь;"6SemZP5VR7߀8L4X2VrVN g#łX~a 1}L#^ϙ}TITT ;ssiD9Nv}.2tXXP+w6W1% jǨj)iXbߣ)oT1cKJʁ\Yqdō@|VrOאj ^*?Iqf/q}GcL11dJsP*2as(fj SdJ9j 7ns0H82k9 JYNb>f {h +~\ԙf_Q&Rӆxݩr vLJk"lW +,N؟W.qR2%;j &tPi1 \F:*19cDZ/PI2crTfQ>  k}h̘;m!oy}jlȀ>=bIOTR9Ʃ[+-?_`.c;7V +d_tQXYm /(ܿ8ḏ@Vg(S>3%f_׭^dLQÏV|2ҏC;&@hKQ"B}9EpB +n@21-h_Sp3c +ޥ1̍Rj.Tt2ٗʔt1lx`}_uTv+(VǸW sH&I|$3rmYo1˾ /~@k +cbA];^LkfSc~o%[8خuEǯR]*oJ+cˆ@$;ӭt1}'I= 4fAyX2ߐeXqs)P,h3Tcccc#R0FJepXXpL2dL*heŠ:un{h 3e֒}Ż!±cbAzƨ3iX];ozu(UV(cp12dȄdgQ/IV*,c}7E]fٷ< ;2 ʂXXP!(ɌLi[H5SRal#rfɎQkJ8ƆAfHvvJl`4}<ɇOτegmLCfec`ł +A f,)m5F Fccٍ*6/*+G11_d@&$;S]y]94,·~, MLbdg87|CcMUXPA(B17SsJTcX5;F؃c3r``ʱfv 1p*16d-D9OXf+-:/ +/.`BEC3MWc;H  *%h ?>s[ UrTvvVvLs SLHfݑ=7u}/]ZC]J_㻌4brLz±cbA̙-PIÏcG-Ř7 j oLYX7:+1SEXb,P,`qbScz +6\RC ڴj޴re Ɍ;Օuu/.PuVCtHķnhvdY%bm'ڱ2OtǏrLJUŽRqleHmTlLHVY5W#|PAgF㻘]B.Ū-[)nݺ -Pl e(L@v`];ԩM޹}#XJ1Ked}{ɺ: +Nȉdv\>}۷R_o>}5ЌYF(` Yı+ɎasV  *H1@|SJc8V>CϿx!2٘Q#dTS<Ѵe5jѣ(e7N>Sdt M +!XyXJݎqJ.bˇL(TcT1c/WR9d&%# aOoO}tƍ?~ &*M>Q?^QMldY^!Tñ;(V^uc~0XXP*wTO^Qv1+c^BE dSL! 稇*.A5y)SL:u4 +_L̆ T+)VZ`b,fϜH6$#) ꩬx6HcH.b/.5cƌ3gΚ5k6k>Tߚia84@ 7=[15C=v+N+ ,R-2/CeXPs1Ic|XXzL8J +kV!Y‘͛;{l +P])L_K56].5wyWZK}1wb 1tրCS!3OiwTr,cyb,)UŽXi9{m[6#Xn\Atɢ ATz\]k)$32,\ ,\pѢE/^-—E.T@G1D2:kP $7=81]#Uk2b̖c4ϩK|cGGR])^ˮ9Qv-fv\TVZz5kZKիVg 5t +dqsS5)Vj;&RctTc%  *d%cUz嘵co)S̱܏` @v )-h.w]cEZn7@}׭@3y84@6Qnz\ٸa}Jߎ]Eg;|g>3wL^311q )&9X@A"HP""E v4fR&uLq^k=u?{gY|?s]xPAZ}ߛCEc˱P9Xʱ=L,*'K {6n(+uqdzru-feό^ɵn7lذQGa*wSgd97\]dpۧ:VJvҿOc+)ʖ;J+~SrLΕ{#dRmflM29]6bzruL"ͷuݱܯtxEK'NM6ݧlV?V_޴Im|c%C&LA&Kc4ձrL^VJ}ǟ3O) +c;P9_V~VsrTc;5كAIzru-j +.\lQ<$] 7VI1AXB}'w8QN6~\1V7*]FwXk lOmAmYOikز+Ȯ{"٥K?um@0Q޾kAv[t:Wl\Gn>.\I#~Ucz4<Δ*ޗ{2\[*^}%SRlgde3 ѫ.]:TXm߾}ǎ#۷KI,]l.^tY!drL$;]T\%WM)ʗ7"Xc9 IRG=$_0%W]64ٵfN.VvzLy\<~`. 4 3r+l鏠ct]1}*k۶#PrŘ}Wi1XɱL + IC#w-oȻΌe.\*|ɧӖ#'Daf̾kvαGؘFrL^VʩR.NhgĘ }cerO$Ƙ9fO +#LAfPIMK#{3WW.̨ /]w2ebkϞ=ψgck$ҞyN]W) <ɩ3HEcۥ1R[Uɱ2cg 2IR=w3WWv.h.]~tڻws C{J198~\)R:9VNR1yYٷO ;W.߼cEe)I1T1܎9l9 +2I2ɤ:2G=ss,c#WwyeKE%r|ID +gwW\x<1mUvlTygib+1R UlJ +3s,2"${QeMsԓ<c+2eKU t,ZƦ'ַ>2dѭr=vݵӯZnF%c73A7)cX4J[ 3GKd/HNz{=Oxw]{C]Ar! _U?*q&afA{CBڏҼc tl)e=U^ttrr}cEe\bɧh9cdAٳ(:Pt`n$Py]/]6Rd8{~gd~\o:c˗ɱҔcSx89U;;?Sb" 1."c&~mrLd^ҖdAjzrs-]WrvzWyO~TLg|SO>!+?J/˱^c6o^b2W9I9fALd^,+z\_Y z]./W>0> 1_Q?]&$Ȟ`~$[Tʱ97\7SNYcL7\E=&jCUIX)c/L~Im,7Wru GƠ +EG o;zstmSʕ˥Ti.O1Y#_9\GW)*r+1[\KyQϞ͕\]%d\O!+:>w66S :Vr7ͱJcX͛}~Ǿ̼+bC[1`iO:Ⱦ $ Ey(벅ׇAxѥ38Uh&L㾪Wos69V޳a*}*m,Ǝ1vcEe)I1Tx1d2Ad:>#sw_{_x? +pv3L& tiVom?6oeKTi.̫ M2.᫱>SbBYs쯡.A Ⱦe&>n>0A+KgϵHw5xRfH`srlwSכ;X0RV-izTҿ )K#PX-Ȃ ̋ja1tٕ]LΟ{ +6ؽصӧʫx1_T~L:<RFeͱhAN2/ʾG=su};2uW]&~e:|ƙWʻOC:G˱Rc[t>U1ҏ^kJƒƢK#PX,2[yIK8ypueY+\_~c˱S\b1vfSOpqȟ+3%)jeF=9Ǽ,d^wV\vpvy$~/,|H`أr:;P1 1f_Tګ15VgJR +K9s,zdDUʿ +]s"Ș]^X{/7Yc4X)c;wS\;{ ?գgtwq,Ѧ1R ,M9ZI _] +_vEHtL@,܏1黐c.TrLC1vav16r5;Sj1Fe+9f "AQUƵ|79ϫ?f~S{?&Jy[ܳTK*rm:P9wхͻ7Wcv3ec\(BA_E=79Ŏ꿢 ~Gc܎Sm;pM:{//*Xϔ%Wbz 9T,e^hQw] +R+ϑ? +K2oяҴ>U~;=e֮61&Wȡ.mcrï'*XJ#ŀ|9YfWyd̮?%G0GirLnԩ\m{8cN"# ~g )K#ŀhr,TAPzA%cFt+[B }V:VrĘHcH)&-mc}.ѽX"z _L1F"1"Ad(v}+|fLή&e M~9Tܳ{?c3]=q[~jL½v {,b,m5(^YXb5.f X{߻&ƞv ZyǒE|u3j[ зwO}5q ϗ9 $UGieͮoDOArl߻T{C1殕2tӍIۘᗫ3t)M﫾u[Z_])dɱx-(0K+Wv-h1'RJ9U1c[/ oo՘3g{R'ŀ/YFz,~Ǖ2B1e ~cTч3=ܹŷΟ_TN3Z_Iטn3e]l1FQYs,!bُC nзc1icl#;~ۭEj쒾/8O-R6&( ~R Ȑ&b%RVv%Wzo19V嘜*; Ƥ㺻W-7^?{5^=Δz2^P)$2GObMbHOV8(Lwtɫpmڸn*yQy ͐# v 9Sn#ŀD2GfFW,dҔc~UUcO=s$˖,/r5&-2xOi.n i}-bxefY +o*bs,\開p=+1}냺Bn˙O/Rz_uӘ-cP2,3fi*7n2bL=Ę~Qy˗޶reLslӘ_)dY,9&V4dc9U˱H0OJ_ygJRz_;u .mEԊ1R +MGc9fRH2S' +Lyas:o c1R H#eq԰} c:~1/}F^Tn}{7HmB~逾TxcV+;1sc{՗^kn՘tEΔiAEbT:_I1 |R|xXr~cm̿۸NΔ Rz_1-פbR#%Woʱp9Ę}S>4Ƕߤ-L0t[4;1R F :c2c21 ) AkicP]oKt  ΔU)M1M1Nfc)H1"4Brr,cf p5fΔ=ec'c(H1lc_3Wc3KbRbA1V2P9b̎{tgʵV{c)2?P X40/뮱{w;3R)H1%cc ǘᏞ)U) ~mc+Jق^c՘[3壏<u[ĊHXP>)Tp i~ )er=t[b,2M#YƘ >oϔj.7t[8n}c2k ŀʐ+Gj;SJkv[Hk;9ZCbPoƂ~}5ϔ^?>ӭb,XmRicP)Řw4)xM_~m[_3A1}6eub@H1{CL)zIwn "R[mϦJ Ƽ3yOi.n =N|if1fW[8Fc?2Ř v=Rb@%Icf̛Fk ŀ2r ]KbLo7M /}R ,Wc3e_:h161Z~l[#D:_h#%)T~14˞1?қ wꝯlA*V-b=d:_f-H1R,1/̄g|-f R T b쓠{1ٔz |.fl-H1Ő㐼pu҄1~|-f R \y~;|Jw&7[%*Wf-Ƽ=cn]i}}R `b,3,}Ϧ!-]t\|;_m ǵkUP?Nj|]lvkfS-aJR d)Rd٢CF\#ŀe2qH2d;_wxzkl1"7Wb@E:M|6eBm0-B#rJcs5)Tl-BXu{5[D>FDY-H1E"kkbl1"%pO-^e|}5iHby1"PRtf4[6[D>FD)5[b"{1|9#RÔPrufo6[\-)դPu*^f蚱ub4[?Fn>)I1e-tϿȵBȈ!Jqs5)T?%5[7[f cDJxs5)Tt6Wb@5Hl S޷Q%nN8$ŀnśnЛjimnksucb@UHla>F$as0塇\M!\/z]tsu0e l&ŀ~_"zIKms5)Tܛ-ftsucGaʒh ŀ*QeSzi7W'S6jR \,դP- +̽sjWÔP-5[6Wa,Sb@ը0:l]"ÔP5ov7LIU#~kK1f)g00ej;L)Tvs0eo3LyR\ÔlAգGw +)u1pH4\}\ltHտ-^5cr SN0Ô=KE0f R &-aPSvx\|IÔatuks6W70%)Tl&IrJ7Waʬ~KE7W5CÔb@uɻ:tjXo1d`ޱդPe7WLJ)c3Ô.1R 2)aer̿ц)I1zghson4gE)I1Ios`sud2l}A1R 67W{fs̱0%)TlF-E6WrN0`2}m8\MU'0)z5LI'[EaJsu/:s) |#0劥Q` +\m)U1lesu0e6Wb*lrWhr S^1LI1٥\)WÔ:q>XÔSf \*\m"Sbr(`su0:lÔ S~ln7WÔ$vcfr S SfnÔ+H1\\m)Oj_k\Rf%C7aJ]iSl6W_٢hÔ1L9G)'aʞݥ"aRm)Cvr?Lٹ fsuQ)I10Ll^lNLlA(\6W/,`su})I1yL\=M-]6WTդ<꼹Sf\X}R @> SzךաaE'wsu~?l\=b~czo&0Lb,>L\\oi7Wgo1F+0\^;Ly S7Ô7WiWaw6WaMs6[t$䗫"ar[hrV0e٢Ôo7m)sl.0%) TÔY6W_#"[qs5) |)WÔk۴<&jR @Q\\T0W6LIH#[EaaӋ=LIHÔerrSbRI3L/:L S Ôr S֫قJaկdlÔzsu)I1őB1Lb:iE$Sj3L12ysuQ)I16L+4L9W)̳:>) B))WÔlÔSf ora})I1QÔ +|rcRS S5ÔɔI1\erDao\}R @j S> S./`GJR @zYm.h$0eOL'SfaLY}R @5Lɔ I1ETaJɔ~_7[~P\ÔJ1LdڵnQ}R @!:L?r SʲĞݥ"?'$ÔWaʺb#0ن)'SƖ%ֿPaJc9)3%''S݆)m~~H$a)#s|R~?ՑP}3L߿_БPX)cÐt~~Mw$*0d7^D~u?Rb +j2~Zs'8Rb +U0e~Zt$,[1,1ԿoL}ٿo>_enGJR @t nG-c)I1+~?|#H)I11Lpoe~x$<GJR @1-cGR‘2PTy-c)s^b"~Б2bP)k[r)Yf׬GJR @$c m:R.m͹v2ׂP\yM2s{x +)o|YJok1R @ߏ|M>RBf2")n޿o[)$s Rz#y + M1Hk{[JokAh(b,v"-G)>Z/cvrՙ{? ))tmo;/Y*:Ds$SzŘG)͎13n7%^R$R @w1R>.c3M"V R @Dc(ezҽoz/)㓔K,H1b޷NW>2M)~_EM{?Үh 4|_6%^Kʫ'_R&)C1R @ )#}7/) u3$e¬{[-n\H1 ]?KJ;dV|D(kaz)~zw?l}'A:x#)I1+"n$f qpR @0bvl{1$3žoI1%w}IAʌqpE<z7WӼA2^#z'ߓOM8]jAp!jb/3RL/hӲy)I1 9ż8xlj'RbARkr`5O1{fEh5bYjAhHMZ,)=MeY0FTK-2RlVhM")BS VV!zK`_hbJFRFbWI19 +R @eO15g #{eub?Ky y)vbK$R @bQnGr-')qRl4)y@Jb R]R )>@JR @IRUHm&R @y#:u*ƑbJ)ER쯤rC(oV;)b)b)'CpPH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1PH1P(.?oR RlP(ň1"}I(kF(oՔbP,'޳)+b'ŀjbW)+bIRlVFjR쳤bPqSI)IW3RlN$Ş{>Ȧo+)Th5H~CR)I)6tRP"Hx>1T/cʿ_E(Ş+s9TΒb?Y)1r _B,b(դؖm>bӟ%H2EHcb=-&nublQ)uGFZX%e<T+JI_g؎**F)vG<b R*K1/~kS쓏ޏ~rb7Sls/&XHI>ޑk{=1Sy6.NR7~W~bT)pb*C,bS)KbU$U:]tM7`ulSlbUm)o)uEHJЁkc?wz]RIbT-SlM8Nعk$n[f&bܳ739T=^e=OR)iÚUb7DRk'4|WMO.)ؾ?7p1fb *}. }I )vUWx)vVb TmS/[/tØŘ1/H2߼Sܗv1Yiwz>mSnb Li;{ߏX~u]s 7-Xlu=!)fy/)CŘ Ty!b+J^LR b^lnbwh);_Im)vNcSe+^JOeˆ_zŽ7)Vۦbo&ž?bߌ)q7.{5%\#܌3? Q\"6<)b@)biݷ^')vq)fQSu'; \2x| /Xl^}|W?Wg_rAe +coa*8)]?bZ}-&]Ldظ_V)v񵭋b=bMAʛHØ~I'#~Kǟ~Δ }7&9&A&IJbny'T}g~~C)ʧ|liXynݗ ߧI^59N} /?f-ZS)vγ^erMB_Ř)_{ScLib +2eT๖&l*|M(صݾ}-Һ/+-~Jv[4;ý;_CSbը }i/)英GGWxyMǘ1dd&T"G?u!&/(yWGRŤuhUXMbS)U?t//)X%cޑc>1c:tPAG[sa^}C}r-r4 b?h~}()SbzeA cL;1un]1c:TP+a*â!.v?S(2Z7Zt7$ k)Z0&BypGJ3OuzLJ2e֯T๖\=0aW햛+J.3Cbr7^eܴJŰz_f߹F[wK~}%$TIL%=1W0ɰ~b/Rl׎rkEä4v7Xhe]jGl쬞0y̳GLaBW_zgt)rޜgl@+- H^m\4eu7޼@k6lblOy_{ޗrLN22 >& +endstream endobj 299 0 obj <>stream +U0)ݷ%^~gRQg*~գxa {_{%bO>s.e3rBIӦXH۫yIiؤ)3ԑRcu1C۶|\b^zE1c$C#*hs$ؾLB앗^xNB۷=.ŖRL(gLdyEizͺ5bYVVͦ4/)GʹJ1fýM&n_pM7^7CJGJ9Pr1Z̻ܗFTbƂ}}1&+H)o)*Ʀ]{oYx6?Òc;{\L%ٞg$˔<(-Oʯg{\a*~͛6[x-7ϹiwRz\iŲwoflǘ)uŗblfϙ`57ޫNcۥ $(*HT!Wn 0I0)öKׯ[h9gM:ٔb\tG+)k^CcH)o)G0jua^Mcm&AsDOsJ338 +doy;$t=`2l;W.} Rf!GUSemTRؚu7 O%[<(alնH g]׃[<>aׯ[2l:M޶bӧ^u1_n6w@zb)Hi1kFΔr5fcCl8c\9SI2eϿg*Ь*ӮA"l:K 7QÇ߆\yMK}+fJ:();R~߱OB);rj3CuXɱWOff͒(SY6g\g*дy*yyW_`f*l5S,6Q# <:ĺS:dcԖb^k@2Gʯ}=ZL){O9X {_A>rb⤫2Ul:ˮ~lgʍ*~#|/U:&MBa9|襃.wq {Hu='l[ulvTPf(ӥXp c3fΔcTuN={ɱƌ/A6YLEٴg̘9SٵiTvϘ1}4``%ƏsɰճGwuzj' 1s4bR,"G%]m1fΔ5ڴ;Tu9㬳/~ 1Jdcǩ$R쪫l54k:=~ʔJJ`ƪ2lɰS}:NvxǵkӪƜ'm)Oy-t1ߗbəiJrj:T9&9!$.3Iʉ'M4YJ@3Ϲ<8J`&.6Daa;ܳ::NmJO JUwŲ)bތ;;vcU0pCTE6R%DqƏWq6 +q%vЫGܸ`*F*lȥ2bt;:˝ 1~nR,2bY1{ bɝON:z]ԧ*$S5He*.Lj!Tӭwث/`$ TeX>N]O|r y2w)32~c\bL;I*Urg/U$DٰÇL%5@ryՃa`&ʰ^=U4IBv3W.wGkJ{/WckITrL +I&Q6h +K(Ca*}W$tQv=Γ:La4y C!&b~223gJs5X[s׿Fq[(2%6'(e5u dr];i~V\\@\?4@/ +* Uu 4*hl9T E.Gua +"ʘb(EK,P\?(V<~RP\@qR2@p]s \פ@Eq@ץ(P\?hl+P¹~H\@Upa7@p]fU"s]`Uu8\ו,azq]Np #ׅ$s]Bu< -ו#\s]3HuZ "¸ $s]'(@ +@ݹ\׆u@ +,vAE:Nb@*  \G @q]h(4,P\}p=uT2׵:u**Ҹ8:~*cCB.:*@IpEeuATN#溚PB\@s](9c ,."P~\WpJ|('k7%uD ׅR:ʃ @ypUeu<*R^P6\@Is](' t׹P\hʒ(Ek4eut2:J @ysau]칎1(P \'@Ip] =:\r](# %׵:q]4S U +:p]X T,Ш\_*h<+/u4ו +: @ssu*:P-\@r]m".TיЀ\Zh(,Uu4Ej:" @5r|P\@񹮰T)Pd+u +@Us亶P\ @q*x* +,/X\S`Czq]L@u"ԋb +\WR:u%C\Q:uqs.\Pu4ԅ +F. t( +NG¸ + Pd:  +t\\g$@\NHuyI\MHuNJT\MHuNJ\WLuK<\KuiK<\Kup# +ׅujdP¸NMd$(HJNd$(HDp \HP u}u:>\GPG u}u:>"\GPw uqu:A"\GPw 2zqוԋ\EP_sr]@}QuY:Gu5(lBNSW*4xBNSP\WCP4T;@u5E:P@Uytey'I,L=Ig1ƘH\vkEQEEEU6YYDPPDADŎk4Ƥi&ݙLIfzfzO}NU繪N}>s{SK(0Kٙ +,Q`3X^se* ˎU`yeA3f/;Y%=^vK*{dQ-XFW`d?%;_=l|N]X.ٳ6ʎX`d>(;b%=lHSX"كNY`YdO=.;he=lBX +#NZ@e;;$;n˞wvHv==z.{9ى YCI`Ge.[cN]@?e8  Av==N_ Mt&;ɞnd0+٣ @ z%{Ȕ@d5ɲc Yv ==Nb'|I AD0Xx c`e3";Ŗ=̑H[,0G#X`ك |Ne`QeO1s';E=̝`R0X< ʎg`d/+;=̯I0ײCXc i`1d, ;Ő=,@w +l`e*$;=,TxG +Bo`d'*;=,H`زSS r`.d$}@y'H=Gv'^u M7ٹȞAz(;@?e;<[ X&;7!R+ϲ3`evɾ,c s10cٱ)3ײ'R{]s-0/O"{M}ȑ}Hv/;))O~qdpf/L,s(8[}jZ?6!!b;*;Ctm}heFL,;!myey&ePv&-[ t>i̋gd)Av1fdL֗gز3Ő}N^ `RvtOɾclN-z" /[Vd,쬢<ʾ'l]!N)EI 7]' 0%}d_rf&`dm}?[9H0]1cٗm 06*Y٢HBuO:/ 2e'Lʾ $ȑ=Z؄VpdOа6'{鲟 ش!~,`+h"ȞaR3[=Jäg({1l]4 cغiF%5d? Kjhe? +gjhe? +gj@X ==Yz@OdO,'f&{fe?035K-,e,=_>X>0c#6K*eO,=eO=lA}`d,#%{fdwF6%6Y"هW>'nEIm=t,O:l졛}`'d,c;!{8ћ>soz.ɞ ;*{ϲO7>Ӳgpz+hN˞s p)\@1>#{5Ȟ iqz%8@y^>){?2$ ɲGrz" @쩜>/{*O1̅>>0s^y=0ٜ̋Ŗ}~`d, %{Bge^/:*YT'NB>0tRy=x,̩Qœ}f`Ne, +{ZgdX_:$\YG]>0gvC9=),챝}H`1dO,C +!{rgePX;.ޙkI\>HwW=3&,)9}0`dỌS ){geJXHكyKy=3G#,쉞9}`eŐ /{g.dC칞} zeAў|gz"{'YȞI}?{2e>L٧z%{'MɞI}og|rd;1ه){'A~ʞi'z+{ge8a}ϲ}vTq>˞9g z.{gd5쑟}~vHA˞ ٧ B϶>b,g]e=,}`dl%,v>YtK%d.lc(-,e)XRU>P3}`yef)4R.Ri].03G ]v'`6^D9ԫ>>D@n@!Bv3`We ]%d.c+[}v1->8e`RvK`+O 0EvQ`+O 0EvQ`Ӳ 0]vW`Ӳ 0]vW`s &d`-ٍM>,Z}Rud6*. lH1֗ؐc/73lHvu`}gؐ:Qud`k>&dV}4*h!.\]#.\]#"P[$"P[$}"-.L>e d`cu}JA+ *U>nS@v d`Dv@.3]/]f&^,RvXj7솱<0c%cIev`{ƒʾee}m]5Q=EvX:7.mcdp`d}m]8KQvX"ٷ^ٝcdj`{ewe}m];BMvBvX +7 ͣ0CGea`d˾=}{?,;*YvTv [7i-* P-rdwʾ@.7H]G&~iHdL Sv# dn$}'d٥?$,DmeȾ@^ de@`^d}yN[HvAYlw#ee:`dw}QU}NvMYT ;5e!e4`e7}yTOTvYY0ٷ _}ed.`~eE}]YIZveY7 +w٭ead(`eŐ}]\C]@vqYٷX ed"`1dwy}]_ZIvk7X$ f~e`d}g]bTmOvSٷX<=fe`!eWy}O]eN Uv/wX`مfd `e9}+ŖiH[vXxٵf^d`eך}>n6s!&}le'M;DvI}7=+'Sz%ɾ@d4얓#=]trd_uNKSvI}~:;-z]wvZz+ Yv9Wҳs4s٥gd_f{ɾ@e}]}vB5BvvXge_``Yd}u%]WHvFٗX.hd_W`dנ}]]EEQvXFMh(e_Q`Ie˾C3}9݇f)ZK-RZv% ,V4W@b4ٗ dwȾ!ʮG*.ɾx# id_<솴uW`LvIں+0&$mQeݓ"L]"L]6-Lݖ6-Lݖ6'j*0mNXUvaڄKδ ٗ +`-ٝi:kFe_'udצ ɾHnN˾B]֗}6$<#lTvZGبk j-`+Ԫ/ dUe_nQe_M.Re_M.RSd_ReשI`ԘuٍjLغF5}%vIvɾ$T/U{UȾ3]B5j[=[̄z0LW3[̄z0LW3[̄z0LW3[̄z0LW3[̄z0LV3^̄n0LW3[̄z0LV3^̄z0LW3^̄n0LW3[̄z0LW3^̄n0LW3^v+ +XZLW3^̄z0LW3^̄z0LWnJz0LW3^̄zfۭ+`iW3^땆,' +`&+]Jz0LWn, +`&+Pvݶv+ +X]4,`IWnz, +`&v^iX@XR~SvNv+ 1 +`&v^iX@t+ + +`eu+ n^ݮB5Uٽj$Jl]v}1.QMʾ[ݥ˾*ݢV}a6'E%lTvZ_X_vsڐڴ ٗ +`-ٝistmi+잴uW`$!j(BK-XTv.X"he_``)dW}ʮ; /9CE'Sz"̅,Z3_ʾ3b.$^s*,[̅j+7H]Dz.+s,;@v`C/7E]v'`d5Xl=,$/7$J`m,k6؜Yōֳ-lɆSfmX f1fiy[jFOv&feȬgɓ}Y5S Kg#NȬg;< ?Y7x 0kCf=g:}Y;qx7zl4x0 ճVzLI}F̛)a3.?8j2y܁Y?qVd،MJMF#wM1X%ƢgY=w/YEĈ38ݸ3?<ݴ=SG@l,qVM7nV?^ӊFj#w68Ӊ~0?%Y/w%#g2qM'mCV7AH;68R2pq3J&T~tu~͟a ge;bș> g2ofigQ;Ma&o:i3 gSh>S ɾ@c3ު"oFi3 3ӵh= 4xV掚snY+q: o٦IAl?7a@IAt5rG5 Z3ș8R 6oqdM/4~cA5SN=iǛY?w̟DN7q~IAu* mڤxylGm3I=5z:3O<ϊxʾ69!n%N75p"oFiS&bqůOQ?-M 'g,yƃg1xCN$Nwgy3L&jJjkV?$ |"zF &w^yf6Hr̙93Uv(o"nڰisfv)7PMȞp;?2w6u'o T'a <â5;f;kE欌W698ei&8ݼaSӊ9,>|j͡?MSgǴSVx D띍;Rvf"gV)U͈S*0pJf65jj3?|$POdO=%yӌ5{j٭MAYQlYbvªc*3rZ5qTň3 ҧ)q3HȚ3sh ~Y>)a@?>MMxJժO[Z6;Sb'@_լGh)qyl$K4ST7%nڴi2f=|^^UB?>M'<O얧ΔJ;3eN7r~`ȩCNԪU5q)uMmaQS3f~AOcߪ>B>>%{J'kP&Ɲ"vl5*ijU'qPw8&&⦦MdMM /*kj_yPO>%{bSGv܉;?Πf;-KȜfZ^U79M=N8 Zj4qS&&K^bꀡK^H>%{J43(x"wg;>+ޣ׬U[}OkV#U!8c)idM^<G""}j쉱IvxVNw5wY+v ;0{9jY;qMMn"nJDXc栃^W8xi)cO(rHPO =5z3 sgީ5w&Zؑ:MVV+X9+g87GEDDD~GqđG,~x$POIȞ{J&D;YݗYbv֔js92gj VugeH64}QG}s׏GT'F0y3x:Ӊf5xZ+vԆƜm-V^UZb3Jn4Mɛ7%mJDҼ7q՛W~Z>=M g<1DNj;qg2}˝&vq'vÎԁYZ9f"rUN!g :#NL8ysb66%l"i:9s=Waώ*S&=8TY~\>>%|"{sݵSV͝+yk^=Y͸/ږՍMذTS'NbX+sjnGcN}gUUKXMjt›O$Nq N͛RJDڔ;KЄY;""~"|i<6LO 6euy8ͪ?+^w#U͐sɧvz8]|eoʫ:SMI64G>w/.?-~@%}J-H6xbm]rqi;o<ÚUǝi[X~]팥Ώ: +lЪ]猿,fg={6r^ZS{>^|dGsOdP>%{j43 w\su3DѪ7p|)5Cq5-.wSt:l4u'̻3*2yiՎ9ĦYy{Kn^u|SV{U]qbi'MMdM̽{}}ɧ' S§L>%zi'V3\qy;us)h9`ڲb'v24ILk؄^[[ /b﬚fJxRr(C^T[UI뮿]7Fjg77%mJԜx3Ńg?O =13p}3O?] ƝC~emYrg=jɊ7YOj:Vvm(X12BnՏ~7g04˜DN 9QvymU׿38u‰ySOɦ5>C}}܄Y>%{c n"rJMQnMRʈS+ՃmԼ)MȚ47UNUyP>5zOxb<;!;QmֹˬhY3vڊaM[댥N]Ȝ +B`[WfiYfuQ7x) 9w}(f6qFMn"n~fMM-~ >i2(ҧfO&yjۊihEDϊYމUǝ9c2v^qѱNTRY˨kY=s_[ 9Q0V1z=ox |X9ZhU%qbNS5opӤMDM/u1GYM6|"z"yb3x5̝o{-uݵ3hY94v&R9QL/Xw3Ωof9Wڬ-Q|KlrbȹcD,3 75n"mj֔t?Ϛ&O3 gP"wbѣftc}uU2N@U٩k:?WSN2z~'pjķsuN֪ 7ۜ1D3ώ7VcS79Vڪ"qNSm4iS˟߭U5FO$O[O;6hjVͪ۝ڲةN@/v}^bN:TS{XF؄3gu|!V 7/1'YE:팳=_N& 9KA:yM &gƿh~3y3xܩχ?5}mƝkb'v;ǽca瀗֊ݟI_ٚ:Վ:BVV=WnNyTfu9_xѥoq9ȉMNr>g\8͈32ԼiӦFM$ßP&PM6zjԑg8L}~uSjVwF-NOdd#/VϜk:yk*6ȇ~dlsʘ﬚fy]Nlg~W$NN4qӤM4C fODOM6xbi6wg} )5w3Z0v.쒷^pgvj ;;:*A/?`:O{wkS-XG694̜?ojU7Gv9xM~E]=r"r>g?7rVuǝqӄMD˿T6~ ?lvy_hjVwe֝{j/8:VvN zOl O͝i;͸e`SKFǺsbw:M}OWXQQGTe9u\9VJ6.kjc귿Vu8ei͛6mjm?LhDNUu&N3 M7_V5ʟ6{SN<1|ig5;e=p۹-V;uع Kzm|Ё/x։5%:L3J`ڪdξ/}3>4cG.Vѐ&NqFSf7+M~0L&zڙg<1r[q \]weعW\v(ub\Rg))O&G*YUkeN~#pЬsҪsY=мD~J8M7m|Uu}'K*n:'p>Շ_%N|Wg_Y fN}U^X2sjGcN˜/K6rp,rbsm430x&rrg8Djc=;};gzo|QGv` GW?]%[AQԯīBn9juͷƜA*oj4y=>8DLx <|OW;5vG~ ;)뽃ԹO?2Wxu:J1\eO9/zɴ̉ju{nVu̩ .׾o};r꯺3 ALf5d gfiշ~w{9*A FAڀ$OS* un+.sbc^%7NeEtЩ/79rSn.}OmN3|cEh8͈3 45zϨhrYUߍN ;Qs7_:;%ǨӼzr]%7ԁIfN34ov "sVuNVw}nNgi՟|{9!8+-Ӳg<݁;5;cŰbӦέ7kΙo97:/oYOtUa٭Dn2gȜY!9Z<#_hǜhVտ"3'dL ge̝fSǝe%+:V ;Q u>pۭ~uW_qE7ŨW6W+:6Zo3̜g>{>z`ƨs9Jno$gxȲBgɜj<9csqMī +#Ľj/b̩Fj8fE֬>+gEƝ&vcy>roxU1 uu}=\a}cRgIZX茖eyww{{3'V:[ `.s]D䌵-jɳ2wV;;ŝf؉N:o~= +VQ'Vɥ_RՑ>Kݟ7uMЁjW: o?4/;wnU2Q4+vSĘ38%r$VgjΊUcvjŊ}OZ_jFK.:9u`@' +qEdi\q +di_@:jth 5{Āc61ci3sH JV0rNw2 QHjg;y*xf:GKA93irjG:>Ա=wݾP:O•䡃9fgԁtȨ"+넎N"sYW4Cs.!9kR+sUS;>PX_=m+_ԙq4x)ھԁtN[ :RD8k\roE9ZV9"*Y5T9%cPwI~Rfxhi<tH:a9JhAZg."S14xŗ]q5xf:GJdaGU#ᝤu|c󫰨dn_6B{ӁR\$WsG3hIH|ŗҝ@qݙαrRaN㔓N`0Ա^yY:IX'(JiPGV>|`:_!d:@UjrG+[СYsqE'~69%VsN:ף~:H<ڃ8DӁ(.:'tΙ-"s㊝C79'Z5[5$:|Ѡ9[san $3r>Q#:s&Wh\iA6qCt" aίt[iͼt2NB:kt22-v@\ME]V3+ۂ+ZDƕr8th|+/([:\kMH^/O:4H]cg*v(eI:69%m|IgItHgW6rk^*\䊻 :Q*9VK>9c Ltȧhc"*2v3]Dfy9t^yIxA:@g} t*2L@M[:RI 贑s6>I:>P@u:+v"_c n[+W"rظj'uJI{0Б@ t\"X "?e삎Cn@:Ԓt:n.宊|usX`\TM3 &SnrE*2]Eֱ@\鄎+货s jHNӭ+ҕ˩|TX`\N[:K:<r_E t{ArSDnQ +Iʥ+%UD rܥ#:>Nc\"rRHȮӁ/@\oKY".Mlja; Pv=W o#'Ztr]ϼ]vד2 zvl +tzR<0FZtl-#gzew==}KؖQN-#C:exszgOػ#22@)]O-#w=; Sʕysw=3OC:ZFt)eew=÷]N t zF~Shӝ ![F~Ȑ=$+ȴE[Ft@'/ 0/ٙedHt_;'v=H:eZ2Ѯ+@:tZel׳#HP2IЗg|-#Ӯhnd *`\2rWz2G Z22z&ݰ@:TL^/wG-hdUɮw=틚P)T`s2t>t \{]/+LG-i.d *tc7 ڕF;hHHʈvF'j]g=r/n#g;zHHH&WYހXu@}B֮6rbKȐ8Lb93i7 +t\󷑻 P :YO;o ~|G P*r@7 ` #vF.VFt }$+"wt|::W_`22@a>\zy^Ct``/ZtI09ɕ?臑M  &]VFt(J* + tC|HG-awQ ɕ"n*C:_wGI.@?:YO ~C#EggW(\vyl: ~wKyovV⃁^@;0]O<+"kǫ@G/C::22@&W:(ۈ݌ tx3:C-.(#C:S*k;:::!tUg!ʒ\Udy rF t坛]A:!9񈎯"K[;:u3:@'>~9n"WБU0loٖCyY[W,)tr4[U7$98~DN</t u(W\rf?v0a ހ22@)rt8#:]Ud uF''~'%(-+^*:?Qa0Io@t~K9tov9?q!t (s:WvU ䷮@g脁Nzc@:휠lo,g%"@#GyNr@:P9Zѱ3If{* ' hF'oҁt@Wn\It~r\,2˹  ;:<ܥ@I$WZDn +?<:CwMr.Udm[W|9?@T1S9T-P\9]rUd~^F[WYN?t@]ӡ)."ӄtV\" q=;:]@: Dz$p}AGws'W\Es]@:R+ݴz3jȁs\ :\X %W2W}:an t /ӎUO!hN\U\]A ۹@ykH۩@3%pοJ~aMjw@\EU}P֭5ɧ˓RN2C-zcqrȶ] uӥ6(kRDւui*Jd9"۹;:aL7A_@_Esd@Gxtdruյ8V];:@:FɲL*POia夝5_D}cw|r"UdZ@*&(w |;9TDȶ#r׹m\i91U5NY˔{ZY<0'j[sm\qJ@cJvy:NwPV8EdSV[|dո0Ǘss8gfqΎۂ/@\Ҭ*IH)$lR\.X< ߋ sJ;t对q\D>3iꅗ̸sU.OB:NR8id&˿ggzld*' s|<9,ן&t3 .J޹@IxD'UE@+t,卓MJ6^>EIw+ +~5srݷt݁'L:TБn9'Js&Wuә5NB8n5, VN/( kj%%deA+cԸsGG+W-t*+*'NGDMB6]GBOýSR9AjV_fsY.+Бuu,_}]Gt*21Ō +'M$/(IZ@zRi (eV>C;uڸ'rΡY΍+^+_y޹J&W@:A*i@8omox‧w˓O+hjܷm%{I9䑣ϤId[D -AdrQEt ֧rlqD8omh.|#z|ȓ𤼓__̧sH9ǶV]v<Fs?tYNx,tiHDZ +'M`go2 ?G#Owʖ+K}F90GR+-s[e:Ը +)" _ 3+Hiu +('Ϊb$|#a|vo9yzyx)w)ߖ&9Zr?[z6M8GWҸ5Oe.O v'W98,эƊ;wg| +H#Owr^=lPNvV5tq JKkWmfWs9/>8gNXD~ٰcɱn"1('4qp4"ptöרeVb~ L$aHGkYn\7caNZ[m5ݲ؃/tdr6uȼrt. t r +Y|KF\c#Ï?#aybDN^Y9W1 )+'s426:o?[ι8Gn9("ǣݙ\A:Jە rUEC, FD߆Uɀ +#" ̓OaOa"$ʶ s~Ԋ9ܶn]z~җfαrD"r8('Hq!N FDOUBQzV x';eews_{l2N`X99*H91434P㊋/'t9tڒb n8pQٰhV3N?A?!zy8р'{'C<e EiX3+ slS+*ض9nId] + :ݚ\A:mH*Qh'0 q$aF}#aٰh`~f9V~*b{zyx8ⱙVa$SѤlo'vGYI5DŽ9Zz.p9g 4r }RWD)@:NKS^9GVIᘌ#!IpoH7dv {fKFk>=6yL#OQd' e}ct#aՈd]w_N+"|=kpccb/V;>I\Y.i_ꨇv){Sf9Zm6S 9gN}+qѡ@iIwCAœ<帴jPc) UcԲz뭿0'GDQzLC1rP>nH7"2.뮻[^vgPO^槻J"g+Jy8RS{xw"~!Mp+ؒM=Wh1fVPyJ9ܶrΙ5'vϽb9(" NP6IlI5YAN`/ME87ܘІlC!Ǟ{^{6A6?1?' ~D>5g#'z''O>[_+DʡbgVa]+_ΑeW\snYx{94tPб@:On,PM2c|ú11!Րgg}ϰ?s 0> #LQ'Odygy *? )أ.'z +s~T͡0瀃Rϵιv6Q<\s H%IVQ<mI'1hZ'C87c#R I<蠃6C|{L;G=$$Zw~ηe!]D<zh߾}#w3C21!zO4x6I9f0Y\ɡjRPc#p7&߄6lH5~8# G EG2111lpl}rɀd!ɇ!h'ZA ?zzYm":kZHx+zص9N8ѧV\ѶՂk}ϊ@:D0'u.PU6o8gU8So(1!ِi=v;nРA=g >yBp%Z#Ǚǿ_k_ }- keԕ_cZbO}-|]fquqx# r$:C? skeS+NKȋヌ!sUP`t>tZ*͉/U:ů֣IL@Y'U&ġJ@@ DsIÆ >d)IgÇ7?' |LcC xpEM+ swuLje9\B9o9%tZ|aΗ0'XY Cy r۞ +d q(q!ݘdC9#F5jԩ"#GA2aǨ'0R- +xcww17hH<?}=OOrtu] ķjG~L0'O@R+*p Z<l΁t !'Vtʡ :lN;{R*dc\C=O3fęx駏M21!$QGCeZ&QR;.WIu?`I`/.D-HԳ2ձz#5̙rZ];󤄬r̷,s'8'H%+9~+:̯uM)Ѵj=("HC + 3ǎ7nYgup!|xر |z<x( Wlf {g geyX"|Ͻ. n{:p2I-m`EXJ}rgřՉGMaTkE9\ѶUwon/"N+R6J9~((nMA}콷7ΑGQJe0i&C!ՐcƏ?s'&G'ǓH?c=&1aP%'Z)l xV ,ǴV^Og=k+.V![x]WDRɜCsqYQE<6wye{O/f,HEOʝ-nu+9vs(:cmO9s|Ml9GsJ8rjd}9ǥV0?!9:?qLcR*c#2ͥ^vٌ3.7\\i}h~ve #|yBqa'ΖKzeYc~1G O'|yu{(Nɬ&L +sfR3օҵzЕsLo{e@:-CrVAYœ&:y)ߧ 2?Zv>yL5͊D<PU;v^yXBc/f{ӁEpl5n<uWd<3(̳ΡjE\zVshJ|a;99@:-EIR#=+~ߟrѼOOzBQsƙP!߈nm5$믟3g ̏zq|X=jx<9 Bφ1-Q_L!$O븧NAwڱ-r3y4* _qLjZiR+8N+Q9A׊*.OgO(> ?e(UU(oL&źِhΝ{M7l'̟?_}h~6w. Ca1$.dzw;h}gwų}LK^Og' _[T!^xWWd3~dYqfu9A#dZt-d9U;i%J8ǖske+A{2?uc gi9?cBpX86 نTÎ[n5,.\>4?c |n`PʥaP4?c |L32#?>5G_O7!sȟ v,}˾uRΫbL"HJ2[0uLjE i2sV\YCt& }:s'q4P:%/!qbÝb#;1|k'JLÉxw\ub䝾}9X +,[kZ<&o58p:%!݈lH4w}=̽DQyx4DKwG' rsОwEӒ״7gG[l>l +NAӡă8:Ac5+2+(̉RC>9y@:-B)%0 +kZI3?C4ߧIS/j̖)ېkX37<>4?c~=&19' xc- ;#p?]W1&1ي @lM"ӁpCvh[yUr*slj9ym+8' d:糁sZQYgsl?u()4‹/a㘤ʄ8R,Xhs;E7&1!ٰh|-G9C!pIst!+N<{wbcP}`TOt`xzf=RcǖN ~Eihfĩr@:-As>8Ǘslj +VR͡0ǽFop*T r.~WPơj}c ãc! Day8q$ZޡAG/?;,ǝ5Y=}pPb]cK_S/pfcOPVr/!9pN +vwʃ0'x[ 8l qT8Pt#!ٰg7RzѐG%Z;3;Gׅtxy=t+#Ot`|z%R%_QYl9ZA!䨜cKpNN P9A9ܵ7LïQrfO阛)h9̼nqsc نUci~bz<XhCVO8ǖsk/x6G9T@Q1Ա +c8ș5{ Uq$aG}C!وh5Ct~-Q#'P13+. k5VR΁s4bs\jFpJ}X\ij +rcc)e#y"G>X>2<x$3K;+no+1~~ + 9tJs>/E6{i聃()SPuNN(ՍU;Ļ>V=dP<$C,tޱ W<y_O7!'''Yd~:pl =V쯵cKԓ~EK#H1', KL@:$qrUL圭W~$Us(qQr8ȱu6pLJe#FeCby]#kvǘNJj<wg__O71J@;=5O  +x^x!wx^I؀]YO!cv}E'CrE#cKdV9 s@:#qi[q yM]+NS)̑(ϸ⪙/>BAQx8xռӏGͣTwd~.Ǩǽ_lsY~8rh>6?'Yt`xz%ʝD1-SE/0'#s2tFY9k#%䭶rԊfsNj s5嵳T9?$u}1!FuV'N>6zF@ >`gRYg3[R a+gV0)$RE{lVgPӊ~3eN|DB8Xㄾqkz<*"$YBz,ٳ;~Wx|@1t;?|<(og"tJח)w)9y@:!UI9G| Ys6ڄV,ΑԊfs|Ù"sa0 r|G#M3'!NIdg>%i{t)AA,ut9z5" 1NsJ;smE%d-HjuO/^)d{LL 8i'k@87lI>yx2z\X'mX=~1>PI55Yd}:PY 8ORN2BS!NS(Ѹs)9ǶJ9GS Λv%\r wB8X$e cœ3P<'mX=udd`gim*qʉ3+8 fPY89=(!gh5}N=)jؐg!=!z|~ؾNaWOs ?|-t cOAa8q}]rrάZiбwsVtNTΡK/(s{86ı‰tchY=֕x[/vR<,O.o]Ct'$ǩ +aN@:M 9\=o};-sl ٕs4ٜogœ ғw;6q18N8 |T{| 鏅W﵏izn_Og v,<oˬኽ.h[z&<9ŁtO"s ++(9Ҷ2skEhCmɻDDŽqR wt^I <m,9=Ŀ)"䳪p rrd( SIͮUd>'pʹm%d{S+~u9Kgi +VA8Id&> H{G&W@<Ǵz:';I5"%ؗJ-/} xl#$9ٙSHd&WaJ=5x&0vʹm9Ե2e_Cد9Ǚd'%x;A?x''1-RG^Oӗ{ v{4x['R`7DQ24REd7Cr9GjBVC9&愙UR9ߧ8edS>q A{G#!Oz:' 1y]EmyJyWOI ̩H+D򟬺֢[YΡV99RYȤV<}flIG q*MzBλ_ze%G/f g |ɽua%! VrjP :QYt9f8v/*hJfs4J99LT ;)ǴX=b֏(L<э{+<=Cb $~ETPJt+^~XͶt9 pۊsݺvLjEM+s4ɻ`$8*|ʋ';Mz'[<<^=/d@ s}]EJ7prW0@:$;_Dv:t}Ͷz;CΡ)974V +3Ϻj+P8eSF>a;A{LKs(J!?y=z;+B 򗌼 +ʩ)N)SБ׸Zm D츋>WҲm9qJiEa?X8&<9{;rRs9پ9灥#U:WN~N:ъ,?SH_bd 'q#UQ4UP"6xt,erFjsuN;9 [&uޞ(4I@9ui*rFr%rб-"S4LIEsVenķw_O #J÷.> +qK Ftɕ\ζ;kO*"Sj0?8+z)0' հh9OÈftxƁr&Wrtt_c v +5'Nv- uI缛pNPAsww'KAf"?( "g'W[ts8]\4~r-焩U4T;)'D +Jh&MS^YI-5@:jMIlACL+йj,u=WΡBvaN;լpO4?#g)@9ҩ;%yOhAsJtha>rs9- +'|-F 8[80NctN@'\g\m<c 63Q㊛4L$96ʬ4] d>i!"?p`zԛUd +^uwтϛF뮿݇IVJ,gOy8ҩ7n,P+ҋ'tCWS]D+s@ԋd,r\E-j&Wf'tl9l\}Wphm :Q];#:~jKݺ(бW9S9#tD\`]γ|FtC"r,d 9tCv^~Dw䊻&n?phi 9lE"&WNPDs@ԅr,-*r8#;WҹJu8 N= t褪Aruu\i<*fyz@ҩhJfUFre't,o-2t@vf[&2-x,0H[L踂NYZdԁܹT|-Jjy~ҩ=]|n{o*&WWԃJVȠtjO]-EO;Z*-Ot@:5\`.ѵm޹9hc%+8 Nl>9hoj^,rPEs&W("vҩ5vmۋqywЂsɕ햣 HT0.ȼ9.wIr\%NRP +H m\.Z$2-h,03BA Nm):m`9"3s +5Nmt+'+"_qM#:khg t21v9mZ?,U`DTrQҩ) \`]X9z!QEZUPҩ%%_QK/v.]DmS+ +.@Dv_s-*2+О@:5Dp/p=zWgd.P_`^H@Ԉ-@Wg@~wG߆r$WtjCO Wg\`]h"7/EtjCzGX] k :H&]2kp/0 /]vyNUn@:5wy@w=] +5N-Dt/0s.0.H@Ԁ {@dHty\ t <9x^/k.m]:Hzzsh.pH<\`j S5 VN,@콟#Ls{3ɹ@ATML>q/\` +PNT#l x\ ct "ҩ* . {\ t A'TGu {t  o? L" +SU/@ćy.0^\ 4 jĎ.M/@`.t*N5badҩ.@_f"0r]H +_K.@]:Hxb/@6=95ZXad@:=& .FtPEc]@a@:= 7btNMXC@πtzF 2 Q%X]#jq @W,@S z @tz 9N=ҩ,@PN`jt* TS)X* JUT HB@u@:ҩ ,@P%NE`jt* T S Xj +T H8X@:5)  Na@-tjS,@P ` HXF@:) N@̀tjS,@P; ` H + 4N0.@Fa ^SSl.0!si.pW@,Y8GH Lm1 4N{s a)3+:G@$T>). !"@kq,@܉F'H 4x׽X^tt\.^e PEJY:yױ@ҖҩfO>5w"{.5ӓUF>t +.@X{? <ٹ9\  h+ +^XIJ3 <.@Wz'is`vSđ~X t[.@,  @vҩ~" \@OI  X!tXZx0^adJI' ; .1m)Z,@\B{I YxdԐvNm bfVҩj"^x4wtXX##δt]J|Vt9#A:Ѯҩh" o\ @h#T1$Z 4NM nMݤS۰@Sh`ΠͤSD,@tE:XCh/T1 m",@)t@;CI 5m!,@9t@>AHf W`6ҩ,@wܘQÇ:ұm|`gXF! qdt$ԑ {'SH|ahc+#l -t.c>jAG2js#_|)rNAgW|to%_/: ~9=] +˯;V:6awo@m_4Vw:Zґ$ϼϟ<~#9Jg6ߘOWW~M_F@/RvEed/J&#g{'2nMcɮ+Hs:O?Æ7Cw^;tWI8*dsߝ _jwkIG:ԽPcc7+)99\qCty|8pN8n@CwD:gV:E:_t!ʮly=ɮ eWs/%#t2PZCƑqΡ*:]QIGW2OsfIWɛF^r@dX:8p~%ֱX|8F9[QoQ2ݵՑuL Ϟh]{ήid]d tУH+.@c/}ޟH9\1y7^{e(Zr c~4H%9`=D:YtdW]eWZV:TYkop#1IA( @4QΑ:O=nմ@2-̍t~VJ+_UH'ѻ*}zd tNw2_Yv;$@coCg~1ήX%+yEc:4|?hft>sm䲽7@&Ǟ\GvҡB\yYGcQG@]q_6Xy tlvE%rj$@D2Ig|IJXʮ@l t cՑ#saC:{age )P҉tlGҡ9qu:< ΫFa(oї| _pSO>n 'W\>yJZ:4ltRS:RGv:sp_Q1 vLCޡ<vHg˖q7y'avΝ/+/jt:[oAsӡ~{V-גu7#ҙ4t}y.PGOR!D!X^K$0ч>@ιcѭoLcÆhIҼfsNūӠysh J #.˯9k΍7S$Xd};Ox96y XQ#-}>v΂7xu\A$].xْo^1@rJ@'ռZ.~d.F:|$'7Tԙ}M#yp&yx;F<&!}1Ι8|.Ps|JSuCǸi֏,}21!&@>5\q2ʹm[tYiM֙GRsԻ슎ؒ#SǼc:CÁzQGwT{6:^rW^Cֹyoe,.#2Qqǃٻ7^>k߽b2h4=y$@9g!I +PX,I r2`  ^ﮟ9>?h_򭫗Ko?ɜo}׿>\it5rNWSW:+{}κ>s\~Gn8zmw{j0_V:e*Wo?K4%{jTHh_^NmrFN͟f׿W_KAs'>~GhW,&&:p|\pW]{7׏z2_5ΗAͿ/Kno%{F;0 wrͿKMa2\=ģw5r`Y,; BgU\|ٕ\Otw#?/֭o)֏~ӟ)CoOM)5kX?$"G?ͯ 22\=FY#_tjy3#/b#o8^ ?2 sο+Wus=V[ϔ/ R?,N~;&yKi30{W.?c5˟M.mwQ3.tpu]uk5W,tVx59^,u|u /kWMO?[S/kibG%w~Z$O_W%}j 7W/O~?a9W_gkSR+_No~;5w~<5z~?-?75p{ηY"/Ws/̹ܳ:\]s`SݧNLWV:|xQ43}as쎻ˀ%u{}k|ηj|/k?_?k axe)8_-]NϗϞ}̹ȵW_14_tY K.;̛NN;N>Sb|Wַ|O@VB~N͛o~5qyO?4s7겋ytWYA4GKiV XvgI2a=Tmv>E͝&xJ|7K|P;@͒6z͛7(=Ϋ_Kbmsxɜ/~茬UU:Y(t[w=հչʀuӭ%u}}6;nM|j|7>_Z@Tsˍ,͗+%q>W9O?YFOOj4 FgE:jʟ8j|5lu.ʫMqyA˯Eiy^}^ϗj ^{M /y VM<}m4̜ЩՁFg?]8t&.u)97ֵGjrws_mv{ɧ w^>D/RҧЫ@+\K/?{j3y&z>ϕkbjָ)N O?O>Xr>uwy??њ9_pg|贃eՍgWMWѥ|5huXe&uʄO\Fy;?1<= /y3K}ѫ\r-_x+yS穚8<ȹ妣7~G?Rf/8f`|hs՛jٽwz6;My=%wh$c?D '*zH\z)|K 灚8wQ9͹+/2[9|`_ W~tU5V:R~NASCI.ʫf[^rA|z>~%wnOI;K)~ f[Y.gwռMŭձ LϺr\ҦMɛ&p\\uEr.5~j d-]z3-is5oj\S49^\sjڜ.dN] 5:+6Cg||4`-=nvJ\pŗܹO<%z)oܰY5^Ϗմ%o$Nir.8jSF2YljtV|H݌XOS;]|I<%yfO >uKaKז# p..sy}%r6V̩ -RgVX#s?X63:ɝ2g.fϕ%}JT95쬽Ynh +J\vi85qjsƇ?DNmshu{a :kUk䭆 ZfZN֟~iv9};M\pa3pK5^r%5q>ȩۜS{I~z3":#U5uwrj;:;)Ϲw~ɞ>^T\ d嚖ZM &qN/sv96?Y9m6:<_muS xONv/ٻ93ϪS§O X~{Z쳚s q]rmsh'o[|Uue:BlԯY:uzXu;iO͟%-r' -3jܔ)8)UѪ~}rpYZ:`N\Jp6sJ;9xFO=5}j,9h[Yhih\#ns32\mY +խN3`:<43ȝA)SO@ f嶖;{ɛ8Y9ok2J :c7::õrꬍܩN ٳdO ?Zr[ W75oJg)q59iYJ0uFة3hxNU6=Miex7{Xf5oSgu䬓9FY,XZg9uV7;nNw=%|ih"7r%^rk?P Y6_j$su:ka4;M4C wj)SO?DF;6MԼS{8Ӵ9gΘΪY;`5w;ߩ3L=%{ɃhxGu}oA4- qfmk'9ǵ:#֪)pƪC0wj DOɞy v\¾M͛a4SaS':g9:6juFSgiZASsgV0rW'rL8uϝUs|]&/ęJs|쬓;#N]Zo83;#6ztƉ.t3Y;Y^'T"Y;% 8]s׏˂)ez6w>@GwO)FAH!ozql%yZ$rN;zh>,wfW|ƉܑD ۾ɑA ec/3H 0lي;N`l'=ܛo9 _O:G^}C{~/Կ^bv:t=7?xۻ|cϡ{_8r׿_?ݳ/o]>po9||OpO=:݋v;{ž{v(?^س߮_ 4=X{wY,?t۳k(6{,ߵws>k ڷ@1w{\?]Юܵ,.,-سX~v[~izz.^8@=.~ҕ_9\O=Ͻ|b};e}=yԏ<ݾ>[>G.ڋ]8m}[{ѓN_xY->Z~?ዲp+OOi<={mՃ7-WuY<| :|(?í|Y>z{cG?꡵b)Ko#/QIa4u;m?};[|A>أwr ^8Ҥ5 B~v:{6[{ʋucy{.(/hy?"oZ[~5){B4_u +endstream endobj 248 0 obj [/ICCBased 262 0 R] endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 165 0 obj <> endobj 166 0 obj <> endobj 217 0 obj [/View/Design] endobj 218 0 obj <>>> endobj 215 0 obj [/View/Design] endobj 216 0 obj <>>> endobj 137 0 obj [/View/Design] endobj 138 0 obj <>>> endobj 135 0 obj [/View/Design] endobj 136 0 obj <>>> endobj 133 0 obj [/View/Design] endobj 134 0 obj <>>> endobj 235 0 obj [234 0 R 233 0 R] endobj 300 0 obj <> endobj xref +0 301 +0000000004 65535 f +0000000016 00000 n +0000000234 00000 n +0000042338 00000 n +0000000005 00000 f +0000000006 00000 f +0000000010 00000 f +0001143087 00000 n +0001143162 00000 n +0001143234 00000 n +0000000012 00000 f +0000042390 00000 n +0000000013 00000 f +0000000014 00000 f +0000000015 00000 f +0000000016 00000 f +0000000017 00000 f +0000000018 00000 f +0000000019 00000 f +0000000020 00000 f +0000000021 00000 f +0000000022 00000 f +0000000023 00000 f +0000000024 00000 f +0000000025 00000 f +0000000026 00000 f +0000000027 00000 f +0000000028 00000 f +0000000029 00000 f +0000000030 00000 f +0000000031 00000 f +0000000032 00000 f +0000000033 00000 f +0000000034 00000 f +0000000035 00000 f +0000000036 00000 f +0000000037 00000 f +0000000038 00000 f +0000000039 00000 f +0000000040 00000 f +0000000041 00000 f +0000000042 00000 f +0000000043 00000 f +0000000044 00000 f +0000000045 00000 f +0000000046 00000 f +0000000047 00000 f +0000000048 00000 f +0000000049 00000 f +0000000050 00000 f +0000000051 00000 f +0000000052 00000 f +0000000053 00000 f +0000000054 00000 f +0000000055 00000 f +0000000056 00000 f +0000000057 00000 f +0000000058 00000 f +0000000059 00000 f +0000000060 00000 f +0000000061 00000 f +0000000062 00000 f +0000000063 00000 f +0000000064 00000 f +0000000065 00000 f +0000000066 00000 f +0000000067 00000 f +0000000068 00000 f +0000000069 00000 f +0000000070 00000 f +0000000071 00000 f +0000000072 00000 f +0000000073 00000 f +0000000074 00000 f +0000000075 00000 f +0000000076 00000 f +0000000077 00000 f +0000000078 00000 f +0000000079 00000 f +0000000080 00000 f +0000000081 00000 f +0000000082 00000 f +0000000083 00000 f +0000000084 00000 f +0000000085 00000 f +0000000086 00000 f +0000000087 00000 f +0000000088 00000 f +0000000089 00000 f +0000000090 00000 f +0000000091 00000 f +0000000092 00000 f +0000000093 00000 f +0000000094 00000 f +0000000095 00000 f +0000000096 00000 f +0000000097 00000 f +0000000098 00000 f +0000000099 00000 f +0000000100 00000 f +0000000101 00000 f +0000000102 00000 f +0000000103 00000 f +0000000104 00000 f +0000000105 00000 f +0000000106 00000 f +0000000107 00000 f +0000000108 00000 f +0000000109 00000 f +0000000110 00000 f +0000000111 00000 f +0000000112 00000 f +0000000113 00000 f +0000000114 00000 f +0000000115 00000 f +0000000116 00000 f +0000000117 00000 f +0000000118 00000 f +0000000119 00000 f +0000000120 00000 f +0000000121 00000 f +0000000122 00000 f +0000000123 00000 f +0000000124 00000 f +0000000125 00000 f +0000000126 00000 f +0000000127 00000 f +0000000128 00000 f +0000000129 00000 f +0000000130 00000 f +0000000131 00000 f +0000000132 00000 f +0000000139 00000 f +0001143941 00000 n +0001143973 00000 n +0001143823 00000 n +0001143855 00000 n +0001143705 00000 n +0001143737 00000 n +0000000140 00000 f +0000000141 00000 f +0000000142 00000 f +0000000143 00000 f +0000000144 00000 f +0000000145 00000 f +0000000146 00000 f +0000000147 00000 f +0000000148 00000 f +0000000149 00000 f +0000000150 00000 f +0000000151 00000 f +0000000152 00000 f +0000000153 00000 f +0000000154 00000 f +0000000155 00000 f +0000000156 00000 f +0000000157 00000 f +0000000158 00000 f +0000000159 00000 f +0000000160 00000 f +0000000161 00000 f +0000000162 00000 f +0000000163 00000 f +0000000164 00000 f +0000000000 00000 f +0001143318 00000 n +0001143395 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0001143587 00000 n +0001143619 00000 n +0001143469 00000 n +0001143501 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000537465 00000 n +0000537542 00000 n +0001144059 00000 n +0000042866 00000 n +0000044356 00000 n +0000538093 00000 n +0000047145 00000 n +0000047031 00000 n +0000537852 00000 n +0000537977 00000 n +0000045549 00000 n +0000045907 00000 n +0000046265 00000 n +0000046624 00000 n +0000044420 00000 n +0001143050 00000 n +0000044984 00000 n +0000045034 00000 n +0000369041 00000 n +0000052590 00000 n +0000455753 00000 n +0000369105 00000 n +0000215266 00000 n +0000294790 00000 n +0000215330 00000 n +0000047538 00000 n +0000133616 00000 n +0000047602 00000 n +0000046967 00000 n +0000047182 00000 n +0000052636 00000 n +0000133560 00000 n +0000133732 00000 n +0000133798 00000 n +0000133829 00000 n +0000134154 00000 n +0000215153 00000 n +0000134229 00000 n +0000221150 00000 n +0000294906 00000 n +0000294972 00000 n +0000295003 00000 n +0000295326 00000 n +0000295401 00000 n +0000374653 00000 n +0000455869 00000 n +0000455935 00000 n +0000455966 00000 n +0000456290 00000 n +0000456365 00000 n +0000537734 00000 n +0000537766 00000 n +0000537616 00000 n +0000537648 00000 n +0000538169 00000 n +0000538557 00000 n +0000539644 00000 n +0000547371 00000 n +0000612961 00000 n +0000618330 00000 n +0000683920 00000 n +0000749510 00000 n +0000815100 00000 n +0000880690 00000 n +0000946280 00000 n +0001011870 00000 n +0001077460 00000 n +0001144094 00000 n +trailer +<<358C9ABF7223AD4A95CC9945F0F51C2C>]>> +startxref +1144291 +%%EOF diff --git a/FlutterHelper/flutter_helper/ios/.gitignore b/FlutterHelper/flutter_helper/ios/.gitignore new file mode 100644 index 00000000..e96ef602 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/FlutterHelper/flutter_helper/ios/Flutter/AppFrameworkInfo.plist b/FlutterHelper/flutter_helper/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..f2872cf4 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/FlutterHelper/flutter_helper/ios/Flutter/Debug.xcconfig b/FlutterHelper/flutter_helper/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/FlutterHelper/flutter_helper/ios/Flutter/Release.xcconfig b/FlutterHelper/flutter_helper/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/FlutterHelper/flutter_helper/ios/Podfile b/FlutterHelper/flutter_helper/ios/Podfile new file mode 100644 index 00000000..1e8c3c90 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/FlutterHelper/flutter_helper/ios/Podfile.lock b/FlutterHelper/flutter_helper/ios/Podfile.lock new file mode 100644 index 00000000..71bda144 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Podfile.lock @@ -0,0 +1,135 @@ +PODS: + - audioplayers (0.0.1): + - Flutter + - DKImagePickerController/Core (4.3.2): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.2) + - DKImagePickerController/PhotoGallery (4.3.2): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.2) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - Flutter (1.0.0) + - flutter_keyboard_visibility (0.0.1): + - Flutter + - flutter_native_timezone (0.0.1): + - Flutter + - flutter_webview_plugin (0.0.1): + - Flutter + - fluttertoast (0.0.2): + - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - path_provider (0.0.1): + - Flutter + - SDWebImage (5.11.1): + - SDWebImage/Core (= 5.11.1) + - SDWebImage/Core (5.11.1) + - sensors (0.0.1): + - Flutter + - shared_preferences (0.0.1): + - Flutter + - sqflite (0.0.2): + - Flutter + - FMDB (>= 2.7.5) + - SwiftyGif (5.4.0) + - url_launcher (0.0.1): + - Flutter + +DEPENDENCIES: + - audioplayers (from `.symlinks/plugins/audioplayers/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - Flutter (from `Flutter`) + - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) + - flutter_native_timezone (from `.symlinks/plugins/flutter_native_timezone/ios`) + - flutter_webview_plugin (from `.symlinks/plugins/flutter_webview_plugin/ios`) + - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - path_provider (from `.symlinks/plugins/path_provider/ios`) + - sensors (from `.symlinks/plugins/sensors/ios`) + - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + +SPEC REPOS: + trunk: + - DKImagePickerController + - DKPhotoGallery + - FMDB + - SDWebImage + - SwiftyGif + +EXTERNAL SOURCES: + audioplayers: + :path: ".symlinks/plugins/audioplayers/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + Flutter: + :path: Flutter + flutter_keyboard_visibility: + :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" + flutter_native_timezone: + :path: ".symlinks/plugins/flutter_native_timezone/ios" + flutter_webview_plugin: + :path: ".symlinks/plugins/flutter_webview_plugin/ios" + fluttertoast: + :path: ".symlinks/plugins/fluttertoast/ios" + path_provider: + :path: ".symlinks/plugins/path_provider/ios" + sensors: + :path: ".symlinks/plugins/sensors/ios" + shared_preferences: + :path: ".symlinks/plugins/shared_preferences/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + url_launcher: + :path: ".symlinks/plugins/url_launcher/ios" + +SPEC CHECKSUMS: + audioplayers: 455322b54050b30ea4b1af7cd9e9d105f74efa8c + DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 + Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 + flutter_native_timezone: 5f05b2de06c9776b4cc70e1839f03de178394d22 + flutter_webview_plugin: ed9e8a6a96baf0c867e90e1bce2673913eeac694 + fluttertoast: b644586ef3b16f67fae9a1f8754cef6b2d6b634b + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d + sensors: 84eb7a30e47a649e4172b71d6e81be614c280336 + shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 + SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7 + url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + +PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c + +COCOAPODS: 1.9.3 diff --git a/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.pbxproj b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..0450c36c --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,594 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + A5F0F8A97FEC1C45A041A784 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3557BEC6B25D98D4249B8452 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1C9F33BDB1ABE411E283A41E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 3557BEC6B25D98D4249B8452 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7DB5AB6C119E6CACA194808F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 7FAF1BA14A58C5697F48B0E9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A5F0F8A97FEC1C45A041A784 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 022D813303DEFB21BD7242F7 /* Pods */ = { + isa = PBXGroup; + children = ( + 7DB5AB6C119E6CACA194808F /* Pods-Runner.debug.xcconfig */, + 7FAF1BA14A58C5697F48B0E9 /* Pods-Runner.release.xcconfig */, + 1C9F33BDB1ABE411E283A41E /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 5B3FB936E763051455921447 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3557BEC6B25D98D4249B8452 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 022D813303DEFB21BD7242F7 /* Pods */, + 5B3FB936E763051455921447 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 20691995DED9A3A117E57474 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + B5700427129F8E7BD65D9998 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 20691995DED9A3A117E57474 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + B5700427129F8E7BD65D9998 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework", + "${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework", + "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", + "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", + "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", + "${BUILT_PRODUCTS_DIR}/audioplayers/audioplayers.framework", + "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", + "${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework", + "${BUILT_PRODUCTS_DIR}/flutter_native_timezone/flutter_native_timezone.framework", + "${BUILT_PRODUCTS_DIR}/flutter_webview_plugin/flutter_webview_plugin.framework", + "${BUILT_PRODUCTS_DIR}/fluttertoast/fluttertoast.framework", + "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", + "${BUILT_PRODUCTS_DIR}/sensors/sensors.framework", + "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", + "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", + "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audioplayers.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_keyboard_visibility.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_native_timezone.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_webview_plugin.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/fluttertoast.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sensors.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterHelper; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterHelper; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterHelper; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..a28140cf --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/contents.xcworkspacedata b/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner/AppDelegate.swift b/FlutterHelper/flutter_helper/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..dc9ada47 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..28c6bf03 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..2ccbfd96 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..f091b6b0 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..4cde1211 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..d0ef06e7 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..dcdc2306 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..2ccbfd96 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..c8f9ed8f Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..a6d6b860 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..a6d6b860 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..75b2d164 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..c4df70d3 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..6a84f41e Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..d0e1f585 Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/ios/Runner/Base.lproj/LaunchScreen.storyboard b/FlutterHelper/flutter_helper/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner/Base.lproj/Main.storyboard b/FlutterHelper/flutter_helper/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner/Info.plist b/FlutterHelper/flutter_helper/ios/Runner/Info.plist new file mode 100644 index 00000000..b8f70ad9 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flutter_helper + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/FlutterHelper/flutter_helper/ios/Runner/Runner-Bridging-Header.h b/FlutterHelper/flutter_helper/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/FlutterHelper/flutter_helper/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/FlutterHelper/flutter_helper/l10n.yaml b/FlutterHelper/flutter_helper/l10n.yaml new file mode 100644 index 00000000..b522046b --- /dev/null +++ b/FlutterHelper/flutter_helper/l10n.yaml @@ -0,0 +1,3 @@ +arb-dir: lib/l10n +template-arb-file: intl_en.arb +output-localization-file: app_localizations.dart \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/inbox_animation.dart b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/inbox_animation.dart new file mode 100644 index 00000000..d5a3911b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/inbox_animation.dart @@ -0,0 +1,301 @@ +import 'package:flutter/material.dart'; +import 'model.dart'; +import 'package:flutter/services.dart'; +import 'widgets/icon_animation_widget.dart'; +import 'widgets/card_tile_widget.dart'; +import 'dart:convert'; + +class SlidingListAction extends StatefulWidget { + final Function updateMessageLength, selectedState; + SlidingListAction({this.updateMessageLength, this.selectedState}); + @override + _SlidingListActionState createState() => _SlidingListActionState(); +} + +class _SlidingListActionState extends State + with SingleTickerProviderStateMixin { + List listCardMessage; + double _headingBarHeight = 4.0; + double _buttonBarHeight = 0.0; + double cardHeight = 108; + List cards; + List brintToTapCardList; + double topPosition = 26; + double iconsTopPositionData; + // Icon Animation Bool + bool rightPositionData, + firstIconAnimationStartData, + secondIconAnimationStartData, + thirdIconAnimationStartData; + // List render + bool render; + // Remove index + int removeIndexData; + bool removeAnimation = false; + Map selectState = {}; + + Future> cardList() async { + String responseJson = await rootBundle.loadString('assets/data.json'); + List cards = json.decode(responseJson); + List listCard = + cards.map((card) => CardMessage.fromJson(card)).toList(); + return listCard; + } + + List _list; + + @override + void initState() { + super.initState(); + render = false; + rightPositionData = false; + firstIconAnimationStartData = false; + secondIconAnimationStartData = false; + thirdIconAnimationStartData = false; + iconsTopPositionData = 0.0; + getCardList(); + } + + // Card List + void getCardList() { + cardList().then( + (futureResultList) { + _list = futureResultList.map((card) { + topPosition = futureResultList.indexOf(card) == 0 + ? topPosition + : (topPosition + cardHeight); + + return CardTileWidget( + key: GlobalKey(), + id: card.id, + name: card.name, + avatar: card.avatar, + message: card.message, + time: card.time, + index: futureResultList.indexOf(card), + topPosition: topPosition, + iconsTopPosition: iconsTopPosition, + height: cardHeight, + blankCard: false, + bringToTop: bringToTop, + rightPosition: rightPosition, + firstIconPosition: firstIconPosition, + secondIconPosition: secondIconPosition, + thirdIconPosition: thirdIconPosition, + removeIndex: removeItemList, + removeAnimation: false, + selectedState: selectedState, + ); + }).toList(); + + // İlk boşluğu ekle + _list.add( + CardTileWidget( + index: (_list.length + 1), + blankCard: true, + topPosition: 0, + ), + ); + // Son boşluğu ekle + _list.add( + CardTileWidget( + index: (_list.length + 1), + blankCard: true, + topPosition: (topPosition + 108), + ), + ); + widget.updateMessageLength((_list.length - 2)); + setState(() {}); + }, + ); + } + + void rightPosition(bool data) { + setState(() { + rightPositionData = data; + }); + } + + void firstIconPosition(bool data) { + setState(() { + firstIconAnimationStartData = data; + }); + } + + void secondIconPosition(bool data) { + setState(() { + secondIconAnimationStartData = data; + }); + } + + void thirdIconPosition(bool data) { + setState(() { + thirdIconAnimationStartData = data; + }); + } + + void iconsTopPosition(double data) { + setState(() { + iconsTopPositionData = data; + }); + } + + void bringToTop(CardTileWidget widget) { + setState(() { + _list.remove(widget); + _list.add(widget); + }); + } + + void selectedState(Map val) { + setState(() { + selectState = val; + }); + } + + void removeItemList(int index) { + if (index != null) { + double removeItemTopPosition = + _list.where((item) => item.index == index).toList()[0].topPosition; + double newTopPosition = topPosition; + _list.removeWhere((item) => item.index == index); + _list = _list.map((card) { + if (card.topPosition < removeItemTopPosition) { + newTopPosition = card.topPosition; + removeAnimation = false; + } else { + newTopPosition = (card.topPosition - 108.0); + removeAnimation = true; + } + + if ((card.blankCard) && (newTopPosition != 0)) { + if (newTopPosition < (MediaQuery.of(context).size.height - 190)) { + return CardTileWidget( + key: GlobalKey(), + id: card.id, + name: card.name, + avatar: card.avatar, + message: card.message, + time: card.time, + index: card.index, + topPosition: 0, + iconsTopPosition: card.iconsTopPosition, + height: cardHeight, + blankCard: card.blankCard, + bringToTop: bringToTop, + rightPosition: rightPosition, + firstIconPosition: firstIconPosition, + secondIconPosition: secondIconPosition, + thirdIconPosition: thirdIconPosition, + removeIndex: removeItemList, + removeAnimation: removeAnimation, + selectedState: selectedState, + ); + } + } + + return CardTileWidget( + key: GlobalKey(), + id: card.id, + name: card.name, + avatar: card.avatar, + message: card.message, + time: card.time, + index: card.index, + topPosition: newTopPosition, + iconsTopPosition: card.iconsTopPosition, + height: cardHeight, + blankCard: card.blankCard, + bringToTop: bringToTop, + rightPosition: rightPosition, + firstIconPosition: firstIconPosition, + secondIconPosition: secondIconPosition, + thirdIconPosition: thirdIconPosition, + removeIndex: removeItemList, + removeAnimation: removeAnimation, + selectedState: selectedState, + ); + }).toList(); + widget.updateMessageLength((_list.length - 2)); + widget.selectedState(selectState); + setState(() { + topPosition = (topPosition - 108.0); + }); + } + } + + @override + Widget build(BuildContext context) { + double _totalHeight = + (topPosition + _headingBarHeight + _buttonBarHeight + cardHeight + 25); + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: _list == null + ? Center(child: CircularProgressIndicator()) + : Container( + height: _totalHeight < (MediaQuery.of(context).size.height - 190) + ? (MediaQuery.of(context).size.height - 190) + : _totalHeight, + color: Color(0xffF4F9FF), + child: Stack( + children: [ + //Person Card List + buildCardList(context), + // Animation Icons + IconAnimation( + leftPosition: -27.0, + topPosition: (iconsTopPositionData - 108.0), + rightAnimationStart: rightPositionData, + firstIconAnimationStart: firstIconAnimationStartData, + secondIconAnimationStart: secondIconAnimationStartData, + thirdIconAnimationStart: thirdIconAnimationStartData, + ), + ], + ), + ), + ); + } + + Container buildCardList(BuildContext context) { + return Container( + margin: EdgeInsets.only(top: 0.0), + width: MediaQuery.of(context).size.width, + child: Padding( + padding: EdgeInsets.only( + top: 0, + left: 0.0, + right: 0.0, + ), + child: Column( + children: [ + Expanded( + child: Container( + width: MediaQuery.of(context).size.width, + child: Stack( + children: _list.length == 2 + ? [ + CardTileWidget( + index: 0, + blankCard: true, + topPosition: 0, + ), + Align( + alignment: Alignment.center, + child: Text( + 'No Item', + style: TextStyle( + color: Colors.grey, + ), + ), + ) + ] + : _list, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/main.dart b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/main.dart new file mode 100755 index 00000000..1b00a1a5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/main.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'widgets/appbar_widget.dart'; +import 'inbox_animation.dart'; + +void main() => runApp( + AnimatedSelectionSlideApp(), + ); + +class AnimatedSelectionSlideApp extends StatelessWidget { + @override + Widget build(BuildContext context) => MaterialApp( + debugShowCheckedModeBanner: false, + title: 'App', + home: Scaffold( + appBar: buildAppBar(), + body: MainApp(), + ), + ); +} + +class MainApp extends StatefulWidget { + @override + _MainAppState createState() => _MainAppState(); +} + +class _MainAppState extends State { + // Bubble length state management + int messageLength; + String selectId; + int selectAction; + + void updateBubble(int val) { + setState(() { + messageLength = val; + }); + } + + // returns list id and action index + void selecetedState(Map val) { + setState(() { + selectId = val["list_id"]; + selectAction = val["select_action"]; + }); + String _action; + if (selectAction == 1) { + _action = 'favorites'; + } else if (selectAction == 2) { + _action = 'delete'; + } else if (selectAction == 3) { + _action = 'archive'; + } + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text('Selected action \"$_action\" for $selectId id number!'), + ), + ); + } + + @override + Widget build(BuildContext context) { + // print(selectId.toLowerCase() + ' --- ' + selectAction.toString()); + return SafeArea( + child: Column( + children: [ + // Message Text + buildHeadingBar(context), + // Inbox and Archive Button + buildButtonBar(context), + Expanded( + child: SlidingListAction( + selectedState: selecetedState, + updateMessageLength: updateBubble, + ), + ), + ], + ), + ); + } + + Widget buildBadge(int length) { + return Container( + decoration: BoxDecoration( + color: Colors.orange, + borderRadius: BorderRadius.circular(10), + ), + width: 20, + height: 20, + child: Center( + child: Text( + length.toString(), + style: TextStyle(color: Colors.white, fontSize: 11), + ), + ), + ); + } + + Container buildHeadingBar(BuildContext context) { + return Container( + height: 65.0, + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.only(left: 15.0, bottom: 20.0), + color: Colors.white, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Messages', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30.0), + ), + buildBadge(messageLength) + ], + ), + ); + } + + Container buildButtonBar(BuildContext context) { + return Container( + color: Colors.white, + height: 45.0, + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.only(left: 15.0, bottom: 0.0), + child: Row( + children: [ + Container( + child: Center( + child: Text( + 'Inbox', + style: TextStyle(color: Colors.white), + ), + ), + width: 80.0, + height: 32.0, + decoration: BoxDecoration(boxShadow: [ + BoxShadow(color: Colors.blue.withOpacity(0.7), blurRadius: 4.0) + ], color: Colors.blue, borderRadius: BorderRadius.circular(20.0)), + ), + SizedBox(width: 12.0), + Text( + 'Archive', + style: TextStyle(color: Colors.grey), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/model.dart b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/model.dart new file mode 100644 index 00000000..834f1760 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/model.dart @@ -0,0 +1,19 @@ +class CardMessage { + String id; + String avatar; + String name; + String message; + String time; + + CardMessage({this.id, this.avatar, this.name, this.message, this.time}); + + factory CardMessage.fromJson(Map json) { + return CardMessage( + id: json["id"], + avatar: json['avatar'], + name: json['name'], + message: json['message'], + time: json['time'], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/services.dart b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/services.dart new file mode 100644 index 00000000..b2a79d8e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/services.dart @@ -0,0 +1,13 @@ +import 'dart:convert'; +import 'model.dart'; +import 'package:flutter/services.dart'; + + + Future> cardList() async { + String responseJson = await rootBundle.loadString('assets/data.json'); + List cards = json.decode(responseJson); + List listCard = + cards.map((card) => CardMessage.fromJson(card)).toList(); + + return listCard; + } diff --git a/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/appbar_widget.dart b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/appbar_widget.dart new file mode 100644 index 00000000..5be78a49 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/appbar_widget.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +AppBar buildAppBar() { + return AppBar( + backgroundColor: Colors.white, + elevation: 0.0, + leading: IconButton( + color: Colors.black, + icon: Icon(Icons.arrow_back), + onPressed: () {}, + ), + actions: [ + IconButton( + color: Colors.black, + icon: Icon(Icons.search), + onPressed: () {}, + ), + IconButton( + color: Colors.black, + icon: Icon(Icons.more_horiz), + onPressed: () {}, + ), + ], + ); +} diff --git a/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/card_tile_widget.dart b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/card_tile_widget.dart new file mode 100644 index 00000000..fc619539 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/card_tile_widget.dart @@ -0,0 +1,440 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/gestures.dart'; + +import '../model.dart'; + +class CardTileWidget extends StatefulWidget { + final bool press; + final String avatar, name, message, time, id; + final int index; + final double topPosition, height; + final CardMessage list; + final bool blankCard, removeAnimation; + final Function bringToTop, + rightPosition, + firstIconPosition, + secondIconPosition, + thirdIconPosition, + iconsTopPosition, + removeIndex, + selectedState; + final Key key; + + CardTileWidget( + {this.key, + this.id, + this.avatar, + this.name, + this.message, + this.time, + this.press, + this.index, + this.removeIndex, + this.topPosition, + this.height, + this.list, + this.blankCard, + this.bringToTop, + this.rightPosition, + this.firstIconPosition, + this.secondIconPosition, + this.thirdIconPosition, + this.iconsTopPosition, + this.removeAnimation, + this.selectedState}); + + @override + _CardTileWidgetState createState() => _CardTileWidgetState(); +} + +class _CardTileWidgetState extends State + with TickerProviderStateMixin { + AnimationController controller, + controller2, + controller3, + opacityController, + controller4; + Animation xAnimation, + yAnimation, + yTopAnimation, + yBottomAnimation, + xAnimationTwo, + xNewAnimation, + xMaxAnimation, + xBackAnimation, + opacityAnimation, + slideAnimation; + + double xPositionOne = 0; + double xPositionTwo = 0; + double yNewPositionOne = 0; + bool onePositionEnd = false; + bool onePositionStart = false; + bool oneAnimationStart = false; + bool oneAnimationContinue = false; + bool animationXForce = false; + bool animationTop = false; + bool animationZero = true; + double yPosition; + int yAnimationAxis; + bool big100 = false; + bool backX = false; + bool pos, opacityVisible, remove; + int selectedState = 0; + + @override + void initState() { + super.initState(); + opacityVisible = true; + remove = false; + yPosition = widget.topPosition; + yAnimationAxis = 0; + + controller = + AnimationController(duration: Duration(milliseconds: 850), vsync: this); + opacityController = + AnimationController(duration: Duration(milliseconds: 500), vsync: this); + controller2 = + AnimationController(duration: Duration(milliseconds: 170), vsync: this); + controller3 = + AnimationController(duration: Duration(milliseconds: 170), vsync: this); + controller4 = + AnimationController(duration: Duration(milliseconds: 300), vsync: this); + + opacityAnimation = + Tween(begin: 1, end: 0).animate(opacityController) + ..addListener(() { + setState(() {}); + }) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + setState(() { + widget.removeIndex(widget.index); + }); + } + }); + + xMaxAnimation = Tween(begin: 100, end: 116).animate(controller2) + ..addListener(() { + setState(() {}); + }); + + xBackAnimation = Tween(begin: 100, end: 135).animate(controller3) + ..addListener(() { + setState(() { + if (xBackAnimation.value > 100) { + widget.secondIconPosition(true); + } else { + widget.secondIconPosition(false); + } + }); + }); + + yAnimation = Tween( + begin: widget.topPosition, end: (widget.topPosition - 16.0)) + .animate(controller2) + ..addListener(() { + setState(() { + if (animationTop) { + if (widget.topPosition > yAnimation.value) { + widget.thirdIconPosition(true); + } else { + widget.thirdIconPosition(false); + } + } + }); + }); + yBottomAnimation = Tween( + begin: widget.topPosition, end: (widget.topPosition + 16.0)) + .animate(controller2) + ..addListener(() { + setState(() { + if (!animationTop) { + if (widget.topPosition < yBottomAnimation.value) { + widget.firstIconPosition(true); + } else { + widget.firstIconPosition(false); + } + } + }); + }); + } + + @override + void dispose() { + controller.dispose(); + controller2.dispose(); + controller3.dispose(); + opacityController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + // Alt veya Üst boşluk döndür + if (widget.blankCard) { + return Positioned( + top: yPosition, + child: Container( + width: MediaQuery.of(context).size.width, + height: 25, + color: Colors.white, + ), + ); + } + + if (big100 && xPositionOne < 100) { + pos = true; + } else { + pos = false; + } + + xAnimation = Tween(begin: pos ? 100 : xPositionOne, end: 0) + .animate(CurvedAnimation(curve: Curves.ease, parent: controller)) + ..addListener(() { + setState(() { + // Icon Animation Pass + if (xAnimation.value > 95) { + widget.rightPosition(true); + } else if (onePositionEnd) { + widget.rightPosition(false); + } + if (xAnimation.value < 10) { + oneAnimationContinue = false; + } + }); + }) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + setState(() { + xPositionOne = 0; + big100 = false; + yPosition = widget.topPosition; + }); + } + }); + + double newPosition = xPositionOne >= 100 + ? (animationZero + ? widget.topPosition + : backX + ? widget.topPosition + : (animationTop ? yAnimation.value : yBottomAnimation.value)) + : backX + ? widget.topPosition + : (animationTop ? yAnimation.value : yBottomAnimation.value); + + if (widget.removeAnimation) controller4.forward(); + + slideAnimation = + Tween(begin: (newPosition + 108.0), end: newPosition) + .animate(controller4) + ..addListener(() { + setState(() {}); + }); + + return Positioned( + top: widget.removeAnimation ? slideAnimation.value : newPosition, + left: + (onePositionEnd ? xAnimation.value : (big100 ? 100 : xPositionOne)) <= + 100 + ? (onePositionEnd + ? xAnimation.value + : big100 + ? (backX ? xBackAnimation.value : xMaxAnimation.value) + : xPositionOne) + : (backX ? xBackAnimation.value : xMaxAnimation.value), + child: Opacity( + opacity: opacityAnimation.value, + child: GestureDetector( + onPanStart: (details) { + widget.bringToTop(widget); + widget.iconsTopPosition((widget.topPosition + 100 + 14)); + }, + onPanUpdate: (position) { + controller.reset(); + setState(() { + oneAnimationContinue = true; + oneAnimationStart = true; + onePositionEnd = false; + + if (position.delta.dx < 0) { + xPositionOne = 0.0; + } else { + xPositionOne += position.delta.dx; + } + + if (xPositionOne >= 100) { + big100 = true; + } + yPosition += position.delta.dy; + }); + + RenderBox box = context.findRenderObject(); + Offset local = box.globalToLocal(position.globalPosition); + + // Animation BackXTrue + if ((local.dx > 220.0) && + (local.dy > 0.0) && + (local.dy < 120) && + position.delta.dx > 1.3) { + controller3.forward(); + setState(() { + selectedState = 2; + remove = true; + backX = true; + }); + } + + // // Animation BackXFalse + if ((local.dx < 100.0) && + position.delta.dx < -2.0 && + position.delta.dx > -3.0 && + backX) { + controller3.reverse(); + setState(() { + backX = true; + animationTop = false; + remove = false; + selectedState = 0; + animationZero = false; + }); + } + + // Animation Top + if (local.dy < 0.0 && + position.delta.dy < -1.3 && + position.delta.dy > -2.3) { + controller2.forward(); + setState(() { + selectedState = 3; + remove = true; + animationTop = true; + animationZero = false; + backX = false; + }); + } + // Animation Center + if ((local.dy < 120 && local.dy > 0) && + (position.delta.dy < -1.3 || position.delta.dy > 1.3) && + !backX) { + controller2.reverse(); + setState(() { + selectedState = 0; + remove = false; + animationZero = false; + backX = false; + }); + } + // Animation Bottom + if (local.dy > 110 && + (position.delta.dy > 1.2 && position.delta.dy < 2.2)) { + controller2.forward(); + setState(() { + remove = true; + selectedState = 1; + animationTop = false; + yAnimationAxis = 1; + animationZero = false; + backX = false; + }); + } + widget.selectedState({ + "list_id": widget.id, + "select_action": selectedState, + }); + }, + onPanEnd: (details) { + controller.forward(); + controller2.reset(); + controller3.reset(); + setState(() { + if (remove) { + opacityVisible = false; + opacityController.forward(); + } + backX = false; + onePositionStart = false; + yAnimationAxis = 0; + animationZero = true; + onePositionEnd = true; + oneAnimationStart = false; + }); + }, + child: Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + child: Column( + children: [ + Container( + padding: EdgeInsets.only(left: 10), + decoration: oneAnimationContinue + ? BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + blurRadius: 8.0, + spreadRadius: 0.3, + color: Colors.black.withOpacity(0.2), + offset: Offset(0, 1), + ), + ], + borderRadius: BorderRadius.only( + topLeft: Radius.circular(3), + bottomLeft: Radius.circular(3), + ), + ) + : BoxDecoration( + color: Colors.white, + ), + child: Container( + height: (widget.height - 1), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ListTile( + leading: CircleAvatar( + backgroundColor: Colors.transparent, + backgroundImage: AssetImage(widget.avatar), + ), + title: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.name, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20.0), + ), + Text( + widget.time, + style: TextStyle( + color: Colors.grey, fontSize: 12.0), + ), + ], + ), + SizedBox(height: 8.0), + ], + ), + subtitle: Text( + widget.message, + ), + contentPadding: EdgeInsets.only( + top: 10.0, bottom: 10.0, left: 5.0, right: 10.0), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/icon_animation_widget.dart b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/icon_animation_widget.dart new file mode 100644 index 00000000..7ba3b146 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/animated_selection_slide/lib/widgets/icon_animation_widget.dart @@ -0,0 +1,307 @@ +import 'package:flutter/material.dart'; +import 'package:dotted_border/dotted_border.dart'; +import 'package:flutter_sequence_animation/flutter_sequence_animation.dart'; + +class IconAnimation extends StatefulWidget { + final double topPosition, leftPosition; + final bool rightAnimationStart, + firstIconAnimationStart, + secondIconAnimationStart, + thirdIconAnimationStart; + IconAnimation( + {this.topPosition, + this.leftPosition, + this.rightAnimationStart, + this.firstIconAnimationStart, + this.secondIconAnimationStart, + this.thirdIconAnimationStart}); + @override + _IconAnimationState createState() => _IconAnimationState(); +} + +class _IconAnimationState extends State + with TickerProviderStateMixin { + AnimationController _sequenceAnimationController, + _firstIconPositionAnimationController, + _secondIconPositionAnimationController, + _thirdIconPositionAnimationController; + Animation _firstIconPosition, _secondIconPosition, _thirdIconPosition; + SequenceAnimation _sequenceAnimation; + bool _rightAnimationIsCompleted = false; + // Total area width and height + double _iconContainerWidth = 120.0; + double _iconContainerHeight = 90.0; + // All icons circle size (width and height) + double _iconsCircleSize = 25.0; + // White icon size + double _whiteIconSize = 17.0; + + @override + void initState() { + super.initState(); + // First Animation Controller + _sequenceAnimationController = AnimationController(vsync: this); + _sequenceAnimation = SequenceAnimationBuilder() + .addAnimatable( + animatable: Tween(begin: 0.0, end: 34.0), + from: Duration.zero, + to: Duration(milliseconds: 80), + tag: 'star') + .addAnimatable( + animatable: Tween(begin: 0.0, end: 34.0), + from: Duration(milliseconds: 80), + to: Duration(milliseconds: 200), + tag: 'trash') + .addAnimatable( + animatable: Tween(begin: 0.0, end: 34.0), + from: Duration(milliseconds: 200), + to: Duration(milliseconds: 300), + tag: 'upload') + .animate(_sequenceAnimationController); + _sequenceAnimationController.addListener(() { + setState(() {}); + }); + _sequenceAnimationController.addStatusListener((status) { + if (status == AnimationStatus.completed) { + setState(() { + _rightAnimationIsCompleted = true; + }); + } + }); + + // Star Animation + _firstIconPositionAnimationController = AnimationController( + vsync: this, + duration: Duration( + milliseconds: 250, + ), + ); + + _firstIconPosition = + Tween(begin: Offset(34.0, 0.0), end: Offset(80.0, 32.0)) + .animate(_firstIconPositionAnimationController) + ..addListener(() { + setState(() {}); + }); + // Trash Animation + _secondIconPositionAnimationController = AnimationController( + vsync: this, + duration: Duration( + milliseconds: 250, + ), + ); + + _secondIconPosition = + Tween(begin: Offset(34.0, 32.0), end: Offset(80.0, 32.0)) + .animate(_secondIconPositionAnimationController) + ..addListener(() { + setState(() {}); + }); + // Upload Animation + _thirdIconPositionAnimationController = AnimationController( + vsync: this, + duration: Duration( + milliseconds: 250, + ), + ); + + _thirdIconPosition = + Tween(begin: Offset(34.0, 64.0), end: Offset(80.0, 32.0)) + .animate(_thirdIconPositionAnimationController) + ..addListener(() { + setState(() {}); + }); + } + + @override + void dispose() { + _sequenceAnimationController.dispose(); + _firstIconPositionAnimationController.dispose(); + _secondIconPositionAnimationController.dispose(); + _thirdIconPositionAnimationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + double _firstAnimationValueX = 0.0; + double _firstAnimationValueY; + double _secondAnimationValueX; + double _thirdAnimationValueX; + double _thirdAnimationValueY = 64.0; + + if (widget.rightAnimationStart) { + _sequenceAnimationController.forward(); + setState(() { + _firstAnimationValueX = _sequenceAnimation['star'].value; + _secondAnimationValueX = _sequenceAnimation['trash'].value; + _thirdAnimationValueX = _sequenceAnimation['upload'].value; + }); + + // Star Icon Animation + if (widget.firstIconAnimationStart) { + setState(() { + _firstIconPositionAnimationController.forward(); + _firstAnimationValueX = _firstIconPosition.value.dx; + _firstAnimationValueY = _firstIconPosition.value.dy; + }); + } else if (_rightAnimationIsCompleted && + !widget.firstIconAnimationStart) { + setState(() { + _firstIconPositionAnimationController.reverse(); + _firstAnimationValueX = _firstIconPosition.value.dx; + _firstAnimationValueY = _firstIconPosition.value.dy; + }); + } + + // Tash Icon Animation + if (widget.secondIconAnimationStart) { + setState(() { + _secondIconPositionAnimationController.forward(); + _secondAnimationValueX = _secondIconPosition.value.dx; + }); + } else if (_rightAnimationIsCompleted && + !widget.secondIconAnimationStart) { + setState(() { + _secondIconPositionAnimationController.reverse(); + _secondAnimationValueX = _secondIconPosition.value.dx; + }); + } + // Upload Icon Animation + if (widget.thirdIconAnimationStart) { + setState(() { + _thirdIconPositionAnimationController.forward(); + _thirdAnimationValueX = _thirdIconPosition.value.dx; + _thirdAnimationValueY = _thirdIconPosition.value.dy; + }); + } else if (_rightAnimationIsCompleted && + !widget.thirdIconAnimationStart) { + setState(() { + _thirdIconPositionAnimationController.reverse(); + _thirdAnimationValueX = _thirdIconPosition.value.dx; + _thirdAnimationValueY = _thirdIconPosition.value.dy; + }); + } + } else { + _sequenceAnimationController.reverse(); + _firstIconPositionAnimationController.reset(); + _secondIconPositionAnimationController.reset(); + _thirdIconPositionAnimationController.reset(); + setState(() { + _rightAnimationIsCompleted = false; + _firstAnimationValueX = _sequenceAnimation['star'].value; + _secondAnimationValueX = _sequenceAnimation['trash'].value; + _thirdAnimationValueX = _sequenceAnimation['upload'].value; + }); + } + + return Positioned( + left: widget.leftPosition, + top: widget.topPosition, + child: Container( + width: _iconContainerWidth, + height: _iconContainerHeight, + child: Stack( + children: [ + // Solid Circle + Positioned( + top: 32.0, + left: 80.0, + child: AnimatedOpacity( + duration: Duration(milliseconds: 100), + opacity: widget.rightAnimationStart ? 1 : 0, + child: DottedBorder( + color: Colors.grey, + padding: EdgeInsets.all(0.0), + borderType: BorderType.Circle, + child: Container( + width: _iconsCircleSize, + height: _iconsCircleSize, + ), + ), + ), + ), + // Star + Positioned( + top: _firstAnimationValueY, + left: _firstAnimationValueX, + child: Container( + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(15.0), + boxShadow: [ + BoxShadow( + color: Colors.blue.withOpacity(0.2), + blurRadius: 2.0, + spreadRadius: 1.5, + offset: Offset.zero, + ), + ], + ), + width: _iconsCircleSize, + height: _iconsCircleSize, + child: Icon( + Icons.star, + size: _whiteIconSize, + color: Colors.white, + ), + ), + ), + // Trash + Positioned( + top: 32.0, + left: _secondAnimationValueX, + child: Container( + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(15.0), + boxShadow: [ + BoxShadow( + color: Colors.red.withOpacity(0.2), + blurRadius: 1.0, + spreadRadius: 1.5, + offset: Offset.zero, + ), + ], + ), + width: _iconsCircleSize, + height: _iconsCircleSize, + child: Icon( + Icons.delete_outline, + size: _whiteIconSize, + color: Colors.white, + ), + ), + ), + // Upload + Positioned( + top: _thirdAnimationValueY, + left: _thirdAnimationValueX, + child: Container( + decoration: BoxDecoration( + color: Color(0xff4A4B68), + borderRadius: BorderRadius.circular(15.0), + boxShadow: [ + BoxShadow( + color: Color(0xff4A4B68).withOpacity(0.2), + blurRadius: 2.0, + spreadRadius: 1.5, + offset: Offset.zero, + ), + ], + ), + width: _iconsCircleSize, + height: _iconsCircleSize, + child: Icon( + Icons.file_upload, + size: _whiteIconSize, + color: Colors.white, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/base_app.dart b/FlutterHelper/flutter_helper/lib/base_app.dart new file mode 100644 index 00000000..078f58f8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/base_app.dart @@ -0,0 +1,12 @@ +import 'package:flutter/cupertino.dart'; + +abstract class BaseApp extends StatelessWidget { + final String name; + final String imageName; + + const BaseApp({Key key, this.name, this.imageName}) : super(key: key); + + BaseApp.withNames(this.name, this.imageName) { + print('$name - $imageName'); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/boss_app.dart b/FlutterHelper/flutter_helper/lib/boss/boss_app.dart new file mode 100644 index 00000000..3d20cf76 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/boss_app.dart @@ -0,0 +1,23 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/base_app.dart'; +import 'package:flutter_helper/boss/splash.dart'; + +class BossApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData( + primaryIconTheme: IconThemeData(color: Colors.white), + brightness: Brightness.light, + primaryColor: Color.fromARGB(255, 0, 215, 198), + accentColor: Colors.cyan[300]), + home: Scaffold( + appBar: AppBar( + title: Text("BossApp"), + ), + body: SplashPage(), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/chat/chat_page.dart b/FlutterHelper/flutter_helper/lib/boss/chat/chat_page.dart new file mode 100644 index 00000000..42db3a77 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/chat/chat_page.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +class ChatPage extends StatefulWidget { + @override + _ChatPageState createState() => _ChatPageState(); +} + +class _ChatPageState extends State + with AutomaticKeepAliveClientMixin { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 0.0, + centerTitle: true, + title: Text( + '聊 天', + style: TextStyle( + fontSize: 20.0, + color: Colors.white, + ), + ), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '暂无消息', + style: TextStyle( + color: Colors.grey, + fontSize: 26.0, + ), + ), + ], + ), + ), + ); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/FlutterHelper/flutter_helper/lib/boss/company/company.dart b/FlutterHelper/flutter_helper/lib/boss/company/company.dart new file mode 100644 index 00000000..b3586a23 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/company/company.dart @@ -0,0 +1,18 @@ +class Company { + final String id; + final String company; + final String logo; + final String info; + final String hot; + + Company({this.id, this.company, this.logo, this.info, this.hot}); + + factory Company.fromJson(Map json) { + return Company( + id: json['id'], + company: json['company'], + logo: json['logo'], + info: json['info'], + hot: json['hot']); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/company/company_detail.dart b/FlutterHelper/flutter_helper/lib/boss/company/company_detail.dart new file mode 100644 index 00000000..00d59237 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/company/company_detail.dart @@ -0,0 +1,14 @@ +class CompanyDetail { + final String id; + final String inc; + final List companyImgsResult; + + CompanyDetail({this.id, this.inc, this.companyImgsResult}); + + factory CompanyDetail.fromJson(Map json) { + return CompanyDetail( + id: json['id'], + inc: json['inc'], + companyImgsResult: json['companyImgsResult'] as List); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/boss/company/company_item.dart b/FlutterHelper/flutter_helper/lib/boss/company/company_item.dart new file mode 100644 index 00000000..4891e08f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/company/company_item.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'company.dart'; + +class CompanyItem extends StatelessWidget { + final Company company; + final String heroLogo; + VoidCallback onPressed; + + CompanyItem({Key key, this.company, this.heroLogo, this.onPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: Container( + margin: EdgeInsets.only(bottom: 10.0), + padding: EdgeInsets.fromLTRB(18.0, 10.0, 18.0, 10.0), + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 20.0), + child: Hero( + tag: heroLogo, + child: Image.network( + company.logo, + width: 40, + ), + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 6.0), + child: Text( + company.company, + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), + ), + ), + Text( + company.info, + style: TextStyle( + color: Colors.grey, + fontSize: 12, + ), + ) + ], + ), + ], + ), + Container( + decoration: BoxDecoration( + color: new Color(0xFFF6F6F8), + borderRadius: BorderRadius.all(Radius.circular(6.0)), + ), + padding: EdgeInsets.fromLTRB(3.0, 3.0, 8.0, 8.0), + margin: EdgeInsets.only(top: 12.0), + child: Text( + company.hot, + style: TextStyle(color: Color(0xFF9fa3b0)), + ), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/company/company_page.dart b/FlutterHelper/flutter_helper/lib/boss/company/company_page.dart new file mode 100644 index 00000000..016da501 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/company/company_page.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/company/company.dart'; +import 'package:flutter_helper/boss/company/company_item.dart'; + +import 'company_page_detail.dart'; + +class CompanyPage extends StatefulWidget { + @override + _CompanyPageState createState() => _CompanyPageState(); +} + +class _CompanyPageState extends State + with AutomaticKeepAliveClientMixin { + Future> _fetchCompanyList() async { + List companyList = []; + for (int i = 0; i < 100; i++) { + companyList.add(Company( + id: "$i", + company: "科大讯飞$i", + logo: + "https://img.bosszhipin.com/beijin/mcs/useravatar/20171211/4d147d8bb3e2a3478e20b50ad614f4d02062e3aec7ce2519b427d24a3f300d68_s.jpg", + info: "已经上市移动互联网", + hot: "热🔥招:高级测试工程师 15k-18k", + )); + } + return companyList; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 0.0, + centerTitle: true, + title: Text( + '公 司', + style: TextStyle(fontSize: 20.0, color: Colors.white), + ), + actions: [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.search, + color: Colors.white, + ), + ), + ], + ), + body: Center( + child: FutureBuilder( + future: _fetchCompanyList(), + builder: (context, snapshot) { + if (ConnectionState.none == snapshot.connectionState || + ConnectionState.waiting == snapshot.connectionState) { + return CircularProgressIndicator(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return _createListView(context, snapshot); + } + }, + ), + ), + ); + } + + @override + bool get wantKeepAlive => true; + + Widget _createListView( + BuildContext context, AsyncSnapshot snapshot) { + List companyList = snapshot.data; + return ListView.builder( + key: new PageStorageKey('company-list'), + itemCount: companyList.length, + itemBuilder: (BuildContext context, int index) { + return CompanyItem( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + // fullscreenDialog: true, + builder: (context) => CompanyDetailPage( + company: companyList[index], + heroLogo: "heroLogo$index", + ), + ), + ); + }, + company: companyList[index], + heroLogo: "heroLogo${index}", + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/company/company_page_detail.dart b/FlutterHelper/flutter_helper/lib/boss/company/company_page_detail.dart new file mode 100644 index 00000000..7cf08579 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/company/company_page_detail.dart @@ -0,0 +1,381 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/company/company.dart'; +import 'package:flutter_helper/boss/company/company_detail.dart'; +import 'package:flutter_helper/boss/company/scroll_img_item.dart'; +import 'package:flutter_helper/boss/company/welfare_item.dart'; + +import 'gallery_page.dart'; + +class CompanyDetailPage extends StatefulWidget { + final Company company; + final String heroLogo; + + const CompanyDetailPage({Key key, this.company, this.heroLogo}) + : super(key: key); + + @override + State createState() => _CompanyDetailPageState(); +} + +class _CompanyDetailPageState extends State + with SingleTickerProviderStateMixin { + ScrollController _scrollController; + bool _isShow = false; + + Future _fetchCompan() async { + return CompanyDetail( + id: "id", + inc: "无锡红光标牌有限公司是一家集研发、生产、销售和服务于一体的专业标牌生产厂家。注册资金500万人民币。主要生产塑料基材、软塑透明树脂、金属、模内复合等标牌产品,洗衣机顶盖板总成,平衡板,以及塑印、彩印、顶盖板、吸音垫等产品。公司位于长江三角洲经济快速增长、风景秀丽的太湖之畔——无锡。 公司自1984年成立至今,已经过了3次跨越式的发展。2004年至今公司投入5000多万元资金建设新的生产基地,目前已竣工并投入生产,占地面积达40000m2,厂房面积近15000m2。公司2004年的年产值达4350多万元,并且每年以平均30%的速度快速增长。目前,本公司的产品已具备国际及国内多项质量认证证书,并为知名家用电器企业:小天鹅电器有限公司、三星电子有限公司、海尔集团、惠尔普等配套生产各类标牌。可以说客户是我们的老师,和他们合作使我们得到很多的学习机会来提高自身的技术水平和管理水平,是我们生产和发展的动力。 公司本着“千方百计生产出满足顾客期望和要求的产品”的宗旨,坚持“工厂出产的不仅仅是产品,更重要的是信誉和质量”的经营理念,不断吸收新技术、引进新设备,使公司的经济效益蒸蒸日上。相信公司将会永不停止探索和发展的脚步,和中国国内以及世界国际性大公司同步发展。", + companyImgsResult: [ + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F017b2a5938c8bca8012193a37db72c.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1630492567&t=e72260aeba623b96fafb25502781e504', + ], + ); + } + + _scrollListener() { + setState(() { + if (_scrollController.offset < 56 && _isShow) { + _isShow = false; + } else if (_scrollController.offset >= 56 && _isShow == false) { + _isShow = true; + } + }); + } + + @override + void initState() { + _scrollController = ScrollController(); + _scrollController.addListener(_scrollListener); + super.initState(); + } + + @override + void dispose() { + _scrollController.removeListener(_scrollListener); + _scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: Scaffold( + backgroundColor: Color.fromARGB(255, 68, 76, 96), + body: Container( + decoration: BoxDecoration( + image: DecorationImage( + colorFilter: ColorFilter.mode( + Colors.black.withOpacity(0.1), + BlendMode.dstATop, + ), + fit: BoxFit.cover, + image: NetworkImage(widget.company.logo), + alignment: Alignment.center, + ), + ), + child: _companyDetailView(context), + ), + ), + ); + } + + _companyDetailView(BuildContext context) { + return Stack( + alignment: Alignment.bottomCenter, + children: [ + CustomScrollView( + controller: _scrollController, + slivers: [ + _buildSliverAppBar(), + _buildSliverList(), + ], + ), + ], + ); + } + + Widget _buildSliverAppBar() { + return SliverAppBar( + elevation: 0.0, + pinned: true, + backgroundColor: Color.fromARGB(_isShow ? 255 : 0, 68, 76, 96), + centerTitle: false, + title: Text( + widget.company.company, + style: TextStyle( + fontSize: 20.0, + color: Color.fromARGB(_isShow ? 255 : 0, 255, 255, 255), + ), + ), + actions: [ + IconButton( + onPressed: () {}, + icon: Icon( + Icons.search, + color: Colors.white, + )) + ], + ); + } + + Widget _buildSliverList() { + return SliverList( + delegate: SliverChildListDelegate( + [ + Row( + children: [ + Expanded( + flex: 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + top: 20.0, + left: 25.0, + bottom: 10.0, + ), + child: Text( + '${widget.company.company}', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 25.0, + ), + ), + ), + Padding( + padding: EdgeInsets.only(left: 25.0), + child: Text( + '${widget.company.info}', + style: TextStyle( + color: Colors.white, + fontSize: 25.0, + ), + ), + ), + ], + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.only( + top: 25.0, + right: 30.0, + ), + child: Hero( + tag: widget.heroLogo, + child: ClipRRect( + borderRadius: BorderRadius.circular(8.0), + child: Image.network( + widget.company.logo, + width: 70, + height: 70, + ), + ), + ), + ), + ), + ], + ), + FutureBuilder( + future: _fetchCompan(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return _companBody(context, snapshot); + } else if (snapshot.hasError) { + return Text('${snapshot.error}'); + } else { + return Center( + child: CircularProgressIndicator(), + ); + } + }, + ), + ], + ), + ); + } + + // 主体 + Widget _companBody( + BuildContext context, AsyncSnapshot snapshot) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 30.0, left: 25.0, right: 20.0), + child: _craeteWorkHours(), + ), + _createWelfareItem(), + Padding( + padding: EdgeInsets.only(left: 25.0, bottom: 20.0), + child: Text( + '公司介绍', + style: TextStyle( + color: Colors.white, + fontSize: 20.0, + ), + ), + ), + Padding( + padding: EdgeInsets.only(left: 25.0, bottom: 10.0, right: 25.0), + child: Text( + snapshot.data.inc, + textAlign: TextAlign.justify, + style: TextStyle( + color: Colors.white, + fontSize: 16.0, + ), + ), + ), + Padding( + padding: EdgeInsets.only(top: 20.0, left: 25.0, bottom: 10.0), + child: Text( + "公司照片", + style: new TextStyle(color: Colors.white, fontSize: 20.0), + ), + ), + Container( + margin: + EdgeInsets.only(left: 20.0, top: 20.0, right: 0.0, bottom: 50.0), + height: 120.0, + child: _createImgList(context, snapshot), + ) + ], + ); + } + + // 上班时间 + Widget _craeteWorkHours() { + return Wrap( + spacing: 40.0, + runSpacing: 16.0, + direction: Axis.horizontal, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.access_alarm, + color: Colors.white, + size: 18.0, + ), + Padding( + padding: EdgeInsets.only(right: 6.0), + ), + Text( + '下午1:00-下午10:00', + style: new TextStyle(color: Colors.white, fontSize: 16.0), + ), + ], + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.account_balance_wallet, + color: Colors.white, + size: 18.0, + ), + Padding( + padding: EdgeInsets.only(right: 6.0), + ), + Text( + '大小周', + style: new TextStyle(color: Colors.white, fontSize: 16.0), + ), + ], + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.movie, + color: Colors.white, + size: 18.0, + ), + Padding( + padding: EdgeInsets.only(right: 6.0), + ), + Text( + '偶尔加班', + style: new TextStyle(color: Colors.white, fontSize: 16.0), + ), + ], + ), + ], + ); + } + + // 公司福利 + Widget _createWelfareItem() { + return Padding( + padding: const EdgeInsets.only( + top: 30.0, + bottom: 10.0, + ), + child: Container( + margin: EdgeInsets.only(left: 20.0, top: 0.0, right: 0.0, bottom: 20.0), + height: 120.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + WelfareItem(iconData: Icons.flip, title: "五险一金"), + WelfareItem(iconData: Icons.security, title: "补充医疗\n保险"), + WelfareItem(iconData: Icons.access_alarm, title: "定期体检"), + WelfareItem(iconData: Icons.face, title: "年终奖"), + WelfareItem(iconData: Icons.brightness_5, title: "带薪年假"), + ], + ), + ), + ); + } + + // 公司照片 + // 公司照片 + Widget _createImgList(BuildContext context, AsyncSnapshot snapshot) { + List imgList = snapshot.data.companyImgsResult; + return ListView.builder( + key: PageStorageKey('img-list'), + scrollDirection: Axis.horizontal, + itemCount: imgList.length, + itemBuilder: (BuildContext context, int index) { + return ScrollImageItem( + url: imgList[index], + heroTag: 'heroTag$index', + onPressed: () { + Navigator.of(context).push( + PageRouteBuilder( + pageBuilder: (BuildContext context, + Animation animation, + Animation secondaryAnimation) { + return AnimatedBuilder( + animation: animation, + builder: (BuildContext context, Widget child) { + return Opacity( + opacity: animation.value, + child: GalleryPage( + url: imgList[index], + heroTag: 'heroTag$index', + ), + ); + }); + }, + transitionDuration: Duration(milliseconds: 300), + ), + ); + }, + ); + }); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/company/gallery_page.dart b/FlutterHelper/flutter_helper/lib/boss/company/gallery_page.dart new file mode 100644 index 00000000..77bca7de --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/company/gallery_page.dart @@ -0,0 +1,40 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class GalleryPage extends StatelessWidget { + final String url; + final String heroTag; + + const GalleryPage({Key key, this.url, this.heroTag}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color.fromARGB(100, 0, 0, 0), + appBar: AppBar( + backgroundColor: Color.fromARGB(100, 0, 0, 0), + ), + body: Padding( + padding: EdgeInsets.all(30.0), + child: Stack( + children: [ + Align( + alignment: Alignment(0, -0.2), + child: Hero( + tag: heroTag, + child: Container( + width: MediaQuery.of(context).size.width, + child: Image.network( + url, + width: 300, + fit: BoxFit.cover, + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/company/scroll_img_item.dart b/FlutterHelper/flutter_helper/lib/boss/company/scroll_img_item.dart new file mode 100644 index 00000000..b431a237 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/company/scroll_img_item.dart @@ -0,0 +1,31 @@ +import 'package:flutter/cupertino.dart'; + +class ScrollImageItem extends StatelessWidget { + final String url; + final String heroTag; + VoidCallback onPressed; + + ScrollImageItem({Key key, this.url, this.heroTag, this.onPressed}) : super(key: + key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: Hero( + tag: heroTag, + child: Container( + margin: EdgeInsets.only(right: 20.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(8.0), + child: Image.network( + url, + width: 300, + fit: BoxFit.cover, + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/company/welfare_item.dart b/FlutterHelper/flutter_helper/lib/boss/company/welfare_item.dart new file mode 100644 index 00000000..b2aa9a9a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/company/welfare_item.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +class WelfareItem extends StatelessWidget { + WelfareItem({Key key, this.iconData, this.title}) : super(key: key); + + final IconData iconData; + final String title; + + @override + Widget build(BuildContext context) { + return Container( + width: 100.0, + height: 120.0, + alignment: Alignment.centerLeft, + padding: EdgeInsets.all(12.0), + margin: EdgeInsets.symmetric(horizontal: 6.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.0)), + border: Border.all( + color: Colors.white, + width: 0.25, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon( + iconData, + color: Colors.white, + size: 32.0, + ), + Padding( + padding: EdgeInsets.only(top: 8.0), + ), + Text( + title, + style: new TextStyle(color: Colors.white, fontSize: 18.0), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/job/job.dart b/FlutterHelper/flutter_helper/lib/boss/job/job.dart new file mode 100644 index 00000000..1de59202 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/job/job.dart @@ -0,0 +1,32 @@ +class Job { + final String id; + final String title; + final String salary; + final String company; + final String info; + final String category; + final String head; + final String publish; + + Job( + {this.id, + this.title, + this.salary, + this.company, + this.info, + this.category, + this.head, + this.publish}); + + factory Job.fromJson(Map json) { + return Job( + title: json['title'], + salary: json['salary'], + company: json['company'], + info: json['info'], + category: json['category'], + head: json['head'], + publish: json['publish'], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/job/job_item.dart b/FlutterHelper/flutter_helper/lib/boss/job/job_item.dart new file mode 100644 index 00000000..ea963308 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/job/job_item.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; + +import 'job.dart'; + +class JobItem extends StatelessWidget { + final Job job; + VoidCallback onPressed; + + JobItem({Key key, this.job, this.onPressed}) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: Container( + margin: EdgeInsets.only(bottom: 10.0), + padding: EdgeInsets.fromLTRB(18.0, 10.0, 18.0, 10.0), + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Expanded( + child: Text( + job.title, + style: TextStyle(color: Colors.black, fontSize: 16), + ), + ), + Text( + job.salary, + style: TextStyle( + color: Colors.black, + fontSize: 16, + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(top: 8.0), + child: Text(job.company), + ), + Container( + decoration: BoxDecoration( + color: Color(0xFFF6F6F8), + borderRadius: BorderRadius.all(Radius.circular(6.0)), + ), + padding: EdgeInsets.fromLTRB(3.0, 3.0, 8.0, 8.0), + child: Text( + job.info, + style: TextStyle(color: Color(0xFF9fa3b0)), + ), + ), + Row( + children: [ + CircleAvatar( + backgroundImage: NetworkImage('https://img.bosszhipin.com/beijin/mcs/useravatar/20171211/4d147d8bb3e2a3478e20b50ad614f4d02062e3aec7ce2519b427d24a3f300d68_s.jpg'), + radius: 15, + ), + Padding( + padding: EdgeInsets.only(left: 8.0), + child: Text(job.publish), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/job/job_page.dart b/FlutterHelper/flutter_helper/lib/boss/job/job_page.dart new file mode 100644 index 00000000..9ee212a6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/job/job_page.dart @@ -0,0 +1,85 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/job/job_item.dart'; +import 'package:flutter_helper/boss/utils.dart'; + +import 'job.dart'; + +class JobPage extends StatefulWidget { + @override + _JobPageState createState() => _JobPageState(); +} + +class _JobPageState extends State with AutomaticKeepAliveClientMixin { + List listJobs = []; + + Future> _fetchJobList() async { + for (int i = 0; i < 100; i++) { + listJobs.add(Job( + id: "id", + title: "开发工程师", + salary: "10K-20K", + company: "EYE公司", + info: "Stemcor 於 1951 年在倫敦成立,乃國際化的鋼材貿易商、分銷商和儲存商。 作為私營公司,我們是獨立的貿易商,表示本公司不屬任何鋼鐵生產商所有,也不控制任何鋼鐵生產商。。", + category: "category", + head: "http://img0.baidu.com/it/u=3311900507,1448170316&fm=26&fmt=auto&gp=0.jpg", + publish: "发布于12月31日")); + } + // sleep(Duration(milliseconds: 3000)); + return listJobs; + } + + @override + Widget build(BuildContext context) { + return Center( + child: Scaffold( + appBar: AppBar( + elevation: 0.0, + centerTitle: true, + title: Text( + '职位', + style: TextStyle( + fontSize: 20.0, + color: Colors.white, + ), + ), + ), + body: Center( + child: FutureBuilder( + future: _fetchJobList(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.none || + snapshot.connectionState == ConnectionState.waiting) { + return CircularProgressIndicator(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return _createListView(context, snapshot); + } + }, + ), + ), + ), + ); + } + + Widget _createListView(BuildContext context, AsyncSnapshot snapshot) { + List jobList = snapshot.data; + return ListView.builder( + key: PageStorageKey('job-list'), + itemCount: jobList.length, + itemBuilder: (BuildContext context, int index) { + return JobItem( + onPressed: () { + showToast(jobList[index].toString()); + }, + job: jobList[index], + ); + }, + ); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/FlutterHelper/flutter_helper/lib/boss/layout_type.dart b/FlutterHelper/flutter_helper/lib/boss/layout_type.dart new file mode 100644 index 00000000..e6b2fcf7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/layout_type.dart @@ -0,0 +1,22 @@ +import 'package:flutter/foundation.dart'; + +abstract class HasLayoutGroup { + VoidCallback get onLayouttoggle; +} + +enum LayoutType { job, company, chat, mine } + +String layoutName(LayoutType layoutType) { + switch (layoutType) { + case LayoutType.job: + return '职位'; + case LayoutType.company: + return '公司'; + case LayoutType.chat: + return '消息'; + case LayoutType.mine: + return '我的'; + default: + return ''; + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/mainpage.dart b/FlutterHelper/flutter_helper/lib/boss/mainpage.dart new file mode 100644 index 00000000..1a9ea085 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/mainpage.dart @@ -0,0 +1,122 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/chat/chat_page.dart'; +import 'package:flutter_helper/boss/company/company_page.dart'; +import 'package:flutter_helper/boss/job/job_page.dart'; +import 'package:flutter_helper/boss/layout_type.dart'; +import 'package:flutter_helper/boss/mine/mine_page.dart'; + +class MainPage extends StatefulWidget { + final String title; + + MainPage({Key key, this.title}) : super(key: key); + + @override + State createState() => _MainPageState(); +} + +class _MainPageState extends State { + LayoutType _layoutSelection = LayoutType.job; + + Color _colorTabMatching({LayoutType layoutSelection}) { + return _layoutSelection == layoutSelection ? Colors.cyan[300] : Colors.grey; + } + + BottomNavigationBarItem _buildItem( + {String icon, LayoutType layoutSelection}) { + String text = layoutName(layoutSelection); + return BottomNavigationBarItem( + icon: Image.asset( + icon, + width: 35.0, + height: 35.0, + ), + //label: text, + title: Text( + text, + style: TextStyle( + color: _colorTabMatching(layoutSelection: layoutSelection)), + ), + ); + } + + // 底部TAB + Widget _buildButtonNavBar() { + return BottomNavigationBar( + type: BottomNavigationBarType.fixed, + onTap: _onSelectTab, + items: [ + _buildItem( + icon: _layoutSelection == LayoutType.job + ? "images/ic_main_tab_find_pre.png" + : "images/ic_main_tab_find_nor.png", + layoutSelection: LayoutType.job, + ), + _buildItem( + icon: _layoutSelection == LayoutType.company + ? "images/ic_main_tab_company_pre.png" + : "images/ic_main_tab_company_nor.png", + layoutSelection: LayoutType.company, + ), + _buildItem( + icon: _layoutSelection == LayoutType.chat + ? "images/ic_main_tab_contacts_pre.png" + : "images/ic_main_tab_contacts_nor.png", + layoutSelection: LayoutType.chat, + ), + _buildItem( + icon: _layoutSelection == LayoutType.mine + ? "images/ic_main_tab_my_pre.png" + : "images/ic_main_tab_my_nor.png", + layoutSelection: LayoutType.mine, + ), + ], + ); + } + + // 选择哪个布局 + void _onLayoutSelected(LayoutType selection) { + setState(() { + _layoutSelection = selection; + }); + } + + void _onSelectTab(int index) { + switch (index) { + case 0: + _onLayoutSelected(LayoutType.job); + break; + case 1: + _onLayoutSelected(LayoutType.company); + break; + case 2: + _onLayoutSelected(LayoutType.chat); + break; + case 3: + _onLayoutSelected(LayoutType.mine); + break; + } + } + + Widget _buildBody() { + LayoutType layoutSelection = _layoutSelection; + switch (layoutSelection) { + case LayoutType.job: + return JobPage(); + case LayoutType.company: + return CompanyPage(); + case LayoutType.chat: + return ChatPage(); + case LayoutType.mine: + return MinePage(); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: _buildBody(), + bottomNavigationBar: _buildButtonNavBar(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/mine/contact_item.dart b/FlutterHelper/flutter_helper/lib/boss/mine/contact_item.dart new file mode 100644 index 00000000..4d4e914b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/mine/contact_item.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class ContactItem extends StatelessWidget { + const ContactItem({Key key, this.count, this.title, this.onPressed}) + : super(key: key); + + final String count; + final String title; + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(bottom: 4.0), + child: Text( + count, + style: TextStyle(fontSize: 18.0), + ), + ), + Text( + title, + style: TextStyle(color: Colors.black54, fontSize: 14.0), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/mine/menu_item.dart b/FlutterHelper/flutter_helper/lib/boss/mine/menu_item.dart new file mode 100644 index 00000000..0e45a685 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/mine/menu_item.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/utils.dart'; +import 'package:flutter_helper/utils/util_log.dart'; + +class MenuItem extends StatelessWidget { + final IconData icon; + final String title; + final VoidCallback onPressed; + + const MenuItem({Key key, this.icon, this.title, this.onPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + LogUtil.e('$title'); + showToast(this.title); + // onPressed(); + }, + child: Column( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(20.0, 12.0, 20.0, 10.0), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 8.0), + child: Icon(icon, color: Colors.black54), + ), + Expanded( + child: Text( + title, + style: TextStyle( + color: Colors.black54, + fontSize: 16.0, + ), + ), + ), + Icon(Icons.chevron_right, color: Colors.grey), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20.0), + child: Divider(), + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/boss/mine/mine_page.dart b/FlutterHelper/flutter_helper/lib/boss/mine/mine_page.dart new file mode 100644 index 00000000..5a618507 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/mine/mine_page.dart @@ -0,0 +1,139 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/mine/contact_item.dart'; +import 'package:flutter_helper/boss/mine/menu_item.dart'; + +class MinePage extends StatefulWidget { + @override + _MinePageState createState() => _MinePageState(); +} + +class _MinePageState extends State + with AutomaticKeepAliveClientMixin { + final double _appBarHeight = 180.0; + final String _userHead = + 'https://img.bosszhipin.com/beijin/mcs/useravatar/20171211/4d147d8bb3e2a3478e20b50ad614f4d02062e3aec7ce2519b427d24a3f300d68_s.jpg'; + + @override + bool get wantKeepAlive => true; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color.fromARGB(255, 242, 242, 245), + body: CustomScrollView( + slivers: [ + SliverAppBar( + expandedHeight: _appBarHeight, + flexibleSpace: FlexibleSpaceBar( + collapseMode: CollapseMode.parallax, + background: backgroundWidget(), + ), + ), + SliverList(delegate: SliverChildListDelegate(delegateChildren())) + ], + ), + ); + } + + Widget backgroundWidget() => Stack( + fit: StackFit.expand, + children: [ + DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment(0.0, -1.0), + end: Alignment(0.0, -0.4), + colors: [ + Color(0x00000000), + Color(0x00000000), + ], + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 3, + child: Column( + children: [ + Padding( + padding: EdgeInsets.only( + top: 30.0, + left: 30.0, + bottom: 15.0, + ), + child: Text( + 'kimi he', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 35.0, + ), + ), + ), + Padding( + padding: EdgeInsets.only(left: 30.0), + child: Text( + '在职-不考虑v机会', + style: TextStyle( + color: Colors.white, + fontSize: 15.0, + ), + ), + ), + ], + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: EdgeInsets.only(top: 40.0, right: 30.0), + child: CircleAvatar( + radius: 35.0, + backgroundImage: NetworkImage(_userHead), + ), + ), + ) + ], + ), + ], + ); + + List delegateChildren() => [ + Container( + color: Colors.white, + child: Padding( + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ContactItem(count: '696', title: '沟通过'), + ContactItem(count: '0', title: '面试'), + ContactItem(count: '71', title: '已投递'), + ContactItem(count: '53', title: '感兴趣'), + ], + ), + ), + ), + Container( + color: Colors.white, + margin: const EdgeInsets.only(top: 10.0), + child: Column( + children: [ + MenuItem(icon: Icons.face, title: "体验新版本"), + MenuItem(icon: Icons.print, title: "我的微简历"), + MenuItem(icon: Icons.archive, title: "附件简历"), + MenuItem(icon: Icons.home, title: "管理求职意见"), + MenuItem(icon: Icons.title, title: "提升简历排名"), + MenuItem(icon: Icons.chat, title: "牛人问答"), + MenuItem(icon: Icons.assessment, title: "关注公司"), + MenuItem(icon: Icons.add_shopping_cart, title: "钱包"), + MenuItem(icon: Icons.security, title: "隐私设置"), + ], + ), + ), + ]; +} diff --git a/FlutterHelper/flutter_helper/lib/boss/splash.dart b/FlutterHelper/flutter_helper/lib/boss/splash.dart new file mode 100644 index 00000000..e528994f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/splash.dart @@ -0,0 +1,65 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mainpage.dart'; + +class SplashPage extends StatefulWidget { + @override + State createState() { + return SplashState(); + } +} + +class SplashState extends State { + + Timer _t; // 延迟 + + @override + void initState() { + _t = Timer(Duration(milliseconds: 100), () { + try { + Navigator.of(context).pushAndRemoveUntil( + PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) { + return AnimatedBuilder(animation: animation, builder: + (context, child) { + return Opacity(opacity: animation.value + , child: MainPage(),); + } + ); + } + ) + , (route) => route == null); + } catch (e) { + + } + }); + super.initState(); + } + + @override + void dispose() { + _t.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Material( + color: Color.fromARGB(255, 0, 215, 198), + child: Container( + alignment: Alignment(0, -0.3), + child: Text( + "BOOS", + style: TextStyle( + color: Colors.white, + fontSize: 50.0, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/boss/utils.dart b/FlutterHelper/flutter_helper/lib/boss/utils.dart new file mode 100644 index 00000000..efbf1453 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/boss/utils.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; + +showToast(String txt) { + Fluttertoast.showToast( + msg: txt, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + timeInSecForIosWeb: 1, + backgroundColor: Colors.black45, + textColor: Colors.white, + fontSize: 16.0); +} diff --git a/FlutterHelper/flutter_helper/lib/flutter_tags/lib/flutter_tags.dart b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/flutter_tags.dart new file mode 100644 index 00000000..28a27efc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/flutter_tags.dart @@ -0,0 +1,5 @@ +library flutter_tags; + +export 'src/suggestions_textfield.dart'; +export 'src/item_tags.dart'; +export 'src/tags.dart'; diff --git a/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/item_tags.dart b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/item_tags.dart new file mode 100644 index 00000000..9f28a546 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/item_tags.dart @@ -0,0 +1,501 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../flutter_tags.dart'; + +/// Used by [ItemTags.onPressed]. +typedef OnPressedCallback = void Function(Item i); + +/// Used by [ItemTags.OnLongPressed]. +typedef OnLongPressedCallback = void Function(Item i); + +/// Used by [ItemTags.removeButton.onRemoved]. +typedef OnRemovedCallback = bool Function(); + +/// combines icon text or image +enum ItemTagsCombine { + onlyText, + onlyIcon, + onlyImage, + imageOrIconOrText, + withTextBefore, + withTextAfter +} + +class ItemTags extends StatefulWidget { + ItemTags( + {@required this.index, + @required this.title, + this.textScaleFactor, + this.active = true, + this.pressEnabled = true, + this.customData, + this.textStyle = const TextStyle(fontSize: 14), + this.alignment = MainAxisAlignment.center, + this.combine = ItemTagsCombine.imageOrIconOrText, + this.icon, + this.image, + this.removeButton, + this.borderRadius, + this.border, + this.padding = const EdgeInsets.symmetric(horizontal: 7, vertical: 5), + this.elevation = 5, + this.singleItem = false, + this.textOverflow = TextOverflow.fade, + this.textColor = Colors.black, + this.textActiveColor = Colors.white, + this.color = Colors.white, + this.activeColor = Colors.blueGrey, + this.highlightColor, + this.splashColor, + this.colorShowDuplicate = Colors.red, + this.onPressed, + this.onLongPressed, + Key key}) + : assert(index != null), + assert(title != null), + super(key: key); + + /// Id of [ItemTags] - required + final int index; + + /// Title of [ItemTags] - required + final String title; + + /// Scale Factor of [ItemTags] - double + final double textScaleFactor; + + /// Initial bool value + final bool active; + + /// Initial bool value + final bool pressEnabled; + + /// Possibility to add any custom value in customData field, you can retrieve this later. A good example: store an id from Firestore document. + final dynamic customData; + + /// ItemTagsCombine (text,icon,textIcon,textImage) of [ItemTags] + final ItemTagsCombine combine; + + /// Icon of [ItemTags] + final ItemTagsIcon icon; + + /// Image of [ItemTags] + final ItemTagsImage image; + + /// Custom Remove Button of [ItemTags] + final ItemTagsRemoveButton removeButton; + + /// TextStyle of the [ItemTags] + final TextStyle textStyle; + + /// TextStyle of the [ItemTags] + final MainAxisAlignment alignment; + + /// border-radius of [ItemTags] + final BorderRadius borderRadius; + + /// custom border-side of [ItemTags] + final BoxBorder border; + + /// padding of the [ItemTags] + final EdgeInsets padding; + + /// BoxShadow of the [ItemTags] + final double elevation; + + /// when you want only one tag selected. same radio-button + final bool singleItem; + + /// type of text overflow within the [ItemTags] + final TextOverflow textOverflow; + + /// text color of the [ItemTags] + final Color textColor; + + /// color of the [ItemTags] text activated + final Color textActiveColor; + + /// background color [ItemTags] + final Color color; + + /// background color [ItemTags] activated + final Color activeColor; + + /// highlight Color [ItemTags] + final Color highlightColor; + + /// Splash color [ItemTags] + final Color splashColor; + + /// Color show duplicate [ItemTags] + final Color colorShowDuplicate; + + /// callback + final OnPressedCallback onPressed; + + /// callback + final OnLongPressedCallback onLongPressed; + + @override + _ItemTagsState createState() => _ItemTagsState(); +} + +class _ItemTagsState extends State { + final double _initBorderRadius = 50; + + DataListInherited _dataListInherited; + DataList _dataList; + + void _setDataList() { + // Get List from Tags widget + _dataListInherited = DataListInherited.of(context); + + // set List length + if (_dataListInherited.list.length < _dataListInherited.itemCount) + _dataListInherited.list.length = _dataListInherited.itemCount; + + if (_dataListInherited.list.length > (widget.index + 1) && + _dataListInherited.list.elementAt(widget.index) != null && + _dataListInherited.list.elementAt(widget.index).title != widget.title) { + // when an element is removed from the data source + _dataListInherited.list.removeAt(widget.index); + + // when all item list changed in data source + if (_dataListInherited.list.elementAt(widget.index) != null && + _dataListInherited.list.elementAt(widget.index).title != widget.title) + _dataListInherited.list + .removeRange(widget.index, _dataListInherited.list.length); + } + + // add new Item in the List + if (_dataListInherited.list.length < (widget.index + 1)) { + //print("add"); + _dataListInherited.list.insert( + widget.index, + DataList( + title: widget.title, + index: widget.index, + active: widget.singleItem ? false : widget.active, + customData: widget.customData)); + } else if (_dataListInherited.list.elementAt(widget.index) == null) { + //print("replace"); + _dataListInherited.list[widget.index] = DataList( + title: widget.title, + index: widget.index, + active: widget.singleItem ? false : widget.active, + customData: widget.customData); + } + + // removes items that have been orphaned + if (_dataListInherited.itemCount == widget.index + 1 && + _dataListInherited.list.length > _dataListInherited.itemCount) + _dataListInherited.list + .removeRange(widget.index + 1, _dataListInherited.list.length); + + //print(_dataListInherited.list.length); + + // update Listener + if (_dataList != null) _dataList.removeListener(_didValueChange); + + _dataList = _dataListInherited.list.elementAt(widget.index); + _dataList.addListener(_didValueChange); + } + + _didValueChange() => setState(() {}); + + @override + void dispose() { + _dataList.removeListener(_didValueChange); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _setDataList(); + + final double fontSize = widget.textStyle.fontSize; + + Color color = _dataList.active ? widget.activeColor : widget.color; + + if (_dataList.showDuplicate) color = widget.colorShowDuplicate; + + return Material( + color: color, + borderRadius: + widget.borderRadius ?? BorderRadius.circular(_initBorderRadius), + elevation: widget.elevation, + //shadowColor: _dataList.highlights? Colors.red : Colors.blue, + child: InkWell( + borderRadius: + widget.borderRadius ?? BorderRadius.circular(_initBorderRadius), + highlightColor: + widget.pressEnabled ? widget.highlightColor : Colors.transparent, + splashColor: + widget.pressEnabled ? widget.splashColor : Colors.transparent, + child: Container( + decoration: BoxDecoration( + border: widget.border ?? + Border.all(color: widget.activeColor, width: 0.5), + borderRadius: widget.borderRadius ?? + BorderRadius.circular(_initBorderRadius)), + padding: widget.padding * (fontSize / 14), + child: _combine), + onTap: widget.pressEnabled + ? () { + if (widget.singleItem) { + _singleItem(_dataListInherited, _dataList); + _dataList.active = true; + } else + _dataList.active = !_dataList.active; + + if (widget.onPressed != null) + widget.onPressed(Item( + index: widget.index, + title: _dataList.title, + active: _dataList.active, + customData: widget.customData)); + } + : null, + onLongPress: widget.onLongPressed != null + ? () => widget.onLongPressed(Item( + index: widget.index, + title: _dataList.title, + active: _dataList.active, + customData: widget.customData)) + : null, + ), + ); + } + + Widget get _combine { + if (widget.image != null) + assert((widget.image.image != null && widget.image.child == null) || + (widget.image.child != null && widget.image.image == null)); + final Widget text = Text( + widget.title, + softWrap: false, + textAlign: _textAlignment, + overflow: widget.textOverflow, + textScaleFactor: widget.textScaleFactor, + style: _textStyle, + ); + final Widget icon = widget.icon != null + ? Container( + padding: widget.icon.padding ?? + (widget.combine == ItemTagsCombine.onlyIcon || + widget.combine == ItemTagsCombine.imageOrIconOrText + ? null + : widget.combine == ItemTagsCombine.withTextAfter + ? EdgeInsets.only(right: 5) + : EdgeInsets.only(left: 5)), + child: Icon( + widget.icon.icon, + color: _textStyle.color, + size: _textStyle.fontSize * 1.2, + ), + ) + : text; + final Widget image = widget.image != null + ? Container( + padding: widget.image.padding ?? + (widget.combine == ItemTagsCombine.onlyImage || + widget.combine == ItemTagsCombine.imageOrIconOrText + ? null + : widget.combine == ItemTagsCombine.withTextAfter + ? EdgeInsets.only(right: 5) + : EdgeInsets.only(left: 5)), + child: widget.image.child ?? + CircleAvatar( + radius: + widget.image.radius * (widget.textStyle.fontSize / 14), + backgroundColor: Colors.transparent, + backgroundImage: widget.image.image, + ), + ) + : text; + + final List list = List(); + + switch (widget.combine) { + case ItemTagsCombine.onlyText: + list.add(text); + break; + case ItemTagsCombine.onlyIcon: + list.add(icon); + break; + case ItemTagsCombine.onlyImage: + list.add(image); + break; + case ItemTagsCombine.imageOrIconOrText: + list.add((image != text ? image : icon)); + break; + case ItemTagsCombine.withTextBefore: + list.add(text); + if (image != text) + list.add(image); + else if (icon != text) list.add(icon); + break; + case ItemTagsCombine.withTextAfter: + if (image != text) + list.add(image); + else if (icon != text) list.add(icon); + list.add(text); + } + + final Widget row = Row( + mainAxisAlignment: widget.alignment, + mainAxisSize: MainAxisSize.min, + children: List.generate(list.length, (i) { + if (i == 0 && list.length > 1) + return Flexible( + flex: widget.combine == ItemTagsCombine.withTextAfter ? 0 : 1, + child: list[i], + ); + return Flexible( + flex: widget.combine == ItemTagsCombine.withTextAfter || + list.length == 1 + ? 1 + : 0, + child: list[i], + ); + })); + + if (widget.removeButton != null) + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + fit: + _dataListInherited.symmetry ? FlexFit.tight : FlexFit.loose, + flex: 2, + child: row), + Flexible( + flex: 0, + child: FittedBox( + alignment: Alignment.centerRight, + fit: BoxFit.fill, + child: GestureDetector( + child: Container( + margin: widget.removeButton.margin ?? + EdgeInsets.only(left: 5), + padding: + (widget.removeButton.padding ?? EdgeInsets.all(2)) * + (widget.textStyle.fontSize / 14), + decoration: BoxDecoration( + color: widget.removeButton.backgroundColor ?? + Colors.black, + borderRadius: widget.removeButton.borderRadius ?? + BorderRadius.circular(_initBorderRadius), + ), + child: widget.removeButton.padding ?? + Icon( + Icons.clear, + color: widget.removeButton.color ?? Colors.white, + size: (widget.removeButton.size ?? 12) * + (widget.textStyle.fontSize / 14), + ), + ), + onTap: () { + if (widget.removeButton.onRemoved != null) { + if (widget.removeButton.onRemoved()) + _dataListInherited.list.removeAt(widget.index); + } + }, + ))) + ]); + + return row; + } + + ///Text Alignment + TextAlign get _textAlignment { + switch (widget.alignment) { + case MainAxisAlignment.spaceBetween: + case MainAxisAlignment.start: + return TextAlign.start; + break; + case MainAxisAlignment.end: + return TextAlign.end; + break; + case MainAxisAlignment.spaceAround: + case MainAxisAlignment.spaceEvenly: + case MainAxisAlignment.center: + return TextAlign.center; + } + return null; + } + + ///TextStyle + TextStyle get _textStyle { + return widget.textStyle.apply( + color: _dataList.active ? widget.textActiveColor : widget.textColor, + ); + } + + /// Single item selection + void _singleItem(DataListInherited dataSetIn, DataList dataSet) { + dataSetIn.list + .where((tg) => tg != null) + .where((tg) => tg.active) + .where((tg2) => tg2 != dataSet) + .forEach((tg) => tg.active = false); + } +} + +///callback +class Item { + Item({this.index, this.title, this.active, this.customData}); + final int index; + final String title; + final bool active; + final dynamic customData; + + @override + String toString() { + return "id:$index, title: $title, active: $active, customData: $customData"; + } +} + +/// ItemTag Image +class ItemTagsImage { + ItemTagsImage({this.radius = 8, this.padding, this.image, this.child}); + + final double radius; + final EdgeInsets padding; + final ImageProvider image; + final Widget child; +} + +/// ItemTag Icon +class ItemTagsIcon { + ItemTagsIcon({this.padding, @required this.icon}); + + final EdgeInsets padding; + final IconData icon; +} + +/// ItemTag RemoveButton +class ItemTagsRemoveButton { + ItemTagsRemoveButton( + {this.icon, + this.size, + this.backgroundColor, + this.color, + this.borderRadius, + this.padding, + this.margin, + this.onRemoved}); + + final IconData icon; + final double size; + final Color backgroundColor; + final Color color; + final BorderRadius borderRadius; + final EdgeInsets padding; + final EdgeInsets margin; + + /// callback + final OnRemovedCallback onRemoved; +} diff --git a/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/suggestions_textfield.dart b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/suggestions_textfield.dart new file mode 100644 index 00000000..cd641c69 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/suggestions_textfield.dart @@ -0,0 +1,223 @@ +import 'package:flutter/material.dart'; + +// InputSuggestions version 0.0.1 +// currently yield inline suggestions +// I will soon implement a list with suggestions +// Credit Dn-a -> https://github.com/Dn-a + +/// Used by [SuggestionsTextField.onChanged]. +typedef OnChangedCallback = void Function(String string); + +/// Used by [SuggestionsTextField.onSubmitted]. +typedef OnSubmittedCallback = void Function(String string); + +class SuggestionsTextField extends StatefulWidget { + SuggestionsTextField( + {@required this.tagsTextField, this.onSubmitted, Key key}) + : assert(tagsTextField != null), + super(key: key); + + final TagsTextField tagsTextField; + final OnSubmittedCallback onSubmitted; + + @override + _SuggestionsTextFieldState createState() => _SuggestionsTextFieldState(); +} + +class _SuggestionsTextFieldState extends State { + final _controller = TextEditingController(); + + List _matches = List(); + String _helperText; + bool _helperCheck = true; + + List _suggestions; + bool _constraintSuggestion; + double _fontSize; + InputDecoration _inputDecoration; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + _helperText = widget.tagsTextField.helperText ?? "no matches"; + _suggestions = widget.tagsTextField.suggestions; + _constraintSuggestion = widget.tagsTextField.constraintSuggestion; + _inputDecoration = widget.tagsTextField.inputDecoration; + _fontSize = widget.tagsTextField.textStyle.fontSize; + + return Stack( + alignment: Alignment.centerLeft, + children: [ + Visibility( + visible: _suggestions != null, + child: Container( + //width: double.infinity, + padding: _inputDecoration != null + ? _inputDecoration.contentPadding + : EdgeInsets.symmetric( + vertical: 6 * (_fontSize / 14), + horizontal: 6 * (_fontSize / 14)), + child: Text( + _matches.isNotEmpty ? (_matches.first) : "", + softWrap: false, + overflow: TextOverflow.fade, + style: TextStyle( + height: widget.tagsTextField.textStyle.height == null + ? 1 + : widget.tagsTextField.textStyle.height, + fontSize: _fontSize ?? null, + color: widget.tagsTextField.suggestionTextColor ?? Colors.red, + ), + ), + ), + ), + TextField( + controller: _controller, + enabled: widget.tagsTextField.enabled, + autofocus: widget.tagsTextField.autofocus ?? true, + keyboardType: widget.tagsTextField.keyboardType ?? null, + textCapitalization: widget.tagsTextField.textCapitalization ?? + TextCapitalization.none, + maxLength: widget.tagsTextField.maxLength ?? null, + maxLines: 1, + autocorrect: widget.tagsTextField.autocorrect ?? false, + style: widget.tagsTextField.textStyle.copyWith( + height: widget.tagsTextField.textStyle.height == null ? 1 : null), + decoration: _initialInputDecoration, + onChanged: (str) => _checkOnChanged(str), + onSubmitted: (str) => _onSubmitted(str), + ) + ], + ); + } + + InputDecoration get _initialInputDecoration { + var input = _inputDecoration ?? + InputDecoration( + disabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + vertical: 6 * (_fontSize / 14), + horizontal: 6 * (_fontSize / 14)), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.blueGrey[300], + ), + ), + enabledBorder: UnderlineInputBorder( + borderSide: + BorderSide(color: Colors.blueGrey[400].withOpacity(0.3)), + ), + border: UnderlineInputBorder( + borderSide: + BorderSide(color: Colors.blueGrey[400].withOpacity(0.3)), + )); + + return input.copyWith( + helperText: _helperCheck || _suggestions == null ? null : _helperText, + helperStyle: widget.tagsTextField.helperTextStyle, + hintText: widget.tagsTextField.hintText ?? 'Add a tag', + hintStyle: TextStyle(color: widget.tagsTextField.hintTextColor)); + } + + ///OnSubmitted + void _onSubmitted(String str) { + var onSubmitted = widget.onSubmitted; + + if (_suggestions != null && _matches.isNotEmpty) str = _matches.first; + + if (widget.tagsTextField.lowerCase) str = str.toLowerCase(); + + str = str.trim(); + + if (_suggestions != null) { + if (_matches.isNotEmpty || !_constraintSuggestion) { + if (onSubmitted != null) onSubmitted(str); + setState(() { + _matches = []; + }); + _controller.clear(); + } + } else if (str.isNotEmpty) { + if (onSubmitted != null) onSubmitted(str); + _controller.clear(); + } + } + + ///Check onChanged + void _checkOnChanged(String str) { + if (_suggestions != null) { + _matches = + _suggestions.where((String sgt) => sgt.startsWith(str)).toList(); + + if (str.isEmpty) _matches = []; + + if (_matches.length > 1) _matches.removeWhere((String mtc) => mtc == str); + + setState(() { + _helperCheck = + _matches.isNotEmpty || str.isEmpty || !_constraintSuggestion + ? true + : false; + _matches.sort((a, b) => a.compareTo(b)); + }); + } + + if (widget.tagsTextField.onChanged != null) + widget.tagsTextField.onChanged(str); + } +} + +/// Tags TextField +class TagsTextField { + TagsTextField( + {this.lowerCase = false, + this.textStyle = const TextStyle(fontSize: 14), + this.width = 200, + this.padding, + this.enabled = true, + this.duplicates = false, + this.suggestions, + this.constraintSuggestion = true, + this.autocorrect, + this.autofocus, + this.hintText, + this.hintTextColor, + this.suggestionTextColor, + this.helperText, + this.helperTextStyle, + this.keyboardType, + this.textCapitalization, + this.maxLength, + this.inputDecoration, + this.onSubmitted, + this.onChanged}); + + final double width; + final EdgeInsets padding; + final bool enabled; + final bool duplicates; + final TextStyle textStyle; + final InputDecoration inputDecoration; + final bool autocorrect; + final List suggestions; + + /// Allows you to insert tags not present in the list of suggestions + final bool constraintSuggestion; + final bool lowerCase; + final bool autofocus; + final String hintText; + final Color hintTextColor; + final Color suggestionTextColor; + final String helperText; + final TextStyle helperTextStyle; + final TextInputType keyboardType; + final TextCapitalization textCapitalization; + final int maxLength; + final OnSubmittedCallback onSubmitted; + final OnChangedCallback onChanged; +} diff --git a/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/tags.dart b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/tags.dart new file mode 100644 index 00000000..d55f7193 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/tags.dart @@ -0,0 +1,290 @@ +import 'package:flutter/material.dart'; + +import '../flutter_tags.dart'; +import 'util/custom_wrap.dart'; + +///ItemBuilder +typedef Widget ItemBuilder(int index); + +class Tags extends StatefulWidget { + Tags( + {this.columns, + this.itemCount = 0, + this.symmetry = false, + this.horizontalScroll = false, + this.heightHorizontalScroll = 60, + this.spacing = 6, + this.runSpacing = 14, + this.alignment = WrapAlignment.center, + this.runAlignment = WrapAlignment.center, + this.direction = Axis.horizontal, + this.verticalDirection = VerticalDirection.down, + this.textDirection = TextDirection.ltr, + this.itemBuilder, + this.textField, + Key key}) + : assert(itemCount >= 0), + assert(alignment != null), + assert(runAlignment != null), + assert(direction != null), + assert(verticalDirection != null), + assert(textDirection != null), + super(key: key); + + ///specific number of columns + final int columns; + + ///numer of item List + final int itemCount; + + /// imposes the same width and the same number of columns for each row + final bool symmetry; + + /// ability to scroll tags horizontally + final bool horizontalScroll; + + /// horizontal spacing of the [ItemTags] + final double heightHorizontalScroll; + + /// horizontal spacing of the [ItemTags] + final double spacing; + + /// vertical spacing of the [ItemTags] + final double runSpacing; + + /// horizontal alignment of the [ItemTags] + final WrapAlignment alignment; + + /// vertical alignment of the [ItemTags] + final WrapAlignment runAlignment; + + /// direction of the [ItemTags] + final Axis direction; + + /// Iterate [Item] from the lower to the upper direction or vice versa + final VerticalDirection verticalDirection; + + /// Text direction of the [ItemTags] + final TextDirection textDirection; + + /// Generates a list of [ItemTags]. + /// + /// Creates a list with [length] positions and fills it with values created by + /// calling [generator] for each index in the range `0` .. `length - 1` + /// in increasing order. + final ItemBuilder itemBuilder; + + /// custom TextField + final TagsTextField textField; + + @override + TagsState createState() => TagsState(); +} + +class TagsState extends State { + final GlobalKey _containerKey = GlobalKey(); + Orientation _orientation = Orientation.portrait; + double _width = 0; + + final List _list = List(); + + List get getAllItem => _list.toList(); + + //get the current width of the screen + void _getWidthContext() { + WidgetsBinding.instance.addPostFrameCallback((_) { + final keyContext = _containerKey.currentContext; + if (keyContext != null) { + final RenderBox box = keyContext.findRenderObject(); + final size = box.size; + setState(() { + _width = size.width; + }); + } + }); + } + + @override + Widget build(BuildContext context) { + // essential to avoid infinite loop of addPostFrameCallback + if (widget.symmetry && + (MediaQuery.of(context).orientation != _orientation || _width == 0)) { + _orientation = MediaQuery.of(context).orientation; + _getWidthContext(); + } + + Widget child; + if (widget.horizontalScroll && !widget.symmetry) + child = Container( + height: widget.heightHorizontalScroll, + color: Colors.transparent, + child: ListView( + padding: EdgeInsets.all(0), + scrollDirection: Axis.horizontal, + shrinkWrap: true, + physics: ClampingScrollPhysics(), + children: _buildItems(), + ), + ); + else + child = CustomWrap( + key: _containerKey, + alignment: widget.alignment, + runAlignment: widget.runAlignment, + spacing: widget.spacing, + runSpacing: widget.runSpacing, + column: widget.columns, + symmetry: widget.symmetry, + textDirection: widget.textDirection, + direction: widget.direction, + verticalDirection: widget.verticalDirection, + crossAxisAlignment: WrapCrossAlignment.end, + children: _buildItems(), + ); + + return DataListInherited( + list: _list, + symmetry: widget.symmetry, + itemCount: widget.itemCount, + child: child, + ); + } + + List _buildItems() { + /*if(_list.length < widget.itemCount) + _list.clear();*/ + + final Widget textField = widget.textField != null + ? Container( + alignment: Alignment.center, + width: widget.symmetry ? _widthCalc() : widget.textField.width, + padding: widget.textField.padding, + child: SuggestionsTextField( + tagsTextField: widget.textField, + onSubmitted: (String str) { + if (!widget.textField.duplicates) { + final List lst = + _list.where((l) => l.title == str).toList(); + + if (lst.isNotEmpty) { + lst.forEach((d) => d.showDuplicate = true); + return; + } + } + + if (widget.textField.onSubmitted != null) + widget.textField.onSubmitted(str); + }, + ), + ) + : null; + + List finalList = List(); + + List itemList = List.generate(widget.itemCount, (i) { + final Widget item = widget.itemBuilder(i); + if (widget.symmetry) + return Container( + width: _widthCalc(), + child: item, + ); + else if (widget.horizontalScroll) + return Container( + margin: EdgeInsets.symmetric(horizontal: widget.spacing), + alignment: Alignment.center, + child: item, + ); + return item; + }); + + if (widget.horizontalScroll && widget.textDirection == TextDirection.rtl) + itemList = itemList.reversed.toList(); + + if (textField == null) { + finalList.addAll(itemList); + return finalList; + } + + if (widget.horizontalScroll && + widget.verticalDirection == VerticalDirection.up) { + finalList.add(textField); + finalList.addAll(itemList); + } else { + finalList.addAll(itemList); + finalList.add(textField); + } + + return finalList; + } + + //Container width divided by the number of columns when symmetry is active + double _widthCalc() { + int columns = widget.columns ?? 0; + int margin = widget.spacing.round(); + + int subtraction = columns * (margin); + double width = (_width > 1) ? (_width - subtraction) / columns : _width; + + return width; + } +} + +/// Inherited Widget +class DataListInherited extends InheritedWidget { + DataListInherited( + {Key key, this.list, this.symmetry, this.itemCount, Widget child}) + : super(key: key, child: child); + + final List list; + final bool symmetry; + final int itemCount; + + @override + bool updateShouldNotify(DataListInherited old) { + //print("inherited"); + return false; + } + + /*static DataListInherited of(BuildContext context) => + context.inheritFromWidgetOfExactType(DataListInherited);*/ + static DataListInherited of(BuildContext context) => + context.dependOnInheritedWidgetOfExactType(); +} + +/// Data List +class DataList extends ValueNotifier implements Item { + DataList( + {@required this.title, + this.index, + bool highlights = false, + bool active = true, + this.customData}) + : _showDuplicate = highlights, + _active = active, + super(active); + + final String title; + final dynamic customData; + final int index; + + get showDuplicate { + final val = _showDuplicate; + _showDuplicate = false; + return val; + } + + bool _showDuplicate; + set showDuplicate(bool a) { + _showDuplicate = a; + // rebuild only the specific Item that changes its value + notifyListeners(); + } + + get active => _active; + bool _active; + set active(bool a) { + _active = a; + // rebuild only the specific Item that changes its value + notifyListeners(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/util/custom_wrap.dart b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/util/custom_wrap.dart new file mode 100644 index 00000000..68051cff --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/flutter_tags/lib/src/util/custom_wrap.dart @@ -0,0 +1,697 @@ +import 'dart:math' as math; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; + +/// Custom Wrap +class CustomWrap extends MultiChildRenderObjectWidget { + CustomWrap({ + Key key, + this.column, + this.symmetry, + this.direction = Axis.horizontal, + this.alignment = WrapAlignment.start, + this.spacing = 0.0, + this.runAlignment = WrapAlignment.start, + this.runSpacing = 0.0, + this.crossAxisAlignment = WrapCrossAlignment.start, + this.textDirection, + this.verticalDirection = VerticalDirection.down, + List children = const [], + }) : super(key: key, children: children); + + final int column; + + final bool symmetry; + + final Axis direction; + + final WrapAlignment alignment; + + final double spacing; + + final WrapAlignment runAlignment; + + final double runSpacing; + + final WrapCrossAlignment crossAxisAlignment; + + final TextDirection textDirection; + + final VerticalDirection verticalDirection; + + @override + CustomRenderWrap createRenderObject(BuildContext context) { + return CustomRenderWrap( + column: column, + symmetry: symmetry, + direction: direction, + alignment: alignment, + spacing: spacing, + runAlignment: runAlignment, + runSpacing: runSpacing, + crossAxisAlignment: crossAxisAlignment, + textDirection: textDirection ?? Directionality.of(context), + verticalDirection: verticalDirection, + ); + } + + @override + void updateRenderObject(BuildContext context, CustomRenderWrap renderObject) { + renderObject + ..column = column + ..symmetry = symmetry + ..direction = direction + ..alignment = alignment + ..spacing = spacing + ..runAlignment = runAlignment + ..runSpacing = runSpacing + ..crossAxisAlignment = crossAxisAlignment + ..textDirection = textDirection ?? Directionality.of(context) + ..verticalDirection = verticalDirection; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(EnumProperty('direction', direction)); + properties.add(EnumProperty('alignment', alignment)); + properties.add(DoubleProperty('spacing', spacing)); + properties.add(EnumProperty('runAlignment', runAlignment)); + properties.add(DoubleProperty('runSpacing', runSpacing)); + properties.add(DoubleProperty('crossAxisAlignment', runSpacing)); + properties.add(EnumProperty('textDirection', textDirection, + defaultValue: null)); + properties.add(EnumProperty( + 'verticalDirection', verticalDirection, + defaultValue: VerticalDirection.down)); + } +} + +/// Displays its children in multiple horizontal or vertical runs. +class CustomRenderWrap extends RenderBox + with + ContainerRenderObjectMixin, + RenderBoxContainerDefaultsMixin { + CustomRenderWrap({ + List children, + int column, + bool symmetry, + Axis direction = Axis.horizontal, + WrapAlignment alignment = WrapAlignment.start, + double spacing = 0.0, + WrapAlignment runAlignment = WrapAlignment.start, + double runSpacing = 0.0, + WrapCrossAlignment crossAxisAlignment = WrapCrossAlignment.start, + TextDirection textDirection, + VerticalDirection verticalDirection = VerticalDirection.down, + }) : assert(direction != null), + assert(alignment != null), + assert(spacing != null), + assert(runAlignment != null), + assert(runSpacing != null), + assert(crossAxisAlignment != null), + _column = column, + _symmetry = symmetry, + _direction = direction, + _alignment = alignment, + _spacing = spacing, + _runAlignment = runAlignment, + _runSpacing = runSpacing, + _crossAxisAlignment = crossAxisAlignment, + _textDirection = textDirection, + _verticalDirection = verticalDirection { + addAll(children); + } + + int get column => _column; + int _column; + set column(int value) { + if (column == value) return; + _column = value; + markNeedsLayout(); + } + + bool get symmetry => _symmetry; + bool _symmetry; + set symmetry(bool value) { + if (symmetry == value) return; + _symmetry = value; + markNeedsLayout(); + } + + Axis get direction => _direction; + Axis _direction; + set direction(Axis value) { + assert(value != null); + if (_direction == value) return; + _direction = value; + markNeedsLayout(); + } + + WrapAlignment get alignment => _alignment; + WrapAlignment _alignment; + set alignment(WrapAlignment value) { + assert(value != null); + if (_alignment == value) return; + _alignment = value; + markNeedsLayout(); + } + + double get spacing => _spacing; + double _spacing; + set spacing(double value) { + assert(value != null); + if (_spacing == value) return; + _spacing = value; + markNeedsLayout(); + } + + WrapAlignment get runAlignment => _runAlignment; + WrapAlignment _runAlignment; + set runAlignment(WrapAlignment value) { + assert(value != null); + if (_runAlignment == value) return; + _runAlignment = value; + markNeedsLayout(); + } + + double get runSpacing => _runSpacing; + double _runSpacing; + set runSpacing(double value) { + assert(value != null); + if (_runSpacing == value) return; + _runSpacing = value; + markNeedsLayout(); + } + + WrapCrossAlignment get crossAxisAlignment => _crossAxisAlignment; + WrapCrossAlignment _crossAxisAlignment; + set crossAxisAlignment(WrapCrossAlignment value) { + assert(value != null); + if (_crossAxisAlignment == value) return; + _crossAxisAlignment = value; + markNeedsLayout(); + } + + TextDirection get textDirection => _textDirection; + TextDirection _textDirection; + set textDirection(TextDirection value) { + if (_textDirection != value) { + _textDirection = value; + markNeedsLayout(); + } + } + + VerticalDirection get verticalDirection => _verticalDirection; + VerticalDirection _verticalDirection; + set verticalDirection(VerticalDirection value) { + if (_verticalDirection != value) { + _verticalDirection = value; + markNeedsLayout(); + } + } + + bool get _debugHasNecessaryDirections { + assert(direction != null); + assert(alignment != null); + assert(runAlignment != null); + assert(crossAxisAlignment != null); + if (firstChild != null && lastChild != firstChild) { + // i.e. there's more than one child + switch (direction) { + case Axis.horizontal: + assert(textDirection != null, + 'Horizontal $runtimeType with multiple children has a null textDirection, so the layout order is undefined.'); + break; + case Axis.vertical: + assert(verticalDirection != null, + 'Vertical $runtimeType with multiple children has a null verticalDirection, so the layout order is undefined.'); + break; + } + } + if (alignment == WrapAlignment.start || alignment == WrapAlignment.end) { + switch (direction) { + case Axis.horizontal: + assert(textDirection != null, + 'Horizontal $runtimeType with alignment $alignment has a null textDirection, so the alignment cannot be resolved.'); + break; + case Axis.vertical: + assert(verticalDirection != null, + 'Vertical $runtimeType with alignment $alignment has a null verticalDirection, so the alignment cannot be resolved.'); + break; + } + } + if (runAlignment == WrapAlignment.start || + runAlignment == WrapAlignment.end) { + switch (direction) { + case Axis.horizontal: + assert(verticalDirection != null, + 'Horizontal $runtimeType with runAlignment $runAlignment has a null verticalDirection, so the alignment cannot be resolved.'); + break; + case Axis.vertical: + assert(textDirection != null, + 'Vertical $runtimeType with runAlignment $runAlignment has a null textDirection, so the alignment cannot be resolved.'); + break; + } + } + if (crossAxisAlignment == WrapCrossAlignment.start || + crossAxisAlignment == WrapCrossAlignment.end) { + switch (direction) { + case Axis.horizontal: + assert(verticalDirection != null, + 'Horizontal $runtimeType with crossAxisAlignment $crossAxisAlignment has a null verticalDirection, so the alignment cannot be resolved.'); + break; + case Axis.vertical: + assert(textDirection != null, + 'Vertical $runtimeType with crossAxisAlignment $crossAxisAlignment has a null textDirection, so the alignment cannot be resolved.'); + break; + } + } + return true; + } + + @override + void setupParentData(RenderBox child) { + if (child.parentData is! WrapParentData) + child.parentData = WrapParentData(); + } + + double _computeIntrinsicHeightForWidth(double width) { + assert(direction == Axis.horizontal); + int runCount = 0; + double height = 0.0; + double runWidth = 0.0; + double runHeight = 0.0; + int childCount = 0; + RenderBox child = firstChild; + while (child != null) { + final double childWidth = child.getMaxIntrinsicWidth(double.infinity); + final double childHeight = child.getMaxIntrinsicHeight(childWidth); + if (runWidth + childWidth > width) { + height += runHeight; + if (runCount > 0) height += runSpacing; + runCount += 1; + runWidth = 0.0; + runHeight = 0.0; + childCount = 0; + } + runWidth += childWidth; + runHeight = math.max(runHeight, childHeight); + if (childCount > 0) runWidth += spacing; + childCount += 1; + child = childAfter(child); + } + if (childCount > 0) height += runHeight + runSpacing; + return height; + } + + double _computeIntrinsicWidthForHeight(double height) { + assert(direction == Axis.vertical); + int runCount = 0; + double width = 0.0; + double runHeight = 0.0; + double runWidth = 0.0; + int childCount = 0; + RenderBox child = firstChild; + while (child != null) { + final double childHeight = child.getMaxIntrinsicHeight(double.infinity); + final double childWidth = child.getMaxIntrinsicWidth(childHeight); + if (runHeight + childHeight > height) { + width += runWidth; + if (runCount > 0) width += runSpacing; + runCount += 1; + runHeight = 0.0; + runWidth = 0.0; + childCount = 0; + } + runHeight += childHeight; + runWidth = math.max(runWidth, childWidth); + if (childCount > 0) runHeight += spacing; + childCount += 1; + child = childAfter(child); + } + if (childCount > 0) width += runWidth + runSpacing; + return width; + } + + @override + double computeMinIntrinsicWidth(double height) { + switch (direction) { + case Axis.horizontal: + double width = 0.0; + RenderBox child = firstChild; + while (child != null) { + width = math.max(width, child.getMinIntrinsicWidth(double.infinity)); + child = childAfter(child); + } + return width; + case Axis.vertical: + return _computeIntrinsicWidthForHeight(height); + } + return null; + } + + @override + double computeMaxIntrinsicWidth(double height) { + switch (direction) { + case Axis.horizontal: + double width = 0.0; + RenderBox child = firstChild; + while (child != null) { + width += child.getMaxIntrinsicWidth(double.infinity); + child = childAfter(child); + } + return width; + case Axis.vertical: + return _computeIntrinsicWidthForHeight(height); + } + return null; + } + + @override + double computeMinIntrinsicHeight(double width) { + switch (direction) { + case Axis.horizontal: + return _computeIntrinsicHeightForWidth(width); + case Axis.vertical: + double height = 0.0; + RenderBox child = firstChild; + while (child != null) { + height = + math.max(height, child.getMinIntrinsicHeight(double.infinity)); + child = childAfter(child); + } + return height; + } + return null; + } + + @override + double computeMaxIntrinsicHeight(double width) { + switch (direction) { + case Axis.horizontal: + return _computeIntrinsicHeightForWidth(width); + case Axis.vertical: + double height = 0.0; + RenderBox child = firstChild; + while (child != null) { + height += child.getMaxIntrinsicHeight(double.infinity); + child = childAfter(child); + } + return height; + } + return null; + } + + @override + double computeDistanceToActualBaseline(TextBaseline baseline) { + return defaultComputeDistanceToHighestActualBaseline(baseline); + } + + double _getMainAxisExtent(RenderBox child) { + switch (direction) { + case Axis.horizontal: + return child.size.width; + case Axis.vertical: + return child.size.height; + } + return 0.0; + } + + double _getCrossAxisExtent(RenderBox child) { + switch (direction) { + case Axis.horizontal: + return child.size.height; + case Axis.vertical: + return child.size.width; + } + return 0.0; + } + + Offset _getOffset(double mainAxisOffset, double crossAxisOffset) { + switch (direction) { + case Axis.horizontal: + return Offset(mainAxisOffset, crossAxisOffset); + case Axis.vertical: + return Offset(crossAxisOffset, mainAxisOffset); + } + return Offset.zero; + } + + double _getChildCrossAxisOffset(bool flipCrossAxis, double runCrossAxisExtent, + double childCrossAxisExtent) { + final double freeSpace = runCrossAxisExtent - childCrossAxisExtent; + switch (crossAxisAlignment) { + case WrapCrossAlignment.start: + return flipCrossAxis ? freeSpace : 0.0; + case WrapCrossAlignment.end: + return flipCrossAxis ? 0.0 : freeSpace; + case WrapCrossAlignment.center: + return freeSpace / 2.0; + } + return 0.0; + } + + bool _hasVisualOverflow = false; + + @override + void performLayout() { + assert(_debugHasNecessaryDirections); + _hasVisualOverflow = false; + RenderBox child = firstChild; + if (child == null) { + size = constraints.smallest; + return; + } + BoxConstraints childConstraints; + double mainAxisLimit = 0.0; + bool flipMainAxis = false; + bool flipCrossAxis = false; + switch (direction) { + case Axis.horizontal: + childConstraints = BoxConstraints(maxWidth: constraints.maxWidth); + mainAxisLimit = constraints.maxWidth; + if (textDirection == TextDirection.rtl) flipMainAxis = true; + if (verticalDirection == VerticalDirection.up) flipCrossAxis = true; + break; + case Axis.vertical: + childConstraints = BoxConstraints(maxHeight: constraints.maxHeight); + mainAxisLimit = constraints.maxHeight; + if (verticalDirection == VerticalDirection.up) flipMainAxis = true; + if (textDirection == TextDirection.rtl) flipCrossAxis = true; + break; + } + assert(childConstraints != null); + assert(mainAxisLimit != null); + final double spacing = this.spacing; + final double runSpacing = this.runSpacing; + final List<_RunMetrics> runMetrics = <_RunMetrics>[]; + double mainAxisExtent = 0.0; + double crossAxisExtent = 0.0; + double runMainAxisExtent = 0.0; + double runCrossAxisExtent = 0.0; + int childCount = 0; + + int cnt = 0; + while (child != null) { + child.layout(childConstraints, parentUsesSize: true); + final double childMainAxisExtent = _getMainAxisExtent(child); + final double childCrossAxisExtent = _getCrossAxisExtent(child); + if ((childCount > 0 && + runMainAxisExtent + spacing + childMainAxisExtent > + mainAxisLimit) || + (_column != null && _column != 0 && cnt == _column)) { + cnt = 0; + mainAxisExtent = math.max(mainAxisExtent, runMainAxisExtent); + crossAxisExtent += runCrossAxisExtent; + if (runMetrics.isNotEmpty) crossAxisExtent += runSpacing; + runMetrics.add( + _RunMetrics(runMainAxisExtent, runCrossAxisExtent, childCount)); + runMainAxisExtent = 0.0; + runCrossAxisExtent = 0.0; + childCount = 0; + } + cnt++; + runMainAxisExtent += childMainAxisExtent; + if (childCount > 0) runMainAxisExtent += spacing; + runCrossAxisExtent = math.max(runCrossAxisExtent, childCrossAxisExtent); + childCount += 1; + final WrapParentData childParentData = child.parentData; + childParentData._runIndex = runMetrics.length; + child = childParentData.nextSibling; + } + if (childCount > 0) { + mainAxisExtent = math.max(mainAxisExtent, runMainAxisExtent); + crossAxisExtent += runCrossAxisExtent; + if (runMetrics.isNotEmpty) crossAxisExtent += runSpacing; + runMetrics + .add(_RunMetrics(runMainAxisExtent, runCrossAxisExtent, childCount)); + } + + final int runCount = runMetrics.length; + assert(runCount > 0); + + double containerMainAxisExtent = 0.0; + double containerCrossAxisExtent = 0.0; + + switch (direction) { + case Axis.horizontal: + size = constraints.constrain(Size(mainAxisExtent, crossAxisExtent)); + containerMainAxisExtent = size.width; + containerCrossAxisExtent = size.height; + break; + case Axis.vertical: + size = constraints.constrain(Size(crossAxisExtent, mainAxisExtent)); + containerMainAxisExtent = size.height; + containerCrossAxisExtent = size.width; + break; + } + + _hasVisualOverflow = containerMainAxisExtent < mainAxisExtent || + containerCrossAxisExtent < crossAxisExtent; + + final double crossAxisFreeSpace = + math.max(0.0, containerCrossAxisExtent - crossAxisExtent); + double runLeadingSpace = 0.0; + double runBetweenSpace = 0.0; + switch (runAlignment) { + case WrapAlignment.start: + break; + case WrapAlignment.end: + runLeadingSpace = crossAxisFreeSpace; + break; + case WrapAlignment.center: + runLeadingSpace = crossAxisFreeSpace / 2.0; + break; + case WrapAlignment.spaceBetween: + runBetweenSpace = + runCount > 1 ? crossAxisFreeSpace / (runCount - 1) : 0.0; + break; + case WrapAlignment.spaceAround: + runBetweenSpace = crossAxisFreeSpace / runCount; + runLeadingSpace = runBetweenSpace / 2.0; + break; + case WrapAlignment.spaceEvenly: + runBetweenSpace = crossAxisFreeSpace / (runCount + 1); + runLeadingSpace = runBetweenSpace; + break; + } + + runBetweenSpace += runSpacing; + double crossAxisOffset = flipCrossAxis + ? containerCrossAxisExtent - runLeadingSpace + : runLeadingSpace; + + child = firstChild; + for (int i = 0; i < runCount; ++i) { + final _RunMetrics metrics = runMetrics[i]; + final double runMainAxisExtent = metrics.mainAxisExtent; + final double runCrossAxisExtent = metrics.crossAxisExtent; + final int childCount = metrics.childCount; + + final double mainAxisFreeSpace = + math.max(0.0, containerMainAxisExtent - runMainAxisExtent); + double childLeadingSpace = 0.0; + double childBetweenSpace = 0.0; + + //print(symmetry); + switch (alignment) { + case WrapAlignment.start: + if (symmetry) childLeadingSpace = spacing / 2; + break; + case WrapAlignment.end: + childLeadingSpace = mainAxisFreeSpace; + if (symmetry) childLeadingSpace = mainAxisFreeSpace - spacing / 2; + break; + case WrapAlignment.center: + childLeadingSpace = mainAxisFreeSpace / 2.0; + break; + case WrapAlignment.spaceBetween: + childBetweenSpace = + childCount > 1 ? mainAxisFreeSpace / (childCount - 1) : 0.0; + break; + case WrapAlignment.spaceAround: + childBetweenSpace = mainAxisFreeSpace / childCount; + childLeadingSpace = childBetweenSpace / 2.0; + break; + case WrapAlignment.spaceEvenly: + childBetweenSpace = mainAxisFreeSpace / (childCount + 1); + childLeadingSpace = childBetweenSpace; + break; + } + + childBetweenSpace += spacing; + double childMainPosition = flipMainAxis + ? containerMainAxisExtent - childLeadingSpace + : childLeadingSpace; + + if (flipCrossAxis) crossAxisOffset -= runCrossAxisExtent; + + while (child != null) { + final WrapParentData childParentData = child.parentData; + if (childParentData._runIndex != i) break; + final double childMainAxisExtent = _getMainAxisExtent(child); + final double childCrossAxisExtent = _getCrossAxisExtent(child); + final double childCrossAxisOffset = _getChildCrossAxisOffset( + flipCrossAxis, runCrossAxisExtent, childCrossAxisExtent); + if (flipMainAxis) childMainPosition -= childMainAxisExtent; + childParentData.offset = _getOffset( + childMainPosition, crossAxisOffset + childCrossAxisOffset); + if (flipMainAxis) + childMainPosition -= childBetweenSpace; + else + childMainPosition += childMainAxisExtent + childBetweenSpace; + child = childParentData.nextSibling; + } + + if (flipCrossAxis) + crossAxisOffset -= runBetweenSpace; + else + crossAxisOffset += runCrossAxisExtent + runBetweenSpace; + } + } + + @override + bool hitTestChildren(HitTestResult result, {Offset position}) { + return defaultHitTestChildren(result, position: position); + } + + @override + void paint(PaintingContext context, Offset offset) { + // it can be reused here + if (_hasVisualOverflow) + context.pushClipRect( + needsCompositing, offset, Offset.zero & size, defaultPaint); + else + defaultPaint(context, offset); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(EnumProperty('direction', direction)); + properties.add(EnumProperty('alignment', alignment)); + properties.add(DoubleProperty('spacing', spacing)); + properties.add(EnumProperty('runAlignment', runAlignment)); + properties.add(DoubleProperty('runSpacing', runSpacing)); + properties.add(DoubleProperty('crossAxisAlignment', runSpacing)); + properties.add(EnumProperty('textDirection', textDirection, + defaultValue: null)); + properties.add(EnumProperty( + 'verticalDirection', verticalDirection, + defaultValue: VerticalDirection.down)); + } +} + +class _RunMetrics { + _RunMetrics(this.mainAxisExtent, this.crossAxisExtent, this.childCount); + + final double mainAxisExtent; + final double crossAxisExtent; + final int childCount; +} + +/// Parent data for use with [CustomRenderWrap]. +class WrapParentData extends ContainerBoxParentData { + int _runIndex = 0; +} diff --git a/FlutterHelper/flutter_helper/lib/flutter_tags/main.dart b/FlutterHelper/flutter_helper/lib/flutter_tags/main.dart new file mode 100644 index 00000000..d2297ee1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/flutter_tags/main.dart @@ -0,0 +1,749 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'lib/flutter_tags.dart'; + + +void main() => runApp(FlutterTagsApp()); + +class FlutterTagsApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Tags Demo', + theme: ThemeData( + primarySwatch: Colors.blueGrey, + ), + home: MyHomePage(title: 'Flutter Tags'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State + with SingleTickerProviderStateMixin { + TabController _tabController; + ScrollController _scrollViewController; + + final List _list = [ + '0', + 'SDK', + 'plugin updates', + 'Facebook', + '哔了狗了QP又不够了', + 'Kirchhoff', + 'Italy', + 'France', + 'Spain', + '美', + 'Dart', + 'SDK', + 'Foo', + 'Select', + 'lorem ip', + '9', + 'Star', + 'Flutter Selectable Tags', + '1', + 'Hubble', + '2', + 'Input flutter tags', + 'A B C', + '8', + 'Android Studio developer', + 'welcome to the jungle', + 'Gauss', + '美术', + '互联网', + '炫舞时代', + '篝火营地', + ]; + + bool _symmetry = false; + bool _removeButton = true; + bool _singleItem = true; + bool _startDirection = false; + bool _horizontalScroll = true; + bool _withSuggesttions = false; + int _count = 0; + int _column = 0; + double _fontSize = 14; + + String _itemCombine = 'withTextBefore'; + + String _onPressed = ''; + + List _icon = [Icons.home, Icons.language, Icons.headset]; + + @override + void initState() { + super.initState(); + _tabController = TabController(length: 2, vsync: this); + _scrollViewController = ScrollController(); + + _items = _list.toList(); + } + + List _items; + + final GlobalKey _tagStateKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + //List lst = _tagStateKey.currentState?.getAllItem; lst.forEach((f) => print(f.title)); + return Scaffold( + body: NestedScrollView( + controller: _scrollViewController, + headerSliverBuilder: (BuildContext context, bool boxIsScrolled) { + return [ + SliverAppBar( + title: Text("flutter tags"), + centerTitle: true, + pinned: true, + expandedHeight: 0, + floating: true, + forceElevated: boxIsScrolled, + bottom: TabBar( + isScrollable: false, + indicatorSize: TabBarIndicatorSize.label, + labelStyle: TextStyle(fontSize: 18.0), + tabs: [ + Tab(text: "Demo 1"), + Tab(text: "Demo 2"), + ], + controller: _tabController, + ), + ) + ]; + }, + body: TabBarView( + controller: _tabController, + children: [ + CustomScrollView( + slivers: [ + SliverList( + delegate: SliverChildListDelegate([ + Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Colors.grey[300], width: 0.5))), + margin: + EdgeInsets.symmetric(horizontal: 10, vertical: 10), + child: ExpansionTile( + title: Text("Settings"), + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + child: Row( + children: [ + Checkbox( + value: _removeButton, + onChanged: (a) { + setState(() { + _removeButton = !_removeButton; + }); + }), + Text('Remove Button') + ], + ), + onTap: () { + setState(() { + _removeButton = !_removeButton; + }); + }, + ), + Padding( + padding: EdgeInsets.all(5), + ), + GestureDetector( + child: Row( + children: [ + Checkbox( + value: _symmetry, + onChanged: (a) { + setState(() { + _symmetry = !_symmetry; + }); + }), + Text('Symmetry') + ], + ), + onTap: () { + setState(() { + _symmetry = !_symmetry; + }); + }, + ), + Padding( + padding: EdgeInsets.all(5), + ), + DropdownButton( + hint: _column == 0 + ? Text("Not set") + : Text(_column.toString()), + items: _buildItems(), + onChanged: (a) { + setState(() { + _column = a; + }); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + child: Row( + children: [ + Checkbox( + value: _horizontalScroll, + onChanged: (a) { + setState(() { + _horizontalScroll = + !_horizontalScroll; + }); + }), + Text('Horizontal scroll') + ], + ), + onTap: () { + setState(() { + _horizontalScroll = !_horizontalScroll; + }); + }, + ), + GestureDetector( + child: Row( + children: [ + Checkbox( + value: _singleItem, + onChanged: (a) { + setState(() { + _singleItem = !_singleItem; + }); + }), + Text('Single Item') + ], + ), + onTap: () { + setState(() { + _singleItem = !_singleItem; + }); + }, + ), + ], + ), + Column( + children: [ + Text('Font Size'), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Slider( + value: _fontSize, + min: 6, + max: 30, + onChanged: (a) { + setState(() { + _fontSize = (a.round()).toDouble(); + }); + }, + ), + Text(_fontSize.toString()), + Padding( + padding: + EdgeInsets.symmetric(horizontal: 20), + ), + Container( + height: 30, + width: 30, + //color: Colors.blueGrey, + child: IconButton( + padding: EdgeInsets.all(0), + //color: Colors.white, + icon: Icon(Icons.add), + onPressed: () { + setState(() { + _count++; + _items.add(_count.toString()); + //_items.removeAt(3); _items.removeAt(10); + }); + }, + ), + ), + Padding( + padding: + EdgeInsets.symmetric(horizontal: 5), + ), + Container( + height: 30, + width: 30, + //color: Colors.grey, + child: IconButton( + padding: EdgeInsets.all(0), + //color: Colors.white, + icon: Icon(Icons.refresh), + onPressed: () { + setState(() { + _items = _list.toList(); + }); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + Padding( + padding: EdgeInsets.all(20), + ), + _tags1, + Container( + padding: EdgeInsets.all(20), + child: Column( + children: [ + Divider( + color: Colors.blueGrey, + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: Text(_onPressed), + ), + ], + )), + ])), + ], + ), + CustomScrollView( + slivers: [ + SliverList( + delegate: SliverChildListDelegate([ + Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Colors.grey[300], width: 0.5))), + margin: + EdgeInsets.symmetric(horizontal: 10, vertical: 10), + child: ExpansionTile( + title: Text("Settings"), + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + child: Row( + children: [ + Checkbox( + value: _withSuggesttions, + onChanged: (a) { + setState(() { + _withSuggesttions = + !_withSuggesttions; + }); + }), + Text('Suggestions') + ], + ), + onTap: () { + setState(() { + _withSuggesttions = !_withSuggesttions; + }); + }, + ), + Padding( + padding: EdgeInsets.all(20), + ), + DropdownButton( + hint: Text(_itemCombine), + items: _buildItems2(), + onChanged: (val) { + setState(() { + _itemCombine = val; + }); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + child: Row( + children: [ + Checkbox( + value: _horizontalScroll, + onChanged: (a) { + setState(() { + _horizontalScroll = + !_horizontalScroll; + }); + }), + Text('Horizontal scroll') + ], + ), + onTap: () { + setState(() { + _horizontalScroll = !_horizontalScroll; + }); + }, + ), + GestureDetector( + child: Row( + children: [ + Checkbox( + value: _startDirection, + onChanged: (a) { + setState(() { + _startDirection = !_startDirection; + }); + }), + Text('Start Direction') + ], + ), + onTap: () { + setState(() { + _startDirection = !_startDirection; + }); + }, + ), + ], + ), + Column( + children: [ + Text('Font Size'), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Slider( + value: _fontSize, + min: 6, + max: 30, + onChanged: (a) { + setState(() { + _fontSize = (a.round()).toDouble(); + }); + }, + ), + Text(_fontSize.toString()), + ], + ), + ], + ), + ], + ), + ), + Padding( + padding: EdgeInsets.all(20), + ), + _tags2, + Container( + padding: EdgeInsets.all(20), + child: Column( + children: [ + Divider( + color: Colors.blueGrey, + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: Text(_onPressed), + ), + ], + )), + ])), + ], + ), + ], + )), + ); + } + + Widget get _tags1 { + return Tags( + key: _tagStateKey, + symmetry: _symmetry, + columns: _column, + horizontalScroll: _horizontalScroll, + //verticalDirection: VerticalDirection.up, textDirection: TextDirection.rtl, + heightHorizontalScroll: 60 * (_fontSize / 14), + itemCount: _items.length, + itemBuilder: (index) { + final item = _items[index]; + + return ItemTags( + key: Key(index.toString()), + index: index, + title: item, + pressEnabled: true, + activeColor: Colors.blueGrey[600], + singleItem: _singleItem, + splashColor: Colors.green, + combine: ItemTagsCombine.withTextBefore, + image: index > 0 && index < 5 + ? ItemTagsImage( + //image: AssetImage("img/p$index.jpg"), + child: Image.network( + "http://www.clipartpanda.com/clipart_images/user-66327738/download", + width: 16 * _fontSize / 14, + height: 16 * _fontSize / 14, + )) + : (1 == 1 + ? ItemTagsImage( + image: NetworkImage( + "https://d32ogoqmya1dw8.cloudfront.net/images/serc/empty_user_icon_256.v2.png"), + ) + : null), + icon: (item == '0' || item == '1' || item == '2') + ? ItemTagsIcon( + icon: _icon[int.parse(item)], + ) + : null, + removeButton: _removeButton + ? ItemTagsRemoveButton( + onRemoved: () { + setState(() { + _items.removeAt(index); + }); + return true; + }, + ) + : null, + textScaleFactor: + utf8.encode(item.substring(0, 1)).length > 2 ? 0.8 : 1, + textStyle: TextStyle( + fontSize: _fontSize, + ), + onPressed: (item) => print(item), + ); + }, + ); + } + + // Position for popup menu + Offset _tapPosition; + + Widget get _tags2 { + //popup Menu + final RenderBox overlay = Overlay.of(context).context?.findRenderObject(); + + ItemTagsCombine combine = ItemTagsCombine.onlyText; + + switch (_itemCombine) { + case 'onlyText': + combine = ItemTagsCombine.onlyText; + break; + case 'onlyIcon': + combine = ItemTagsCombine.onlyIcon; + break; + case 'onlyIcon': + combine = ItemTagsCombine.onlyIcon; + break; + case 'onlyImage': + combine = ItemTagsCombine.onlyImage; + break; + case 'imageOrIconOrText': + combine = ItemTagsCombine.imageOrIconOrText; + break; + case 'withTextAfter': + combine = ItemTagsCombine.withTextAfter; + break; + case 'withTextBefore': + combine = ItemTagsCombine.withTextBefore; + break; + } + + return Tags( + key: Key("2"), + symmetry: _symmetry, + columns: _column, + horizontalScroll: _horizontalScroll, + verticalDirection: + _startDirection ? VerticalDirection.up : VerticalDirection.down, + textDirection: _startDirection ? TextDirection.rtl : TextDirection.ltr, + heightHorizontalScroll: 60 * (_fontSize / 14), + textField: _textField, + itemCount: _items.length, + itemBuilder: (index) { + final item = _items[index]; + + return GestureDetector( + child: ItemTags( + key: Key(index.toString()), + index: index, + title: item, + pressEnabled: false, + activeColor: Colors.green[400], + combine: combine, + image: index > 0 && index < 5 + ? ItemTagsImage(image: AssetImage("img/p$index.jpg")) + : (1 == 1 + ? ItemTagsImage( + image: NetworkImage( + "https://image.flaticon.com/icons/png/512/44/44948.png")) + : null), + icon: (item == '0' || item == '1' || item == '2') + ? ItemTagsIcon( + icon: _icon[int.parse(item)], + ) + : null, + removeButton: ItemTagsRemoveButton( + backgroundColor: Colors.green[900], + onRemoved: () { + setState(() { + _items.removeAt(index); + }); + return true; + }, + ), + textScaleFactor: + utf8.encode(item.substring(0, 1)).length > 2 ? 0.8 : 1, + textStyle: TextStyle( + fontSize: _fontSize, + ), + ), + onTapDown: (details) => _tapPosition = details.globalPosition, + onLongPress: () { + showMenu( + //semanticLabel: item, + items: [ + PopupMenuItem( + child: Text(item, style: TextStyle(color: Colors.blueGrey)), + enabled: false, + ), + PopupMenuDivider(), + PopupMenuItem( + value: 1, + child: Row( + children: [ + Icon(Icons.content_copy), + Text("Copy text"), + ], + ), + ), + ], + context: context, + position: RelativeRect.fromRect( + _tapPosition & Size(40, 40), + Offset.zero & + overlay + .size) // & RelativeRect.fromLTRB(65.0, 40.0, 0.0, 0.0), + ) + .then((value) { + if (value == 1) Clipboard.setData(ClipboardData(text: item)); + }); + }, + ); + }, + ); + } + + TagsTextField get _textField { + return TagsTextField( + autofocus: false, + width: double.infinity, + padding: EdgeInsets.symmetric(horizontal: 10), + textStyle: TextStyle( + fontSize: _fontSize, + //height: 1 + ), + enabled: true, + constraintSuggestion: true, + suggestions: _withSuggesttions + ? [ + "One", + "two", + "android", + "Dart", + "flutter", + "test", + "tests", + "androids", + "androidsaaa", + "Test", + "suggest", + "suggestions", + "互联网", + "last", + "lest", + "炫舞时代" + ] + : null, + onSubmitted: (String str) { + setState(() { + _items.add(str); + }); + }, + ); + } + + List _buildItems() { + List list = []; + + int count = 19; + + list.add( + DropdownMenuItem( + child: Text("Not set"), + value: 0, + ), + ); + + for (int i = 1; i < count; i++) + list.add( + DropdownMenuItem( + child: Text(i.toString()), + value: i, + ), + ); + + return list; + } + + List _buildItems2() { + List list = []; + + list.add(DropdownMenuItem( + child: Text("onlyText"), + value: 'onlyText', + )); + + list.add(DropdownMenuItem( + child: Text("onlyIcon"), + value: 'onlyIcon', + )); + list.add(DropdownMenuItem( + child: Text("onlyImage"), + value: 'onlyImage', + )); + list.add(DropdownMenuItem( + child: Text("imageOrIconOrText"), + value: 'imageOrIconOrText', + )); + list.add(DropdownMenuItem( + child: Text("withTextBefore"), + value: 'withTextBefore', + )); + list.add(DropdownMenuItem( + child: Text("withTextAfter"), + value: 'withTextAfter', + )); + + return list; + } +} diff --git a/FlutterHelper/flutter_helper/lib/generated/intl/messages_all.dart b/FlutterHelper/flutter_helper/lib/generated/intl/messages_all.dart new file mode 100644 index 00000000..3be99e81 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/generated/intl/messages_all.dart @@ -0,0 +1,71 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that looks up messages for specific locales by +// delegating to the appropriate library. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:implementation_imports, file_names, unnecessary_new +// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering +// ignore_for_file:argument_type_not_assignable, invalid_assignment +// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases +// ignore_for_file:comment_references + +import 'dart:async'; + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; +import 'package:intl/src/intl_helpers.dart'; + +import 'messages_en.dart' as messages_en; +import 'messages_ko.dart' as messages_ko; +import 'messages_zh.dart' as messages_zh; + +typedef Future LibraryLoader(); +Map _deferredLibraries = { + 'en': () => new Future.value(null), + 'ko': () => new Future.value(null), + 'zh': () => new Future.value(null), +}; + +MessageLookupByLibrary _findExact(String localeName) { + switch (localeName) { + case 'en': + return messages_en.messages; + case 'ko': + return messages_ko.messages; + case 'zh': + return messages_zh.messages; + default: + return null; + } +} + +/// User programs should call this before using [localeName] for messages. +Future initializeMessages(String localeName) async { + var availableLocale = Intl.verifiedLocale( + localeName, + (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); + if (availableLocale == null) { + return new Future.value(false); + } + var lib = _deferredLibraries[availableLocale]; + await (lib == null ? new Future.value(false) : lib()); + initializeInternalMessageLookup(() => new CompositeMessageLookup()); + messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); + return new Future.value(true); +} + +bool _messagesExistFor(String locale) { + try { + return _findExact(locale) != null; + } catch (e) { + return false; + } +} + +MessageLookupByLibrary _findGeneratedMessagesFor(String locale) { + var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, + onFailure: (_) => null); + if (actualLocale == null) return null; + return _findExact(actualLocale); +} diff --git a/FlutterHelper/flutter_helper/lib/generated/intl/messages_en.dart b/FlutterHelper/flutter_helper/lib/generated/intl/messages_en.dart new file mode 100644 index 00000000..cddc3d47 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/generated/intl/messages_en.dart @@ -0,0 +1,52 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a en locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'en'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static _notInlinedMessages(_) => { + "check_network_describe" : MessageLookupByLibrary.simpleMessage("We are currently checking your network status and generating a log, which would help our developers to better solve your problem. "), + "check_network_state" : MessageLookupByLibrary.simpleMessage("Checking network status..."), + "check_network_toast" : MessageLookupByLibrary.simpleMessage("Diagnostics complete, log has been generated."), + "check_network_warning" : MessageLookupByLibrary.simpleMessage("Please do not quit this page or the APP during the process."), + "contact_via_whatsapp_describe" : MessageLookupByLibrary.simpleMessage("When you encounter a problem, you can communicate with the staff from the institution via WhatsApp"), + "copy_link_success" : MessageLookupByLibrary.simpleMessage("Link has been successfully copied to clipboard."), + "deadline" : MessageLookupByLibrary.simpleMessage("Deadline:%@"), + "download_file_invalid" : MessageLookupByLibrary.simpleMessage("This content is no longer available to be watched and will be cleared."), + "faq_describe" : MessageLookupByLibrary.simpleMessage("You can find answers to the most frequently asked questions here."), + "helloWorld" : MessageLookupByLibrary.simpleMessage("Hello World!"), + "leave_early" : MessageLookupByLibrary.simpleMessage("Leave Early"), + "leave_message_describe" : MessageLookupByLibrary.simpleMessage("When you encounter a problem, you can leave a message to the institution. The institution will contact you later."), + "live_end" : MessageLookupByLibrary.simpleMessage("Live broadcast has ended"), + "not_login_reminder_batch" : MessageLookupByLibrary.simpleMessage("Login to see your batch"), + "not_login_reminder_chatlist" : MessageLookupByLibrary.simpleMessage("Login to chat with your teacher"), + "not_login_reminder_course" : MessageLookupByLibrary.simpleMessage("Login to see your courses"), + "not_login_reminder_timatable" : MessageLookupByLibrary.simpleMessage("Login to see your timetable"), + "report_problem_describe" : MessageLookupByLibrary.simpleMessage("You can use this feature to report a bug/issue to the developers.\t"), + "report_problem_question_content" : MessageLookupByLibrary.simpleMessage("Please describe the problems you encountered."), + "report_problem_question_title" : MessageLookupByLibrary.simpleMessage("What problems have you encountered?"), + "report_problem_toast" : MessageLookupByLibrary.simpleMessage("We have received your message and thank you for your feedback!"), + "router_uri_cannot_open" : MessageLookupByLibrary.simpleMessage("This function is not available on APP. Please move to the pc website for operation."), + "send_otp" : MessageLookupByLibrary.simpleMessage("Send OTP"), + "timetable" : MessageLookupByLibrary.simpleMessage("Timatable"), + "timetable_Nodata_alertString" : MessageLookupByLibrary.simpleMessage("Looks like you don\'t have any events!"), + "udb_kickoff_comment_msg" : MessageLookupByLibrary.simpleMessage("Your account has been kicked off.Please log in again!"), + "zoom_error_livelinkInvalid" : MessageLookupByLibrary.simpleMessage("This live link is not valid. Please contact the institution to update.") + }; +} diff --git a/FlutterHelper/flutter_helper/lib/generated/intl/messages_ko.dart b/FlutterHelper/flutter_helper/lib/generated/intl/messages_ko.dart new file mode 100644 index 00000000..73667c86 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/generated/intl/messages_ko.dart @@ -0,0 +1,51 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a ko locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'ko'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static _notInlinedMessages(_) => { + "check_network_describe" : MessageLookupByLibrary.simpleMessage("현재 네트워크 상황을 검사하고 로그를 생성하고 있습니다. 이 로그는 개발자들이 문제를 해결하는 데 도움이 됩니다. "), + "check_network_state" : MessageLookupByLibrary.simpleMessage("네트워크 측정 중..."), + "check_network_toast" : MessageLookupByLibrary.simpleMessage("검사가 끝났습니다. 로그가 생성되었습니다."), + "check_network_warning" : MessageLookupByLibrary.simpleMessage("네트워크 검사 중... 페이지/앱을 종료하지 마십시오."), + "contact_via_whatsapp_describe" : MessageLookupByLibrary.simpleMessage("이 버튼을 누르시면 카카오톡을 통해 기관과 연락할 수 있습니다."), + "copy_link_success" : MessageLookupByLibrary.simpleMessage("링크가 클립 보드에 성공적으로 복사되었습니다."), + "deadline" : MessageLookupByLibrary.simpleMessage("마감일:%@"), + "download_file_invalid" : MessageLookupByLibrary.simpleMessage("이 콘텐츠는 더 이상 시청할 수 없으며 곧 삭제될 예정입니다."), + "faq_describe" : MessageLookupByLibrary.simpleMessage("이곳에서 자주 묻는 질문에 대한 답변을 찾을 수 있습니다."), + "leave_early" : MessageLookupByLibrary.simpleMessage("조퇴"), + "leave_message_describe" : MessageLookupByLibrary.simpleMessage("이 기능을 통해 기관에 메시지를 남겨 문의할 수 있습니다."), + "live_end" : MessageLookupByLibrary.simpleMessage("실시간 수업은 끝났습니다"), + "not_login_reminder_batch" : MessageLookupByLibrary.simpleMessage("로그인 후 코스 확인"), + "not_login_reminder_chatlist" : MessageLookupByLibrary.simpleMessage("로그인 후 선생님과 채팅하세요"), + "not_login_reminder_course" : MessageLookupByLibrary.simpleMessage("로그인 후 코스 확인"), + "not_login_reminder_timatable" : MessageLookupByLibrary.simpleMessage("시간표를 확인하시려면 먼저 로그인하십시오"), + "report_problem_describe" : MessageLookupByLibrary.simpleMessage("문제 발생시 이 기능을 통해 개발자에게 피드백을 줄수 있습니다."), + "report_problem_question_content" : MessageLookupByLibrary.simpleMessage("사용 중 발생한 문제를 자세히 설명해주십시오."), + "report_problem_question_title" : MessageLookupByLibrary.simpleMessage("어떤 어려움이 있으십니까?"), + "report_problem_toast" : MessageLookupByLibrary.simpleMessage("문제 접수되었습니다. 감사합니다!"), + "router_uri_cannot_open" : MessageLookupByLibrary.simpleMessage("이 기능은 모바일에서 사용할 수 없습니다. PC 웹사이트로 이동하시기 바랍니다."), + "send_otp" : MessageLookupByLibrary.simpleMessage("인증번호 보내기"), + "timetable" : MessageLookupByLibrary.simpleMessage("시간표"), + "timetable_Nodata_alertString" : MessageLookupByLibrary.simpleMessage("일정이 없습니다."), + "udb_kickoff_comment_msg" : MessageLookupByLibrary.simpleMessage("계정 실행이 중지되었습니다. 재로그인 하세요"), + "zoom_error_livelinkInvalid" : MessageLookupByLibrary.simpleMessage("이 링크는 기한이 지났습니다. 업데이트 하시려면 기관에 문의하십시오.") + }; +} diff --git a/FlutterHelper/flutter_helper/lib/generated/intl/messages_zh.dart b/FlutterHelper/flutter_helper/lib/generated/intl/messages_zh.dart new file mode 100644 index 00000000..84ebf2dc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/generated/intl/messages_zh.dart @@ -0,0 +1,51 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a zh locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'zh'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static _notInlinedMessages(_) => { + "check_network_describe" : MessageLookupByLibrary.simpleMessage(""), + "check_network_state" : MessageLookupByLibrary.simpleMessage(""), + "check_network_toast" : MessageLookupByLibrary.simpleMessage(""), + "check_network_warning" : MessageLookupByLibrary.simpleMessage(""), + "contact_via_whatsapp_describe" : MessageLookupByLibrary.simpleMessage(""), + "copy_link_success" : MessageLookupByLibrary.simpleMessage(""), + "deadline" : MessageLookupByLibrary.simpleMessage(""), + "download_file_invalid" : MessageLookupByLibrary.simpleMessage(""), + "faq_describe" : MessageLookupByLibrary.simpleMessage(""), + "leave_early" : MessageLookupByLibrary.simpleMessage(""), + "leave_message_describe" : MessageLookupByLibrary.simpleMessage(""), + "live_end" : MessageLookupByLibrary.simpleMessage(""), + "not_login_reminder_batch" : MessageLookupByLibrary.simpleMessage(""), + "not_login_reminder_chatlist" : MessageLookupByLibrary.simpleMessage(""), + "not_login_reminder_course" : MessageLookupByLibrary.simpleMessage(""), + "not_login_reminder_timatable" : MessageLookupByLibrary.simpleMessage(""), + "report_problem_describe" : MessageLookupByLibrary.simpleMessage(""), + "report_problem_question_content" : MessageLookupByLibrary.simpleMessage(""), + "report_problem_question_title" : MessageLookupByLibrary.simpleMessage(""), + "report_problem_toast" : MessageLookupByLibrary.simpleMessage(""), + "router_uri_cannot_open" : MessageLookupByLibrary.simpleMessage(""), + "send_otp" : MessageLookupByLibrary.simpleMessage("发送验证码"), + "timetable" : MessageLookupByLibrary.simpleMessage(""), + "timetable_Nodata_alertString" : MessageLookupByLibrary.simpleMessage(""), + "udb_kickoff_comment_msg" : MessageLookupByLibrary.simpleMessage(""), + "zoom_error_livelinkInvalid" : MessageLookupByLibrary.simpleMessage("") + }; +} diff --git a/FlutterHelper/flutter_helper/lib/generated/l10n.dart b/FlutterHelper/flutter_helper/lib/generated/l10n.dart new file mode 100644 index 00000000..59f95d3a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/generated/l10n.dart @@ -0,0 +1,337 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'intl/messages_all.dart'; + +// ************************************************************************** +// Generator: Flutter Intl IDE plugin +// Made by Localizely +// ************************************************************************** + +// ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars +// ignore_for_file: join_return_with_assignment, prefer_final_in_for_each +// ignore_for_file: avoid_redundant_argument_values + +class S { + S(); + + static S current; + + static const AppLocalizationDelegate delegate = + AppLocalizationDelegate(); + + static Future load(Locale locale) { + final name = (locale.countryCode?.isEmpty ?? false) ? locale.languageCode : locale.toString(); + final localeName = Intl.canonicalizedLocale(name); + return initializeMessages(localeName).then((_) { + Intl.defaultLocale = localeName; + S.current = S(); + + return S.current; + }); + } + + static S of(BuildContext context) { + return Localizations.of(context, S); + } + + /// `Link has been successfully copied to clipboard.` + String get copy_link_success { + return Intl.message( + 'Link has been successfully copied to clipboard.', + name: 'copy_link_success', + desc: '', + args: [], + ); + } + + /// `Your account has been kicked off.Please log in again!` + String get udb_kickoff_comment_msg { + return Intl.message( + 'Your account has been kicked off.Please log in again!', + name: 'udb_kickoff_comment_msg', + desc: '', + args: [], + ); + } + + /// `We have received your message and thank you for your feedback!` + String get report_problem_toast { + return Intl.message( + 'We have received your message and thank you for your feedback!', + name: 'report_problem_toast', + desc: '', + args: [], + ); + } + + /// `Send OTP` + String get send_otp { + return Intl.message( + 'Send OTP', + name: 'send_otp', + desc: '', + args: [], + ); + } + + /// `Timatable` + String get timetable { + return Intl.message( + 'Timatable', + name: 'timetable', + desc: '', + args: [], + ); + } + + /// `This content is no longer available to be watched and will be cleared.` + String get download_file_invalid { + return Intl.message( + 'This content is no longer available to be watched and will be cleared.', + name: 'download_file_invalid', + desc: '', + args: [], + ); + } + + /// `This live link is not valid. Please contact the institution to update.` + String get zoom_error_livelinkInvalid { + return Intl.message( + 'This live link is not valid. Please contact the institution to update.', + name: 'zoom_error_livelinkInvalid', + desc: '', + args: [], + ); + } + + /// `Login to chat with your teacher` + String get not_login_reminder_chatlist { + return Intl.message( + 'Login to chat with your teacher', + name: 'not_login_reminder_chatlist', + desc: '', + args: [], + ); + } + + /// `Login to see your timetable` + String get not_login_reminder_timatable { + return Intl.message( + 'Login to see your timetable', + name: 'not_login_reminder_timatable', + desc: '', + args: [], + ); + } + + /// `Login to see your batch` + String get not_login_reminder_batch { + return Intl.message( + 'Login to see your batch', + name: 'not_login_reminder_batch', + desc: '', + args: [], + ); + } + + /// `Login to see your courses` + String get not_login_reminder_course { + return Intl.message( + 'Login to see your courses', + name: 'not_login_reminder_course', + desc: '', + args: [], + ); + } + + /// `Diagnostics complete, log has been generated.` + String get check_network_toast { + return Intl.message( + 'Diagnostics complete, log has been generated.', + name: 'check_network_toast', + desc: '', + args: [], + ); + } + + /// `Please do not quit this page or the APP during the process.` + String get check_network_warning { + return Intl.message( + 'Please do not quit this page or the APP during the process.', + name: 'check_network_warning', + desc: '', + args: [], + ); + } + + /// `We are currently checking your network status and generating a log, which would help our developers to better solve your problem. ` + String get check_network_describe { + return Intl.message( + 'We are currently checking your network status and generating a log, which would help our developers to better solve your problem. ', + name: 'check_network_describe', + desc: '', + args: [], + ); + } + + /// `Leave Early` + String get leave_early { + return Intl.message( + 'Leave Early', + name: 'leave_early', + desc: '', + args: [], + ); + } + + /// `Checking network status...` + String get check_network_state { + return Intl.message( + 'Checking network status...', + name: 'check_network_state', + desc: '', + args: [], + ); + } + + /// `Live broadcast has ended` + String get live_end { + return Intl.message( + 'Live broadcast has ended', + name: 'live_end', + desc: '', + args: [], + ); + } + + /// `Please describe the problems you encountered.` + String get report_problem_question_content { + return Intl.message( + 'Please describe the problems you encountered.', + name: 'report_problem_question_content', + desc: '', + args: [], + ); + } + + /// `What problems have you encountered?` + String get report_problem_question_title { + return Intl.message( + 'What problems have you encountered?', + name: 'report_problem_question_title', + desc: '', + args: [], + ); + } + + /// `You can use this feature to report a bug/issue to the developers. ` + String get report_problem_describe { + return Intl.message( + 'You can use this feature to report a bug/issue to the developers. ', + name: 'report_problem_describe', + desc: '', + args: [], + ); + } + + /// `When you encounter a problem, you can communicate with the staff from the institution via WhatsApp` + String get contact_via_whatsapp_describe { + return Intl.message( + 'When you encounter a problem, you can communicate with the staff from the institution via WhatsApp', + name: 'contact_via_whatsapp_describe', + desc: '', + args: [], + ); + } + + /// `When you encounter a problem, you can leave a message to the institution. The institution will contact you later.` + String get leave_message_describe { + return Intl.message( + 'When you encounter a problem, you can leave a message to the institution. The institution will contact you later.', + name: 'leave_message_describe', + desc: '', + args: [], + ); + } + + /// `You can find answers to the most frequently asked questions here.` + String get faq_describe { + return Intl.message( + 'You can find answers to the most frequently asked questions here.', + name: 'faq_describe', + desc: '', + args: [], + ); + } + + /// `Looks like you don't have any events!` + String get timetable_Nodata_alertString { + return Intl.message( + 'Looks like you don\'t have any events!', + name: 'timetable_Nodata_alertString', + desc: '', + args: [], + ); + } + + /// `Deadline:%@` + String get deadline { + return Intl.message( + 'Deadline:%@', + name: 'deadline', + desc: '', + args: [], + ); + } + + /// `This function is not available on APP. Please move to the pc website for operation.` + String get router_uri_cannot_open { + return Intl.message( + 'This function is not available on APP. Please move to the pc website for operation.', + name: 'router_uri_cannot_open', + desc: '', + args: [], + ); + } + + /// `Hello World!` + String get helloWorld { + return Intl.message( + 'Hello World!', + name: 'helloWorld', + desc: 'The conventional newborn programmer greeting', + args: [], + ); + } +} + +class AppLocalizationDelegate extends LocalizationsDelegate { + const AppLocalizationDelegate(); + + List get supportedLocales { + return const [ + Locale.fromSubtags(languageCode: 'en'), + Locale.fromSubtags(languageCode: 'ko'), + Locale.fromSubtags(languageCode: 'zh'), + ]; + } + + @override + bool isSupported(Locale locale) => _isSupported(locale); + @override + Future load(Locale locale) => S.load(locale); + @override + bool shouldReload(AppLocalizationDelegate old) => false; + + bool _isSupported(Locale locale) { + if (locale != null) { + for (var supportedLocale in supportedLocales) { + if (supportedLocale.languageCode == locale.languageCode) { + return true; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/hightlight/HighIconButton.dart b/FlutterHelper/flutter_helper/lib/hightlight/HighIconButton.dart new file mode 100644 index 00000000..7ea17108 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/hightlight/HighIconButton.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/syntax_highlight.dart'; + +class HightIconButton extends StatelessWidget { + @override + Widget build(BuildContext context) => IconButton( + onPressed: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return HighLight(); + })); + }, + icon: Icon(Icons.code), + tooltip: "显示源代码", + ); +} diff --git a/FlutterHelper/flutter_helper/lib/hightlight/mixin_highlight.dart b/FlutterHelper/flutter_helper/lib/hightlight/mixin_highlight.dart new file mode 100644 index 00000000..2cc344a6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/hightlight/mixin_highlight.dart @@ -0,0 +1,10 @@ +mixin HighMixin { + High getHigh(); +} + +class High { + final String title; + final String text; + + const High(this.title, this.text); +} diff --git a/FlutterHelper/flutter_helper/lib/hightlight/syntax_highlight.dart b/FlutterHelper/flutter_helper/lib/hightlight/syntax_highlight.dart new file mode 100644 index 00000000..cb4b2f0c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/hightlight/syntax_highlight.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/utils.dart'; +import 'package:syntax_highlighter/syntax_highlighter.dart'; + +class HighLight extends StatefulWidget { + final String title; + final String text; + final Widget outWidget; + + const HighLight( + {Key key, this.text = _exampleCode, this.title = "TEST", this.outWidget}) + : super(key: key); + + @override + _HighLightState createState() => _HighLightState(); +} + +class _HighLightState extends State { + @override + Widget build(BuildContext context) { + final SyntaxHighlighterStyle style = + Theme.of(context).brightness == Brightness.dark + ? SyntaxHighlighterStyle.darkThemeStyle() + : SyntaxHighlighterStyle.lightThemeStyle(); + return MaterialApp( + title: 'Syntax Highlighter Example', + theme: ThemeData(primarySwatch: Colors.blue), + home: Scaffold( + floatingActionButton: CircleAvatar( + child: TextButton( + onPressed: () { + showToast("跳转效果"); + Navigator.push(context, MaterialPageRoute(builder: (context) { + return widget.outWidget; + })); + }, + child: Text( + '跳', + style: TextStyle( + fontWeight: FontWeight.w900, + color: Colors.red, + ), + )), + ), + appBar: AppBar( + toolbarHeight: 30, + title: Text(widget.title), + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Icon(Icons.arrow_back)), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: RichText( + softWrap: true, + text: TextSpan( + style: TextStyle(fontFamily: 'monospace', fontSize: 10.0), + children: [ + DartSyntaxHighlighter(style).format(widget.text), + ], + ), + ), + ), + ), + ), + ); + } +} + +const _exampleCode = """ + class HighLight extends StatefulWidget { + @override + _HighLightState createState() => _HighLightState(); +} + +class _HighLightState extends State { + static const _exampleCode = ''' + class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState();} + '''; + + @override + Widget build(BuildContext context) { + final SyntaxHighlighterStyle style = + Theme.of(context).brightness == Brightness.dark + ? SyntaxHighlighterStyle.darkThemeStyle() + : SyntaxHighlighterStyle.lightThemeStyle(); + return MaterialApp( + title: 'Syntax Highlighter Example', + theme: ThemeData(primarySwatch: Colors.blue), + home: Scaffold( + appBar: AppBar(title: Text("TEST")), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: RichText( + text: TextSpan( + style: TextStyle(fontFamily: 'monospace', fontSize: 10.0), + children: [ + DartSyntaxHighlighter(style).format(_exampleCode), + ], + ), + ), + ), + ), + ), + ); + } +} + + """; diff --git a/FlutterHelper/flutter_helper/lib/l10n/intl_en.arb b/FlutterHelper/flutter_helper/lib/l10n/intl_en.arb new file mode 100644 index 00000000..4e2e1c18 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/l10n/intl_en.arb @@ -0,0 +1,32 @@ +{ + "copy_link_success": "Link has been successfully copied to clipboard.", + "udb_kickoff_comment_msg": "Your account has been kicked off.Please log in again!", + "report_problem_toast": "We have received your message and thank you for your feedback!", + "send_otp": "Send OTP", + "timetable": "Timatable", + "download_file_invalid": "This content is no longer available to be watched and will be cleared.", + "zoom_error_livelinkInvalid": "This live link is not valid. Please contact the institution to update.", + "not_login_reminder_chatlist": "Login to chat with your teacher", + "not_login_reminder_timatable": "Login to see your timetable", + "not_login_reminder_batch": "Login to see your batch", + "not_login_reminder_course": "Login to see your courses", + "check_network_toast": "Diagnostics complete, log has been generated.", + "check_network_warning": "Please do not quit this page or the APP during the process.", + "check_network_describe": "We are currently checking your network status and generating a log, which would help our developers to better solve your problem. ", + "leave_early": "Leave Early", + "check_network_state": "Checking network status...", + "live_end": "Live broadcast has ended", + "report_problem_question_content": "Please describe the problems you encountered.", + "report_problem_question_title": "What problems have you encountered?", + "report_problem_describe": "You can use this feature to report a bug/issue to the developers.\t", + "contact_via_whatsapp_describe": "When you encounter a problem, you can communicate with the staff from the institution via WhatsApp", + "leave_message_describe": "When you encounter a problem, you can leave a message to the institution. The institution will contact you later.", + "faq_describe": "You can find answers to the most frequently asked questions here.", + "timetable_Nodata_alertString": "Looks like you don't have any events!", + "deadline": "Deadline:%@", + "router_uri_cannot_open": "This function is not available on APP. Please move to the pc website for operation.", + "helloWorld": "Hello World!", + "@helloWorld": { + "description": "The conventional newborn programmer greeting" + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/l10n/intl_ko.arb b/FlutterHelper/flutter_helper/lib/l10n/intl_ko.arb new file mode 100644 index 00000000..81cab5f1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/l10n/intl_ko.arb @@ -0,0 +1,29 @@ +{ + "copy_link_success": "링크가 클립 보드에 성공적으로 복사되었습니다.", + "udb_kickoff_comment_msg": "계정 실행이 중지되었습니다. 재로그인 하세요", + "report_problem_toast": "문제 접수되었습니다. 감사합니다!", + "ResendFormats": "인증번호 재전송(%lds)", + "send_otp": "인증번호 보내기", + "timetable": "시간표", + "download_file_invalid": "이 콘텐츠는 더 이상 시청할 수 없으며 곧 삭제될 예정입니다.", + "zoom_error_livelinkInvalid": "이 링크는 기한이 지났습니다. 업데이트 하시려면 기관에 문의하십시오.", + "not_login_reminder_chatlist": "로그인 후 선생님과 채팅하세요", + "not_login_reminder_timatable": "시간표를 확인하시려면 먼저 로그인하십시오", + "not_login_reminder_batch": "로그인 후 코스 확인", + "not_login_reminder_course": "로그인 후 코스 확인", + "check_network_toast": "검사가 끝났습니다. 로그가 생성되었습니다.", + "check_network_warning": "네트워크 검사 중... 페이지/앱을 종료하지 마십시오.", + "check_network_describe": "현재 네트워크 상황을 검사하고 로그를 생성하고 있습니다. 이 로그는 개발자들이 문제를 해결하는 데 도움이 됩니다. ", + "leave_early": "조퇴", + "check_network_state": "네트워크 측정 중...", + "live_end": "실시간 수업은 끝났습니다", + "report_problem_question_content": "사용 중 발생한 문제를 자세히 설명해주십시오.", + "report_problem_question_title": "어떤 어려움이 있으십니까?", + "report_problem_describe": "문제 발생시 이 기능을 통해 개발자에게 피드백을 줄수 있습니다.", + "contact_via_whatsapp_describe": "이 버튼을 누르시면 카카오톡을 통해 기관과 연락할 수 있습니다.", + "leave_message_describe": "이 기능을 통해 기관에 메시지를 남겨 문의할 수 있습니다.", + "faq_describe": "이곳에서 자주 묻는 질문에 대한 답변을 찾을 수 있습니다.", + "timetable_Nodata_alertString": "일정이 없습니다.", + "deadline": "마감일:%@", + "router_uri_cannot_open": "이 기능은 모바일에서 사용할 수 없습니다. PC 웹사이트로 이동하시기 바랍니다." +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/l10n/intl_zh.arb b/FlutterHelper/flutter_helper/lib/l10n/intl_zh.arb new file mode 100644 index 00000000..f630adba --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/l10n/intl_zh.arb @@ -0,0 +1,29 @@ +{ + "copy_link_success": "", + "udb_kickoff_comment_msg": "", + "report_problem_toast": "", + "ResendFormats": "", + "send_otp": "发送验证码", + "timetable": "", + "download_file_invalid": "", + "zoom_error_livelinkInvalid": "", + "not_login_reminder_chatlist": "", + "not_login_reminder_timatable": "", + "not_login_reminder_batch": "", + "not_login_reminder_course": "", + "check_network_toast": "", + "check_network_warning": "", + "check_network_describe": "", + "leave_early": "", + "check_network_state": "", + "live_end": "", + "report_problem_question_content": "", + "report_problem_question_title": "", + "report_problem_describe": "", + "contact_via_whatsapp_describe": "", + "leave_message_describe": "", + "faq_describe": "", + "timetable_Nodata_alertString": "", + "deadline": "", + "router_uri_cannot_open": "" +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/language/languagea_app.dart b/FlutterHelper/flutter_helper/lib/language/languagea_app.dart new file mode 100644 index 00000000..eefa2468 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/language/languagea_app.dart @@ -0,0 +1,44 @@ +import 'package:flutter_helper/generated/l10n.dart'; +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; // 国际化 + +class LanguageApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + + // var localization = AppLocalizationDelegate(); + // var support = localization.supportedLocales; + return const MaterialApp( + title: 'Localizations Sample App', + locale: Locale('ko', ''), + localizationsDelegates: [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate + ], + supportedLocales: [ + Locale('en', ''), //English, no country code + Locale('ko', ''), //Spanish, no country code + Locale('zh', ''), //Spanish, no country code + ], + home: Scaffold( + body: _MyHome(), + ), + ); + } +} + +class _MyHome extends StatefulWidget { + const _MyHome(); + + @override + __MyHomeState createState() => __MyHomeState(); +} + +class __MyHomeState extends State<_MyHome> { + @override + Widget build(BuildContext context) { + return Center(child: Text(S.of(context).check_network_describe)); + } +} diff --git a/FlutterHelper/flutter_helper/lib/main.dart b/FlutterHelper/flutter_helper/lib/main.dart new file mode 100644 index 00000000..cee9b78a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/main.dart @@ -0,0 +1,118 @@ +import 'dart:ffi'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/boss_app.dart'; +import 'package:flutter_helper/language/languagea_app.dart'; +import 'package:flutter_helper/other/other_app.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/myapp.dart'; +import 'package:flutter_helper/templates/main.dart'; +import 'package:flutter_helper/trip/trip_app.dart'; +import 'package:flutter_helper/utils/util_log.dart'; +import 'package:flutter_helper/widgets/widgets_page.dart'; + +import 'samples/main.dart'; +import 'templates/awesome_flutter/awesome.dart'; +import 'templates/fonts/main.dart'; +import 'templates/navigator_v2/main.dart'; +import 'templates/todo/main.dart'; + +void main() { + LogUtil.init(isDebug: true); + + runApp(_HomeApp()); +} + +class _HomeApp extends StatefulWidget { + @override + __HomeAppState createState() => __HomeAppState(); +} + +class __HomeAppState extends State<_HomeApp> { + var listApp = [ + AppData(app: BossApp()), + AppData(app: TripApp(), imageUrl: 'images/ic_trip.png'), + AppData(app: WidgetPage(), imageUrl: 'images/bird.png'), + AppData(app: SamplesApp(), imageUrl: 'assets/flutter.png'), + AppData(app: TemplatesApp(), imageUrl: 'images/poster.png'), + AppData(app: FlutterUiKitApp(), imageUrl: 'assets/images/pk.jpg'), + AppData(app: GoogleFontsApp(), imageUrl: 'assets/fonts.png'), + AppData(app: LanguageApp(), imageUrl: 'images/beatiful_lady.png'), + AppData(app: TodoApp(), imageUrl: 'assets/todo.png'), + AppData(app: AwesomeFlutterApp(), imageUrl: 'assets/awsome.png'), + AppData(app: NavigatorVeggiesApp(), imageUrl: 'assets/navigation_route.png'), + ]; + + _buildGridViewBuilder() { + return GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + childAspectRatio: 1, + ), + itemCount: listApp.length, + itemBuilder: (BuildContext context, int index) { + var e = listApp[index]; + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) { + return listApp[index].app; + }), + ); + }, + child: Card( + child: Column( + children: [ + Image.asset( + e.imageUrl, + width: 60, + height: 80, + ), + Text(e.getDisplay()) + ], + ), + ), + ); + }, + ); + } + + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: Scaffold( + appBar: AppBar( + title: Text("Flutter"), + ), + body: _buildGridViewBuilder(), + ), + ); + } +} + +class AppData { + final String name; + final String imageUrl; + final Widget app; + + AppData({ + Key key, + this.app, + this.imageUrl = 'images/bossapp2x.png', + this.name = "app", + }); + + AppData.from(): name="AppData", imageUrl="assets/awsome.png", app=null; + + String getDisplay() => app.toStringShort(); +} + + diff --git a/FlutterHelper/flutter_helper/lib/other/other_app.dart b/FlutterHelper/flutter_helper/lib/other/other_app.dart new file mode 100644 index 00000000..1afd88f6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/other/other_app.dart @@ -0,0 +1,11 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_helper/base_app.dart'; + +class OtherApp extends StatelessWidget { + + + @override + Widget build(BuildContext context) { + return Image.asset('images/beatiful_lady.jpeg'); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/MyTemplate.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/MyTemplate.dart new file mode 100644 index 00000000..dc13c27e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/MyTemplate.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; + +import 'lib/main.dart'; +import 'lib/templates/Common.dart'; + +class MyTemplate extends BeautifulPopupTemplate { + final BeautifulPopup options; + MyTemplate(this.options) : super(options); + + @override + final illustrationKey = 'images/mytemplate.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xff000000); + @override + final maxWidth = 400; + @override + final maxHeight = 600; + @override + final bodyMargin = 10; + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(10), + child: title, + ), + Positioned( + top: percentH(40), + height: percentH(actions == null ? 32 : 42), + left: percentW(10), + right: percentW(10), + child: content, + ), + Positioned( + bottom: percentW(10), + left: percentW(10), + right: percentW(10), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/main.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/main.dart new file mode 100644 index 00000000..52cb7c15 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/main.dart @@ -0,0 +1,201 @@ +library beautiful_popup; + +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'dart:ui' as ui; +import 'package:image/image.dart' as img; +import 'package:flutter/services.dart'; +import 'templates/Common.dart'; +import 'templates/OrangeRocket.dart'; +import 'templates/GreenRocket.dart'; +import 'templates/OrangeRocket2.dart'; +import 'templates/Coin.dart'; +import 'templates/BlueRocket.dart'; +import 'templates/Thumb.dart'; +import 'templates/Gift.dart'; +import 'templates/Camera.dart'; +import 'templates/Notification.dart'; +import 'templates/Geolocation.dart'; +import 'templates/Success.dart'; +import 'templates/Fail.dart'; +import 'templates/Authentication.dart'; +import 'templates/Term.dart'; +import 'templates/RedPacket.dart'; + +export 'templates/Common.dart'; +export 'templates/OrangeRocket.dart'; +export 'templates/GreenRocket.dart'; +export 'templates/OrangeRocket2.dart'; +export 'templates/Coin.dart'; +export 'templates/BlueRocket.dart'; +export 'templates/Thumb.dart'; +export 'templates/Gift.dart'; +export 'templates/Camera.dart'; +export 'templates/Notification.dart'; +export 'templates/Geolocation.dart'; +export 'templates/Success.dart'; +export 'templates/Fail.dart'; +export 'templates/Authentication.dart'; +export 'templates/Term.dart'; +export 'templates/RedPacket.dart'; + +class BeautifulPopup { + BuildContext _context; + BuildContext get context => _context; + + Type _template; + Type get template => _template; + + BeautifulPopupTemplate Function(BeautifulPopup options) _build; + BeautifulPopupTemplate get instance { + final build = _build; + if (build != null) return build(this); + switch (template) { + case TemplateOrangeRocket: + return TemplateOrangeRocket(this); + case TemplateGreenRocket: + return TemplateGreenRocket(this); + case TemplateOrangeRocket2: + return TemplateOrangeRocket2(this); + case TemplateCoin: + return TemplateCoin(this); + case TemplateBlueRocket: + return TemplateBlueRocket(this); + case TemplateThumb: + return TemplateThumb(this); + case TemplateGift: + return TemplateGift(this); + case TemplateCamera: + return TemplateCamera(this); + case TemplateNotification: + return TemplateNotification(this); + case TemplateGeolocation: + return TemplateGeolocation(this); + case TemplateSuccess: + return TemplateSuccess(this); + case TemplateFail: + return TemplateFail(this); + case TemplateAuthentication: + return TemplateAuthentication(this); + case TemplateTerm: + return TemplateTerm(this); + case TemplateRedPacket: + default: + return TemplateRedPacket(this); + } + } + + ui.Image _illustration; + ui.Image get illustration => _illustration; + + dynamic title = ''; + dynamic content = ''; + List actions; + Widget close; + bool barrierDismissible; + + Color primaryColor; + + BeautifulPopup({ + @required BuildContext context, + @required Type template, + }) : _context = context, + _template = template { + primaryColor = instance.primaryColor; // Get the default primary color. + } + + static BeautifulPopup customize({ + @required BuildContext context, + @required BeautifulPopupTemplate Function(BeautifulPopup options) build, + }) { + final popup = BeautifulPopup( + context: context, + template: null, + ); + popup._build = build; + return popup; + } + + /// Recolor the BeautifulPopup. + /// This method is kind of slow.R + Future recolor(Color color) async { + this.primaryColor = color; + final illustrationData = await rootBundle.load(instance.illustrationKey); + final buffer = illustrationData.buffer.asUint8List(); + img.Image asset; + asset = img.readPng(buffer); + if (asset != null) { + img.adjustColor( + asset, + saturation: 0, + // hue: 0, + ); + img.colorOffset( + asset, + red: color.red, + // I don't know why the effect is nicer with the number ╮(╯▽╰)╭ + green: color.green ~/ 3, + blue: color.blue ~/ 2, + alpha: 0, + ); + } + final paint = await PaintingBinding.instance.instantiateImageCodec( + asset != null ? Uint8List.fromList(img.encodePng(asset)) : buffer); + final nextFrame = await paint?.getNextFrame(); + _illustration = nextFrame?.image; + return this; + } + + /// `title`: Must be a `String` or `Widget`. Defaults to `''`. + /// + /// `content`: Must be a `String` or `Widget`. Defaults to `''`. + /// + /// `actions`: The set of actions that are displaed at bottom of the dialog, + /// + /// Typically this is a list of [BeautifulPopup.button]. Defaults to `[]`. + /// + /// `barrierDismissible`: Determine whether this dialog can be dismissed. Default to `False`. + /// + /// `close`: Close widget. + Future show({ + dynamic title, + dynamic content, + List actions, + bool barrierDismissible = false, + Widget close, + }) { + this.title = title; + this.content = content; + this.actions = actions; + this.barrierDismissible = barrierDismissible; + this.close = close ?? instance.close; + final child = WillPopScope( + onWillPop: () { + return Future.value(barrierDismissible); + }, + child: instance, + ); + return showGeneralDialog( + barrierColor: Colors.black38, + barrierDismissible: barrierDismissible, + barrierLabel: barrierDismissible ? 'beautiful_popup' : null, + context: context, + pageBuilder: (context, animation1, animation2) { + return child; + }, + transitionDuration: Duration(milliseconds: 150), + transitionBuilder: (ctx, a1, a2, child) { + return Transform.scale( + scale: a1.value, + child: Opacity( + opacity: a1.value, + child: child, + ), + ); + }, + ); + } + + BeautifulPopupButton get button => instance.button; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Authentication.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Authentication.dart new file mode 100644 index 00000000..d2e3192b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Authentication.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import '../main.dart'; +import 'Common.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/authentication.png) +class TemplateAuthentication extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateAuthentication(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/authentication.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xff15c0ec); + @override + final maxWidth = 400; + @override + final maxHeight = 617; + @override + final bodyMargin = 0; + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(32), + child: title, + ), + Positioned( + top: percentH(44), + left: percentW(10), + right: percentW(10), + height: percentH(actions == null ? 52 : 38), + child: content, + ), + Positioned( + bottom: percentW(8), + left: percentW(8), + right: percentW(8), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/BlueRocket.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/BlueRocket.dart new file mode 100644 index 00000000..290a9a9b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/BlueRocket.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; +import 'package:auto_size_text/auto_size_text.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/rocket_blue.png) +class TemplateBlueRocket extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateBlueRocket(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/rocket_blue.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xff4aa3f9); + @override + final maxWidth = 400; + @override + final maxHeight = 512; + @override + final bodyMargin = 0; + + @override + Widget get title { + if (options.title is Widget) { + return SizedBox( + width: percentW(54), + height: percentH(10), + child: options.title, + ); + } + return SizedBox( + width: percentW(54), + child: Opacity( + opacity: 0.9, + child: AutoSizeText( + options.title, + maxLines: 1, + style: TextStyle( + fontSize: Theme.of(options.context).textTheme.display1?.fontSize, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } + + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(13), + left: percentW(10), + child: title, + ), + Positioned( + top: percentH(40), + left: percentW(10), + right: percentW(10), + height: percentH(actions == null ? 50 : 38), + child: content, + ), + Positioned( + bottom: percentW(12), + left: percentW(10), + right: percentW(10), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Camera.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Camera.dart new file mode 100644 index 00000000..4e064350 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Camera.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/camera.png) +class TemplateCamera extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateCamera(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/camera.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xff72b2e0); + @override + final maxWidth = 400; + @override + final maxHeight = 500; + @override + final bodyMargin = 20; + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(42), + child: title, + ), + Positioned( + top: percentH(54), + height: percentH(actions == null ? 40 : 24), + left: percentW(8), + right: percentW(8), + child: content, + ), + Positioned( + bottom: percentW(8), + left: percentW(8), + right: percentW(8), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Coin.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Coin.dart new file mode 100644 index 00000000..e0f5278e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Coin.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/coin.png) +class TemplateCoin extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateCoin(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/coin.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xffff8269); + @override + final maxWidth = 400; + @override + final maxHeight = 586; + @override + final bodyMargin = 0; + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(46), + child: title, + ), + Positioned( + top: percentH(56), + left: percentW(12), + right: percentW(12), + height: percentH(actions == null ? 36 : 24), + child: content, + ), + Positioned( + bottom: percentW(12), + left: percentW(14), + right: percentW(14), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Common.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Common.dart new file mode 100644 index 00000000..2712d6b9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Common.dart @@ -0,0 +1,302 @@ +import 'package:flutter/material.dart'; +import '../main.dart'; +import 'dart:ui' as ui; +import 'package:auto_size_text/auto_size_text.dart'; + +typedef Widget BeautifulPopupButton({ + @required String label, + @required void Function() onPressed, + TextStyle labelStyle, + bool outline, + bool flat, +}); + +/// You can extend this class to custom your own template. +abstract class BeautifulPopupTemplate extends StatefulWidget { + final BeautifulPopup options; + BeautifulPopupTemplate(this.options); + + final State state = BeautifulPopupTemplateState(); + + @override + State createState() => state; + + Size get size { + double screenWidth = MediaQuery.of(options.context).size.width; + double screenHeight = MediaQuery.of(options.context).size.height; + double height = screenHeight > maxHeight ? maxHeight : screenHeight; + double width; + height = height - bodyMargin * 2; + if ((screenHeight - height) < 140) { + // For keep close button visible + height = screenHeight - 140; + width = height / maxHeight * maxWidth; + } else { + if (screenWidth > maxWidth) { + width = maxWidth - bodyMargin * 2; + } else { + width = screenWidth - bodyMargin * 2; + } + height = width / maxWidth * maxHeight; + } + return Size(width, height); + } + + double get width => size.width; + double get height => size.height; + + double get maxWidth; + double get maxHeight; + double get bodyMargin; + + /// The path of the illustration asset. + String get illustrationPath => ''; + String get illustrationKey => + '$illustrationPath'; + Color get primaryColor; + + double percentW(double n) { + return width * n / 100; + } + + double percentH(double n) { + return height * n / 100; + } + + Widget get close { + return MaterialButton( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(100)), + splashColor: Colors.transparent, + hoverColor: Colors.transparent, + minWidth: 45, + height: 45, + child: Container( + padding: EdgeInsets.all(20), + child: Icon(Icons.close, color: Colors.white70, size: 26), + ), + padding: EdgeInsets.all(0), + onPressed: Navigator.of(options.context).pop, + ); + } + + Widget get background { + final illustration = options.illustration; + return illustration == null + ? Image.asset( + illustrationKey, + width: percentW(100), + height: percentH(100), + fit: BoxFit.fill, + ) + : CustomPaint( + size: Size(percentW(100), percentH(100)), + painter: ImageEditor( + image: illustration, + ), + ); + } + + Widget get title { + if (options.title is Widget) { + return Container( + width: percentW(100), + height: percentH(10), + alignment: Alignment.center, + child: options.title, + ); + } + return Container( + alignment: Alignment.center, + width: percentW(100), + height: percentH(10), + child: Opacity( + opacity: 0.95, + child: AutoSizeText( + options.title, + maxLines: 1, + style: TextStyle( + fontSize: Theme.of(options.context).textTheme.display1?.fontSize, + color: primaryColor, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } + + Widget get content { + return options.content is String + ? AutoSizeText( + options.content, + minFontSize: + Theme.of(options.context).textTheme.subhead?.fontSize ?? 12, + style: TextStyle( + color: Colors.black87, + ), + ) + : options.content; + } + + Widget get actions { + final actionsList = options.actions; + if (actionsList == null || actionsList.length == 0) return null; + return Flex( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + direction: Axis.horizontal, + children: actionsList + .map( + (button) => Flexible( + flex: 1, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5), + child: button, + ), + ), + ) + .toList(), + ); + } + + BeautifulPopupButton get button { + return ({ + @required String label, + @required void Function() onPressed, + bool outline = false, + bool flat = false, + TextStyle labelStyle = const TextStyle(), + }) { + final gradient = LinearGradient(colors: [ + primaryColor.withOpacity(0.5), + primaryColor, + ]); + final double elevation = (outline || flat) ? 0 : 2; + final labelColor = + (outline || flat) ? primaryColor : Colors.white.withOpacity(0.95); + final decoration = BoxDecoration( + gradient: (outline || flat) ? null : gradient, + borderRadius: BorderRadius.all(Radius.circular(80.0)), + border: Border.all( + color: outline ? primaryColor : Colors.transparent, + width: (outline && !flat) ? 1 : 0, + ), + ); + final minHeight = 40.0 - (outline ? 2 : 0); + return RaisedButton( + color: Colors.transparent, + elevation: elevation, + highlightElevation: 0, + splashColor: Colors.transparent, + child: Ink( + decoration: decoration, + child: Container( + constraints: BoxConstraints( + minWidth: 100, + minHeight: minHeight, + ), + alignment: Alignment.center, + child: Text( + label, + style: TextStyle( + color: labelColor, + ).merge(labelStyle), + ), + ), + ), + padding: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + onPressed: onPressed, + ); + }; + } + + List get layout; +} + +class BeautifulPopupTemplateState extends State { + OverlayEntry closeEntry; + @override + void initState() { + super.initState(); + + // Display close button + Future.delayed(Duration.zero, () { + closeEntry = OverlayEntry( + builder: (ctx) { + final bottom = (MediaQuery.of(context).size.height - + widget.height - + widget.bodyMargin * 2) / + 4 - + 20; + return Stack( + overflow: Overflow.visible, + children: [ + Positioned( + child: Container( + alignment: Alignment.center, + child: widget.options.close ?? Container(), + ), + left: 0, + right: 0, + bottom: bottom, + ) + ], + ); + }, + ); + final entry = closeEntry; + if (entry != null) Overlay.of(context)?.insert(entry); + }); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Material( + color: Colors.transparent, + child: Container( + margin: EdgeInsets.all(widget.bodyMargin), + height: widget.height, + width: widget.width, + child: Stack( + overflow: Overflow.visible, + children: widget.layout, + ), + ), + ) + ], + ); + } + + @override + void dispose() { + closeEntry?.remove(); + super.dispose(); + } +} + +class ImageEditor extends CustomPainter { + ui.Image image; + ImageEditor({ + @required this.image, + }); + + @override + void paint(Canvas canvas, Size size) { + canvas.drawImageRect( + image, + Rect.fromLTRB(0, 0, image.width.toDouble(), image.height.toDouble()), + Rect.fromLTRB(0, 0, size.width, size.height), + new Paint(), + ); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => false; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Fail.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Fail.dart new file mode 100644 index 00000000..57d16ea4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Fail.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/fail.png) +class TemplateFail extends TemplateSuccess { + final BeautifulPopup options; + TemplateFail(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/fail.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xffF77273); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Geolocation.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Geolocation.dart new file mode 100644 index 00000000..5bd91dd2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Geolocation.dart @@ -0,0 +1,10 @@ +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/geolocation.png) +class TemplateGeolocation extends TemplateCamera { + final BeautifulPopup options; + TemplateGeolocation(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/geolocation.png'; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Gift.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Gift.dart new file mode 100644 index 00000000..d16c4bcd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Gift.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/gift.png) +class TemplateGift extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateGift(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/gift.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xffFF2F49); + @override + final maxWidth = 400; + @override + final maxHeight = 580; + @override + final bodyMargin = 30; + @override + BeautifulPopupButton get button { + return ({ + @required String label, + @required void Function() onPressed, + bool outline = false, + bool flat = false, + TextStyle labelStyle = const TextStyle(), + }) { + final gradient = LinearGradient(colors: [ + primaryColor.withOpacity(0.5), + primaryColor, + ]); + final double elevation = (outline || flat) ? 0 : 2; + final labelColor = + (outline || flat) ? primaryColor : Colors.white.withOpacity(0.95); + final decoration = BoxDecoration( + gradient: (outline || flat) ? null : gradient, + borderRadius: BorderRadius.all(Radius.circular(80.0)), + border: Border.all( + color: outline ? primaryColor : Colors.transparent, + width: (outline && !flat) ? 1 : 0, + ), + ); + final minHeight = 40.0 - (outline ? 4 : 0); + return RaisedButton( + color: Colors.transparent, + elevation: elevation, + highlightElevation: 0, + splashColor: Colors.transparent, + child: Ink( + decoration: decoration, + child: Container( + constraints: BoxConstraints( + minWidth: 100, + minHeight: minHeight, + ), + alignment: Alignment.center, + child: Text( + label, + style: TextStyle( + color: Colors.white.withOpacity(0.95), + fontWeight: FontWeight.bold, + ).merge(labelStyle), + ), + ), + ), + padding: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + onPressed: onPressed, + ); + }; + } + + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(26), + child: title, + ), + Positioned( + top: percentH(36), + left: percentW(5), + right: percentW(5), + height: percentH(actions == null ? 60 : 50), + child: content, + ), + Positioned( + bottom: percentW(5), + left: percentW(5), + right: percentW(5), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/GreenRocket.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/GreenRocket.dart new file mode 100644 index 00000000..0c33f986 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/GreenRocket.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/rocket_green.png) +class TemplateGreenRocket extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateGreenRocket(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/rocket_green.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xff49ceae); + @override + final maxWidth = 400; + @override + final maxHeight = 496; + @override + final bodyMargin = 0; + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(35), + child: title, + ), + Positioned( + top: percentH(45), + left: percentW(14), + right: percentW(14), + height: percentH(actions == null ? 44 : 32), + child: content, + ), + Positioned( + bottom: percentW(12), + left: percentW(12), + right: percentW(12), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Notification.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Notification.dart new file mode 100644 index 00000000..3b8eb31e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Notification.dart @@ -0,0 +1,10 @@ +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/notification.png) +class TemplateNotification extends TemplateCamera { + final BeautifulPopup options; + TemplateNotification(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/notification.png'; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/OrangeRocket.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/OrangeRocket.dart new file mode 100644 index 00000000..5832aca5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/OrangeRocket.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; +import 'package:auto_size_text/auto_size_text.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/rocket_orange.png) +class TemplateOrangeRocket extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateOrangeRocket(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/rocket_orange.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xffdf3428); + @override + final maxWidth = 400; + @override + final maxHeight = 600; + @override + final bodyMargin = 30; + Widget get title { + if (options.title is Widget) { + return SizedBox( + width: percentW(40), + height: percentH(10), + child: options.title, + ); + } + return SizedBox( + width: percentW(40), + child: Opacity( + opacity: 0.8, + child: AutoSizeText( + options.title, + maxLines: 1, + style: TextStyle( + fontSize: Theme.of(options.context).textTheme.display1?.fontSize, + color: primaryColor, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } + + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(20), + left: percentW(10), + child: title, + ), + Positioned( + top: percentH(50), + left: percentW(6), + right: percentW(6), + height: percentH(actions == null ? 46 : 34), + child: content, + ), + Positioned( + bottom: percentW(5), + left: percentW(5), + right: percentW(5), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/OrangeRocket2.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/OrangeRocket2.dart new file mode 100644 index 00000000..da73958e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/OrangeRocket2.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/rocekt_orange_2.png) +class TemplateOrangeRocket2 extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateOrangeRocket2(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/rocket_orange_2.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xffff902b); + @override + final maxWidth = 350; + @override + final maxHeight = 488; + @override + final bodyMargin = 0; + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(42), + width: percentW(54), + child: title, + ), + Positioned( + top: percentH(52), + left: percentW(10), + right: percentW(10), + height: percentH(actions == null ? 40 : 26), + child: content, + ), + Positioned( + bottom: percentW(12), + left: percentW(10), + right: percentW(10), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/RedPacket.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/RedPacket.dart new file mode 100644 index 00000000..500d5a6d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/RedPacket.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import '../main.dart'; +import 'package:auto_size_text/auto_size_text.dart'; +import 'Common.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/red_packet.png) +class TemplateRedPacket extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateRedPacket(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/red_packet.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xfffa1a2c); + @override + final maxWidth = 400; + @override + final maxHeight = 620; + @override + final bodyMargin = 0; + @override + Widget get title { + if (options.title is Widget) { + return SizedBox( + width: percentW(100), + height: percentH(10), + child: Center( + child: options.title, + ), + ); + } + return SizedBox( + width: percentW(100), + child: Center( + child: Opacity( + opacity: 0.95, + child: AutoSizeText( + options.title, + maxLines: 1, + style: TextStyle( + fontSize: Theme.of(options.context).textTheme.display1?.fontSize, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + } + + Widget get content { + return options.content is String + ? AutoSizeText( + options.content, + minFontSize: + Theme.of(options.context).textTheme.subhead?.fontSize ?? 12, + style: TextStyle( + color: Colors.white.withOpacity(0.95), + ), + ) + : options.content; + } + + @override + BeautifulPopupButton get button { + return ({ + @required String label, + @required void Function() onPressed, + bool outline = false, + bool flat = false, + TextStyle labelStyle = const TextStyle(), + }) { + final gradient = LinearGradient(colors: [ + primaryColor.withOpacity(0.5), + primaryColor, + ]); + final double elevation = (outline || flat) ? 0 : 2; + final labelColor = + (outline || flat) ? primaryColor : Colors.white.withOpacity(0.95); + final decoration = BoxDecoration( + gradient: (outline || flat) ? null : gradient, + borderRadius: BorderRadius.all(Radius.circular(80.0)), + border: Border.all( + color: outline ? primaryColor : Colors.transparent, + width: (outline && !flat) ? 1 : 0, + ), + ); + final minHeight = 40.0 - (outline ? 2 : 0); + return RaisedButton( + color: Colors.transparent, + elevation: elevation, + highlightElevation: 0, + splashColor: Colors.transparent, + child: Ink( + decoration: decoration, + child: Container( + constraints: BoxConstraints( + minWidth: 100, + minHeight: minHeight, + ), + alignment: Alignment.center, + child: Text( + label, + style: TextStyle( + color: Colors.white.withOpacity(0.95), + fontWeight: FontWeight.bold, + ).merge(labelStyle), + ), + ), + ), + padding: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + onPressed: onPressed, + ); + }; + } + + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(10), + child: title, + ), + Positioned( + top: percentH(40), + left: percentW(12), + right: percentW(12), + height: percentH(actions == null ? 56 : 42), + child: content, + ), + Positioned( + bottom: percentW(10), + left: percentW(10), + right: percentW(10), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Success.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Success.dart new file mode 100644 index 00000000..21d18481 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Success.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/success.png) +class TemplateSuccess extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateSuccess(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/success.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xff4ABDFE); + @override + final maxWidth = 400; + @override + final maxHeight = 588; + @override + final bodyMargin = 30; + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(46), + child: title, + ), + Positioned( + top: percentH(58), + left: percentW(8), + right: percentW(8), + height: percentH(actions == null ? 40 : 24), + child: content, + ), + Positioned( + bottom: percentW(8), + left: percentW(8), + right: percentW(8), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Term.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Term.dart new file mode 100644 index 00000000..8c36e4e3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Term.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import '../main.dart'; +import 'Common.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/term.png) +class TemplateTerm extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateTerm(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/term.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xfffb8c3c); + @override + final maxWidth = 400; + @override + final maxHeight = 617; + @override + final bodyMargin = 0; + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(32), + child: title, + ), + Positioned( + top: percentH(42), + left: percentW(12), + right: percentW(12), + height: percentH(actions == null ? 52 : 42), + child: content, + ), + Positioned( + bottom: percentW(9), + left: percentW(12), + right: percentW(12), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Thumb.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Thumb.dart new file mode 100644 index 00000000..88916870 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/lib/templates/Thumb.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'Common.dart'; +import '../main.dart'; +import 'package:auto_size_text/auto_size_text.dart'; + +/// ![](https://raw.githubusercontent.com/jaweii/Flutter_beautiful_popup/master/img/bg/thumb.png) +class TemplateThumb extends BeautifulPopupTemplate { + final BeautifulPopup options; + TemplateThumb(this.options) : super(options); + + @override + final illustrationPath = 'img/bg/thumb.png'; + @override + Color get primaryColor => options.primaryColor ?? Color(0xfffb675d); + @override + final maxWidth = 400; + @override + final maxHeight = 570; + @override + final bodyMargin = 0; + + @override + Widget get title { + if (options.title is Widget) { + return SizedBox( + width: percentW(54), + height: percentH(10), + child: options.title, + ); + } + return SizedBox( + width: percentW(54), + child: Opacity( + opacity: 0.9, + child: AutoSizeText( + options.title, + maxLines: 1, + style: TextStyle( + fontSize: Theme.of(options.context).textTheme.display1?.fontSize, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } + + @override + BeautifulPopupButton get button { + return ({ + @required String label, + @required void Function() onPressed, + bool outline = false, + bool flat = false, + TextStyle labelStyle = const TextStyle(), + }) { + final gradient = LinearGradient(colors: [ + primaryColor.withOpacity(0.5), + primaryColor, + ]); + final double elevation = (outline || flat) ? 0 : 2; + final labelColor = + (outline || flat) ? primaryColor : Colors.white.withOpacity(0.95); + final decoration = BoxDecoration( + gradient: (outline || flat) ? null : gradient, + borderRadius: BorderRadius.all(Radius.circular(80.0)), + border: Border.all( + color: outline ? primaryColor : Colors.transparent, + width: (outline && !flat) ? 1 : 0, + ), + ); + final minHeight = 40.0 - (outline ? 2 : 0); + return RaisedButton( + color: Colors.transparent, + elevation: elevation, + highlightElevation: 0, + splashColor: Colors.transparent, + child: Ink( + decoration: decoration, + child: Container( + constraints: BoxConstraints( + minWidth: 100, + minHeight: minHeight, + ), + alignment: Alignment.center, + child: Text( + label, + style: TextStyle( + color: Colors.white.withOpacity(0.95), + ).merge(labelStyle), + ), + ), + ), + padding: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + ), + onPressed: onPressed, + ); + }; + } + + @override + get layout { + return [ + Positioned( + child: background, + ), + Positioned( + top: percentH(10), + left: percentW(10), + child: title, + ), + Positioned( + top: percentH(28), + left: percentW(10), + right: percentW(10), + height: percentH(actions == null ? 62 : 50), + child: content, + ), + Positioned( + bottom: percentW(14), + left: percentW(10), + right: percentW(10), + child: actions ?? Container(), + ), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/main.dart b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/main.dart new file mode 100644 index 00000000..337e0220 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/beautiful_popup/main.dart @@ -0,0 +1,515 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; +import 'package:flutter_highlight/flutter_highlight.dart'; +import 'package:flutter_highlight/themes/github-gist.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import 'MyTemplate.dart'; +import 'lib/main.dart'; +import 'lib/templates/Authentication.dart'; +import 'lib/templates/BlueRocket.dart'; +import 'lib/templates/Camera.dart'; +import 'lib/templates/Coin.dart'; +import 'lib/templates/Fail.dart'; +import 'lib/templates/Geolocation.dart'; +import 'lib/templates/Gift.dart'; +import 'lib/templates/GreenRocket.dart'; +import 'lib/templates/OrangeRocket2.dart'; +import 'lib/templates/RedPacket.dart'; +import 'lib/templates/Success.dart'; +import 'lib/templates/Term.dart'; +import 'lib/templates/Thumb.dart'; + +void main() { + runApp(BeautifulPopupApp()); +} + +class BeautifulPopupApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter_beautiful_popup', + theme: ThemeData(primaryColor: Colors.blue), + home: MyHomePage(title: 'Flutter_Beautiful_Popup'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, @required this.title}) : super(key: key); + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + @override + initState() { + super.initState(); + final templates = [ + TemplateGift, + TemplateCamera, + TemplateNotification, + TemplateGeolocation, + TemplateSuccess, + TemplateFail, + // TemplateOrangeRocket, + TemplateGreenRocket, + TemplateOrangeRocket2, + TemplateCoin, + TemplateBlueRocket, + TemplateThumb, + TemplateAuthentication, + TemplateTerm, + TemplateRedPacket, + ]; + + demos = templates.map((template) { + return BeautifulPopup( + context: context, + template: template, + ); + }).toList(); + } + + List demos = []; + + BeautifulPopup activeDemo; + + Widget get showcases { + final popup = BeautifulPopup.customize( + context: context, + build: (options) => MyTemplate(options), + ); + return Flex( + mainAxisSize: MainAxisSize.max, + direction: Axis.vertical, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.fromLTRB(20, 20, 10, 10), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: Colors.white, + width: 1, + ), + ), + ), + child: Flex( + direction: Axis.horizontal, + children: [ + Text( + 'All Templates:', + style: Theme.of(context).textTheme.title?.merge( + TextStyle( + backgroundColor: Colors.transparent, + ), + ), + ), + Spacer(), + FlatButton( + child: Text('Customize'), + onPressed: () { + popup.show( + title: 'Example', + content: Container( + color: Colors.black12, + child: Text( + 'This popup shows you how to customize your own BeautifulPopupTemplate.'), + ), + actions: [ + popup.button( + label: 'Code', + labelStyle: TextStyle(), + onPressed: () async { + await _launchURL( + 'https://github.com/jaweii/Flutter_beautiful_popup/blob/master/example/lib/MyTemplate.dart', + ); + }, + ), + ], + ); + }, + ) + ], + ), + ), + Expanded( + child: SingleChildScrollView( + padding: EdgeInsets.fromLTRB(20, 20, 0, 20), + child: Wrap( + alignment: WrapAlignment.start, + spacing: 20, + runSpacing: 30, + children: demos.map((demo) { + final i = demos.indexWhere((d) => d.template == demo.template); + return InkWell( + borderRadius: BorderRadius.circular(10), + child: Container( + constraints: BoxConstraints(minWidth: 160), + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: demo.primaryColor?.withOpacity(0.25), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Image.asset( + demo.instance.illustrationKey, + height: 54, + width: 100, + fit: BoxFit.fitWidth, + alignment: Alignment.topCenter, + ), + SizedBox(height: 10), + Text( + 'Demo-${i + 1}\n${demo.instance.runtimeType}', + textAlign: TextAlign.center, + ) + ], + ), + ), + onTap: () { + openDemo(demo: demo); + }, + ); + }).toList(), + ), + ), + ), + ], + ); + } + + Widget get body { + final exampleCode = ''' +final popup = BeautifulPopup( + context: context, + template: ${activeDemo?.instance.runtimeType ?? '// Select a template in right'}, +); + +popup.show( + title: 'String', + content: 'BeautifulPopup is a flutter package that is responsible for beautify your app popups.', + actions: [ + popup.button( + label: 'Close', + onPressed: Navigator.of(context).pop, + ), + ], +); + '''; + if (MediaQuery.of(context).size.width > 1024) { + return Flex( + direction: Axis.horizontal, + children: [ + Flexible( + flex: 1, + fit: FlexFit.tight, + child: Container( + color: activeDemo?.primaryColor?.withOpacity(0.25) ?? + Theme.of(context).primaryColor.withOpacity(0.25), + child: Flex( + mainAxisSize: MainAxisSize.max, + direction: Axis.vertical, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.fromLTRB(20, 20, 10, 10), + child: Text( + '# Usage', + style: Theme.of(context).textTheme.title?.merge( + TextStyle( + color: Colors.black54, + backgroundColor: Colors.transparent, + ), + ), + ), + ), + Expanded( + child: Container( + alignment: Alignment.center, + child: HighlightView( + exampleCode, + language: 'dart', + theme: githubGistTheme, + padding: EdgeInsets.all(30), + ), + ), + ), + ], + ), + ), + ), + Flexible( + flex: 1, + fit: FlexFit.tight, + child: showcases, + ), + ], + ); + } else { + return showcases; + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text( + widget.title, + style: TextStyle(color: Colors.white), + ), + elevation: 2, + backgroundColor: + activeDemo?.primaryColor ?? Theme.of(context).primaryColor, + actions: [ + FlatButton( + child: Image.asset( + 'images/github.png', + width: 32, + height: 32, + ), + onPressed: () async { + await _launchURL( + 'https://github.com/jaweii/Flutter_beautiful_popup', + ); + }, + ), + ], + ), + body: body, + ); + } + + void changeColor( + BeautifulPopup demo, + void Function(Color color) callback, + ) { + Color color = demo.primaryColor?.withOpacity(0.5); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Pick a color'), + content: SingleChildScrollView( + child: ColorPicker( + pickerColor: color == null ? Color(0xFF000000) : color, + onColorChanged: (c) => color = c, + showLabel: true, + pickerAreaHeightPercent: 0.8, + ), + ), + actions: [ + FlatButton( + child: const Text('Got it'), + onPressed: () async { + callback?.call(color); + }, + ), + ], + ), + ); + } + + openDemo({ + @required BeautifulPopup demo, + dynamic title = 'String', + dynamic content = + 'BeautifulPopup is a flutter package that is responsible for beautify your app popups.', + }) { + assert(title is Widget || title is String); + setState(() { + activeDemo = demo; + }); + demo.show( + title: title, + content: content, + actions: [ + demo.button( + label: 'Recolor', + onPressed: () { + changeColor(demo, (color) async { + demo = await BeautifulPopup( + context: context, + template: demo.template, + ).recolor(color); + Navigator.of(context).popUntil((route) { + if (route.settings.name == '/') return true; + return false; + }); + openDemo(demo: demo); + }); + }, + ), + demo.button( + label: 'Show more', + outline: true, + onPressed: () { + Navigator.of(context).pop(); + if (title is Widget) { + return openDemo(demo: demo); + } + getTitle() { + return Opacity( + opacity: 0.95, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + '[Widget]', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20, + color: demo.primaryColor, + backgroundColor: Colors.white70, + ), + ), + Padding( + padding: EdgeInsets.only(top: 20), + child: Icon( + Icons.star, + color: demo.primaryColor?.withOpacity(0.75), + size: 10, + ), + ) + ], + ), + ); + } + + getContent() { + return Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.1), + ), + child: Scrollbar( + child: SingleChildScrollView( + child: Column( + children: [ + CupertinoButton( + child: Text('Remove all buttons'), + onPressed: () { + Navigator.of(context).pop(); + demo = BeautifulPopup( + context: context, + template: demo.template, + ); + demo.show( + title: getTitle(), + content: getContent(), + actions: [], + ); + }, + ), + CupertinoButton( + child: Text('Keep one button'), + onPressed: () { + Navigator.of(context).pop(); + demo = BeautifulPopup( + context: context, + template: demo.template, + ); + demo.show( + title: getTitle(), + content: getContent(), + actions: [ + demo.button( + label: 'One button', + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ), + CupertinoButton( + child: Text('Remove Close button'), + onPressed: () { + Navigator.of(context).pop(); + demo = BeautifulPopup( + context: context, + template: demo.template, + ); + demo.show( + title: getTitle(), + content: getContent(), + close: Container(), + barrierDismissible: true, + actions: [ + demo.button( + label: 'Close', + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ), + CupertinoButton( + child: Text('Change button direction'), + onPressed: () { + Navigator.of(context).pop(); + demo = BeautifulPopup( + context: context, + template: demo.template, + ); + demo.show( + title: getTitle(), + content: Flex( + crossAxisAlignment: CrossAxisAlignment.start, + direction: Axis.vertical, + children: [ + Text('1. blabla... \n2. blabla...'), + Spacer(), + demo.button( + label: 'Accpet', + onPressed: () {}, + ), + Container( + alignment: Alignment.center, + child: FlatButton( + hoverColor: Colors.transparent, + highlightColor: Colors.transparent, + child: Text('Close'), + onPressed: Navigator.of(context).pop, + ), + ), + ], + ), + barrierDismissible: true, + actions: [], + ); + }, + ) + ], + ), + ), + ), + ); + } + + openDemo( + demo: demo, + title: getTitle(), + content: getContent(), + ); + }, + ) + ], + ); + } + + Future _launchURL(String _url) async { + await canLaunch(_url) ? await launch(_url) : throw 'Could not launch $_url'; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/before_after/lib/before_after.dart b/FlutterHelper/flutter_helper/lib/samples/before_after/lib/before_after.dart new file mode 100644 index 00000000..6981b89a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/before_after/lib/before_after.dart @@ -0,0 +1,3 @@ +library before_after; + +export 'src/custom_widget.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/before_after/lib/src/custom_widget.dart b/FlutterHelper/flutter_helper/lib/samples/before_after/lib/src/custom_widget.dart new file mode 100644 index 00000000..bbff3130 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/before_after/lib/src/custom_widget.dart @@ -0,0 +1,175 @@ +import 'package:flutter/material.dart'; + +import 'rect_clipper.dart'; + +class BeforeAfter extends StatefulWidget { + final Widget beforeImage; + final Widget afterImage; + final double imageHeight; + final double imageWidth; + final double imageCornerRadius; + final Color thumbColor; + final double thumbRadius; + final Color overlayColor; + final bool isVertical; + + const BeforeAfter({ + Key key, + @required this.beforeImage, + @required this.afterImage, + this.imageHeight, + this.imageWidth, + this.imageCornerRadius = 8.0, + this.thumbColor = Colors.white, + this.thumbRadius = 16.0, + this.overlayColor, + this.isVertical = false, + }) : assert(beforeImage != null), + assert(afterImage != null), + super(key: key); + + @override + _BeforeAfterState createState() => _BeforeAfterState(); +} + +class _BeforeAfterState extends State { + double _clipFactor = 0.5; + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + Padding( + padding: widget.isVertical + ? const EdgeInsets.symmetric(vertical: 24.0) + : const EdgeInsets.symmetric(horizontal: 24.0), + child: SizedImage( + widget.afterImage, + widget.imageHeight, + widget.imageWidth, + widget.imageCornerRadius, + ), + ), + Padding( + padding: widget.isVertical + ? const EdgeInsets.symmetric(vertical: 24.0) + : const EdgeInsets.symmetric(horizontal: 24.0), + child: ClipPath( + clipper: widget.isVertical + ? RectClipperVertical(_clipFactor) + : RectClipper(_clipFactor), + child: SizedImage( + widget.beforeImage, + widget.imageHeight, + widget.imageWidth, + widget.imageCornerRadius, + ), + ), + ), + Positioned.fill( + child: SliderTheme( + data: SliderThemeData( + trackHeight: 0.0, + overlayColor: widget.overlayColor, + thumbShape: + CustomThumbShape(widget.thumbRadius, widget.thumbColor), + ), + child: widget.isVertical + ? RotatedBox( + quarterTurns: 1, + child: Slider( + value: _clipFactor, + onChanged: (double factor) => + setState(() => this._clipFactor = factor), + ), + ) + : Slider( + value: _clipFactor, + onChanged: (double factor) => + setState(() => this._clipFactor = factor), + ), + ), + ), + ], + ); + } +} + +class SizedImage extends StatelessWidget { + final Widget _image; + final double _height, _width, _imageCornerRadius; + + const SizedImage( + this._image, this._height, this._width, this._imageCornerRadius, + {Key key}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return ClipRRect( + borderRadius: BorderRadius.circular(_imageCornerRadius), + child: SizedBox( + height: _height, + width: _width, + child: _image, + ), + ); + } +} + +class CustomThumbShape extends SliderComponentShape { + final double _thumbRadius; + final Color _thumbColor; + + CustomThumbShape(this._thumbRadius, this._thumbColor); + + @override + Size getPreferredSize(bool isEnabled, bool isDiscrete) { + return Size.fromRadius(_thumbRadius); + } + + @override + void paint(PaintingContext context, Offset center, + {Animation activationAnimation, + Animation enableAnimation, + bool isDiscrete, + TextPainter labelPainter, + RenderBox parentBox, + SliderThemeData sliderTheme, + TextDirection textDirection, + double value, + double textScaleFactor, + Size sizeWithOverflow}) { + final Canvas canvas = context.canvas; + + final Paint paint = Paint() + ..isAntiAlias = true + ..strokeWidth = 4.0 + ..color = _thumbColor + ..style = PaintingStyle.fill; + + final Paint paintStroke = Paint() + ..isAntiAlias = true + ..strokeWidth = 4.0 + ..color = _thumbColor + ..style = PaintingStyle.stroke; + + canvas.drawCircle( + center, + _thumbRadius, + paintStroke, + ); + + canvas.drawCircle( + center, + _thumbRadius - 6, + paint, + ); + + canvas.drawRect( + Rect.fromCenter( + center: center, width: 4.0, height: parentBox.size.height), + paint); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/before_after/lib/src/rect_clipper.dart b/FlutterHelper/flutter_helper/lib/samples/before_after/lib/src/rect_clipper.dart new file mode 100644 index 00000000..0aa0559a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/before_after/lib/src/rect_clipper.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +class RectClipper extends CustomClipper { + final double clipFactor; + + RectClipper(this.clipFactor); + + @override + Path getClip(Size size) { + Path path = Path(); + path.lineTo(size.width * clipFactor, 0.0); + path.lineTo(size.width * clipFactor, size.height); + path.lineTo(0.0, size.height); + path.close(); + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) => true; +} + +class RectClipperVertical extends CustomClipper { + final double clipFactor; + + RectClipperVertical(this.clipFactor); + + @override + Path getClip(Size size) { + Path path = Path(); + path.lineTo(0.0, size.height * clipFactor); + path.lineTo(size.width, size.height * clipFactor); + path.lineTo(size.width, 0.0); + path.close(); + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) => true; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/before_after/main.dart b/FlutterHelper/flutter_helper/lib/samples/before_after/main.dart new file mode 100644 index 00000000..e517c1da --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/before_after/main.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +import 'lib/before_after.dart'; + +void main() => runApp(BeforeAfterApp()); + +class BeforeAfterApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.teal, + ), + home: MyHomePage(), + ); + } +} + +class MyHomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('Before After'), centerTitle: true), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + flex: 1, + child: BeforeAfter( + beforeImage: Image.asset('assets/after.jpg'), + afterImage: Image.asset('assets/before.jpg'), + ), + ), + Expanded( + flex: 1, + child: BeforeAfter( + beforeImage: Image.asset('assets/after.jpg'), + afterImage: Image.asset('assets/before.jpg'), + isVertical: true, + ), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/example.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/example.dart new file mode 100644 index 00000000..78b9ac7d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/example.dart @@ -0,0 +1,851 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:intl/intl.dart'; +import 'package:file_picker/file_picker.dart'; + +import 'lib/card_settings.dart'; +import 'lib/widgets/action_fields/card_settings_button.dart'; +import 'lib/widgets/card_field_layout.dart'; +import 'lib/widgets/card_settings_panel.dart'; +import 'lib/widgets/card_settings_widget.dart'; +import 'lib/widgets/information_fields/card_settings_header.dart'; +import 'lib/widgets/text_fields/card_settings_password.dart'; +import 'plumbing/results.dart'; +import 'plumbing/model.dart'; + +typedef LabelledValueChanged = void Function(T label, U value); + +class ExampleForm extends StatefulWidget { + const ExampleForm( + this.orientation, + this.showMaterialonIOS, + this.scaffoldKey, { + this.onValueChanged, + Key key, + }) : super(key: key); + + final Orientation orientation; + final bool showMaterialonIOS; + final GlobalKey scaffoldKey; + + final LabelledValueChanged onValueChanged; + + @override + ExampleFormState createState() => ExampleFormState(); +} + +class ExampleFormState extends State { + PonyModel _ponyModel; + + bool loaded = false; + + @override + void initState() { + super.initState(); + + initModel(); + } + + void initModel() async { + _ponyModel = PonyModel(); + + await _ponyModel.loadMedia(); + + setState(() => loaded = true); + } + + final GlobalKey _formKey = GlobalKey(); + + AutovalidateMode _autoValidateMode = AutovalidateMode.onUserInteraction; + + // keys for fields + // this is desirable because the fields may change order, in this example + // when the screen is rotated, and this will preserve what state is + // attached to what field. + final GlobalKey _nameKey = GlobalKey(); + final GlobalKey _typeKey = GlobalKey(); + final GlobalKey _ageKey = GlobalKey(); + final GlobalKey _genderKey = GlobalKey(); + final GlobalKey _descriptionlKey = GlobalKey(); + final GlobalKey _hobbiesKey = GlobalKey(); + final GlobalKey _coatKey = GlobalKey(); + final GlobalKey _maneKey = GlobalKey(); + final GlobalKey _hasSpotsKey = GlobalKey(); + final GlobalKey _spotKey = GlobalKey(); + final GlobalKey _heightKey = GlobalKey(); + final GlobalKey _weightKey = GlobalKey(); + final GlobalKey _dateKey = GlobalKey(); + final GlobalKey _photoKey = GlobalKey(); + final GlobalKey _videoKey = GlobalKey(); + final GlobalKey _audioKey = GlobalKey(); + final GlobalKey _customFileKey = GlobalKey(); + final GlobalKey _datetimeKey = GlobalKey(); + final GlobalKey _styleKey = GlobalKey(); + final GlobalKey _timeKey = GlobalKey(); + final GlobalKey _priceKey = GlobalKey(); + final GlobalKey _phoneKey = GlobalKey(); + final GlobalKey _emailKey = GlobalKey(); + final GlobalKey _passwordKey = GlobalKey(); + final GlobalKey _sliderKey = GlobalKey(); + + final FocusNode _nameNode = FocusNode(); + final FocusNode _descriptionNode = FocusNode(); + + @override + Widget build(BuildContext context) { + if (loaded) { + return Form( + key: _formKey, + child: (widget.orientation == Orientation.portrait) + ? _buildPortraitLayout() + : _buildLandscapeLayout(), + ); + } else { + return Center(child: CircularProgressIndicator()); + } + } + + Future savePressed() async { + final form = _formKey.currentState; + + if (form.validate()) { + form.save(); + showResults(context, _ponyModel); + } else { + showErrors(context); + setState(() => _autoValidateMode = AutovalidateMode.onUserInteraction); + } + } + + void resetPressed() { + setState(() => loaded = false); + + initModel(); + + _formKey.currentState.reset(); + } + + CardSettings _buildPortraitLayout() { + return CardSettings.sectioned( + showMaterialonIOS: widget.showMaterialonIOS, + labelWidth: 150, + contentAlign: TextAlign.right, + cardless: false, + children: [ + CardSettingsSection( + header: CardSettingsHeader( + label: 'Bio', + ), + children: [ + _buildCardSettingsText_Name(), + _buildCardSettingsListPicker_Type(), + _buildCardSettingsRadioPicker_Gender(), + _buildCardSettingsNumberPicker_Age(), + _buildCardSettingsParagraph_Description(5), + _buildCardSettingsCheckboxPicker_Hobbies(), + _buildCardSettingsDateTimePicker_Birthday(), + _buildCardSettingsText_Disabled() + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'Colors', + ), + divider: Divider(thickness: 1.0, color: Colors.purple), + children: [ + _buildCardSettingsColorPicker_Coat(), + _buildCardSettingsColorPicker_Mane(), + _buildCardSettingsSwitch_Spots(), + _buildCardSettingsColorPicker_Spot(), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'Size', + ), + children: [ + _buildCardSettingsDouble_Height(), + _buildCardSettingsInt_Weight(), + _buildCardSettingsSelectionPicker_Style(), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'First Show', + ), + instructions: _buildCardSettingsInstructions(), + children: [ + _buildCardSettingsDatePicker(), + _buildCardSettingsPhotoPicker(), + _buildCardSettingsVideoPicker(), + _buildCardSettingsMusicPicker(), + _buildCardSettingsFileCustomPicker(), + _buildCardSettingsTimePicker(), + _buildCardSettingsCurrency(), + _buildCardSettingsPhone(), + _buildCardSettingsDouble_Slider(), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'Security', + ), + children: [ + _buildCardSettingsEmail(), + _buildCardSettingsPassword(), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'Actions', + ), + children: [ + _buildCardSettingsButton_Save(), + _buildCardSettingsButton_Reset(), + ], + ), + ], + ); + } + + CardSettings _buildLandscapeLayout() { + return CardSettings.sectioned( + showMaterialonIOS: widget.showMaterialonIOS, + labelPadding: 12.0, + children: [ + CardSettingsSection( + header: CardSettingsHeader( + label: 'Bio', + ), + children: [ + _buildCardSettingsText_Name(), + _buildCardSettingsListPicker_Type(), + CardFieldLayout( + [ + _buildCardSettingsRadioPicker_Gender(), + _buildCardSettingsNumberPicker_Age(labelAlign: TextAlign.right), + ], + flexValues: [2, 1], + ), + _buildCardSettingsParagraph_Description(3), + _buildCardSettingsCheckboxPicker_Hobbies(), + _buildCardSettingsDateTimePicker_Birthday(), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'Security', + ), + children: [ + CardFieldLayout([ + _buildCardSettingsEmail(), + _buildCardSettingsPassword(), + ]), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'Colors', + ), + children: [ + CardFieldLayout([ + _buildCardSettingsColorPicker_Coat(), + _buildCardSettingsColorPicker_Mane(), + ]), + CardFieldLayout([ + _buildCardSettingsSwitch_Spots(), + _buildCardSettingsColorPicker_Spot(), + ]), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'Size', + ), + children: [ + CardFieldLayout([ + _buildCardSettingsDouble_Height(), + _buildCardSettingsInt_Weight(), + _buildCardSettingsSelectionPicker_Style(), + ]), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'First Show', + ), + instructions: _buildCardSettingsInstructions(), + children: [ + CardFieldLayout([ + _buildCardSettingsDatePicker(), + _buildCardSettingsPhotoPicker(), + ]), + CardFieldLayout([ + _buildCardSettingsVideoPicker(), + _buildCardSettingsMusicPicker(), + ]), + CardFieldLayout([ + _buildCardSettingsFileCustomPicker(), + _buildCardSettingsTimePicker(), + ]), + CardFieldLayout([ + _buildCardSettingsCurrency(), + _buildCardSettingsPhone(), + ]), + _buildCardSettingsDouble_Slider(), + ], + ), + CardSettingsSection( + header: CardSettingsHeader( + label: 'Actions', + ), + children: [ + CardFieldLayout([ + _buildCardSettingsButton_Save(), + _buildCardSettingsButton_Reset(), + ]), + ], + ), + ], + ); + } + + CardSettingsButton _buildCardSettingsButton_Reset() { + return CardSettingsButton( + label: 'RESET', + isDestructive: true, + onPressed: resetPressed, + backgroundColor: Colors.red, + textColor: Colors.white, + bottomSpacing: 4.0, + ); + } + + CardSettingsButton _buildCardSettingsButton_Save() { + return CardSettingsButton( + label: 'SAVE', + backgroundColor: Colors.green, + onPressed: savePressed, + ); + } + + CardSettingsPassword _buildCardSettingsPassword() { + return CardSettingsPassword( + key: _passwordKey, + icon: Icon(Icons.lock), + labelWidth: 200, + initialValue: _ponyModel.password, + autovalidateMode: _autoValidateMode, + validator: (value) { + if (value == null) return 'Password is required.'; + if (value.length <= 6) return 'Must be more than 6 characters.'; + return null; + }, + onSaved: (value) => _ponyModel.password = value, + onChanged: (value) { + setState(() { + _ponyModel.password = value; + }); + widget.onValueChanged('Password', value); + }, + ); + } + + CardSettingsEmail _buildCardSettingsEmail() { + return CardSettingsEmail( + key: _emailKey, + icon: Icon(Icons.person), + initialValue: _ponyModel.email, + autovalidateMode: _autoValidateMode, + validator: (value) { + if (value == null || value.isEmpty) return 'Email is required.'; + if (!value.contains('@')) + return "Email not formatted correctly."; // use regex in real application + return null; + }, + onSaved: (value) => _ponyModel.email = value, + onChanged: (value) { + setState(() { + _ponyModel.email = value; + }); + widget.onValueChanged('Email', value); + }, + ); + } + + CardSettingsPhone _buildCardSettingsPhone() { + return CardSettingsPhone( + key: _phoneKey, + label: 'Box Office', + initialValue: _ponyModel.boxOfficePhone, + autovalidateMode: _autoValidateMode, + validator: (value) { + return null; + }, + onSaved: (value) => _ponyModel.boxOfficePhone = value, + onChanged: (value) { + setState(() { + _ponyModel.boxOfficePhone = value; + }); + widget.onValueChanged('Box Office', value); + }, + ); + } + + CardSettingsCurrency _buildCardSettingsCurrency() { + return CardSettingsCurrency( + key: _priceKey, + label: 'Ticket Price', + initialValue: _ponyModel.ticketPrice, + autovalidateMode: _autoValidateMode, + validator: (value) { + if (value != null && value > 100) return 'No scalpers allowed!'; + return null; + }, + onSaved: (value) => _ponyModel.ticketPrice = value, + onChanged: (value) { + setState(() { + _ponyModel.ticketPrice = value; + }); + widget.onValueChanged('Ticket Price', value); + }, + ); + } + + CardSettingsTimePicker _buildCardSettingsTimePicker() { + return CardSettingsTimePicker( + key: _timeKey, + icon: Icon(Icons.access_time), + label: 'Time', + initialValue: TimeOfDay( + hour: _ponyModel.showDateTime.hour, + minute: _ponyModel.showDateTime.minute), + onSaved: (value) => _ponyModel.showDateTime = + updateJustTime(value, _ponyModel.showDateTime), + onChanged: (value) { + setState(() { + _ponyModel.showDateTime = + updateJustTime(value, _ponyModel.showDateTime); + }); + widget.onValueChanged('Show Time', value); + }, + ); + } + + CardSettingsDatePicker _buildCardSettingsDatePicker() { + return CardSettingsDatePicker( + key: _dateKey, + icon: Icon(Icons.calendar_today), + label: 'Date', + dateFormat: DateFormat.yMMMMd(), + initialValue: _ponyModel.showDateTime, + onSaved: (value) => _ponyModel.showDateTime = + updateJustDate(value, _ponyModel.showDateTime), + onChanged: (value) { + setState(() { + _ponyModel.showDateTime = value; + }); + widget.onValueChanged( + 'Show Date', updateJustDate(value, _ponyModel.showDateTime)); + }, + ); + } + + CardSettingsFilePicker _buildCardSettingsPhotoPicker() { + return CardSettingsFilePicker( + key: _photoKey, + icon: Icon(Icons.photo), + label: 'Photo', + fileType: FileType.image, + initialValue: _ponyModel.photo, + onSaved: (value) => _ponyModel.photo = value, + onChanged: (value) { + setState(() { + _ponyModel.photo = value; + }); + }, + ); + } + + CardSettingsFilePicker _buildCardSettingsVideoPicker() { + return CardSettingsFilePicker( + key: _videoKey, + icon: Icon(Icons.video_library), + label: 'Video', + fileType: FileType.video, + initialValue: _ponyModel.video, + onSaved: (value) => _ponyModel.video = value, + onChanged: (value) { + setState(() { + _ponyModel.video = value; + }); + }, + ); + } + + CardSettingsFilePicker _buildCardSettingsMusicPicker() { + return CardSettingsFilePicker( + key: _audioKey, + icon: Icon(Icons.music_note), + label: 'Audio', + fileType: FileType.audio, + initialValue: _ponyModel.audio, + onSaved: (value) => _ponyModel.audio = value, + onChanged: (value) { + setState(() { + _ponyModel.audio = value; + }); + }, + ); + } + + CardSettingsFilePicker _buildCardSettingsFileCustomPicker() { + return CardSettingsFilePicker( + key: _customFileKey, + icon: Icon(Icons.insert_drive_file), + label: 'Custom file', + fileType: FileType.custom, + allowedExtensions: ['jpg'], + initialValue: _ponyModel.customFile, + onSaved: (value) => _ponyModel.customFile = value, + onChanged: (value) { + setState(() { + _ponyModel.customFile = value; + }); + }, + ); + } + + CardSettingsDateTimePicker _buildCardSettingsDateTimePicker_Birthday() { + return CardSettingsDateTimePicker( + key: _datetimeKey, + icon: Icon(Icons.card_giftcard, color: Colors.yellow[700]), + label: 'Birth day', + initialValue: _ponyModel.showDateTime, + onSaved: (value) => _ponyModel.showDateTime = + updateJustDate(value, _ponyModel.showDateTime), + onChanged: (value) { + setState(() { + _ponyModel.showDateTime = value; + }); + widget.onValueChanged( + 'Show Date', updateJustDate(value, _ponyModel.showDateTime)); + }, + ); + } + + CardSettingsInstructions _buildCardSettingsInstructions() { + return CardSettingsInstructions( + text: 'This is when this little horse got her big break', + ); + } + + CardSettingsInt _buildCardSettingsInt_Weight() { + return CardSettingsInt( + key: _weightKey, + label: 'Weight', + unitLabel: '(lbs)', + initialValue: _ponyModel.weight, + autovalidateMode: _autoValidateMode, + validator: (value) { + if (value != null) { + if (value > 70) return 'You won\'t fly at the weight.'; + if (value < 10) return 'Cmon, you are not a feather.'; + } + return null; + }, + onSaved: (value) => _ponyModel.weight = value, + onChanged: (value) { + setState(() { + _ponyModel.weight = value; + }); + widget.onValueChanged('Weight', value); + }, + ); + } + + CardSettingsDouble _buildCardSettingsDouble_Height() { + return CardSettingsDouble( + key: _heightKey, + label: 'Height', + unitLabel: '(ft)', + decimalDigits: 2, + locale: Locale('fr'), // force french mode to simulate localization + initialValue: _ponyModel.height, + onSaved: (value) => _ponyModel.height = value, + onChanged: (value) { + setState(() { + _ponyModel.height = value; + }); + widget.onValueChanged('Height', value); + }, + ); + } + + CardSettingsColorPicker _buildCardSettingsColorPicker_Spot() { + return CardSettingsColorPicker( + key: _spotKey, + label: 'Spot', + pickerType: CardSettingsColorPickerType.block, + initialValue: intelligentCast(_ponyModel.spotColor), + visible: _ponyModel.hasSpots, + onSaved: (value) => _ponyModel.spotColor = colorToString(value), + onChanged: (value) { + setState(() { + _ponyModel.spotColor = colorToString(value); + }); + widget.onValueChanged('Spot', value); + }, + ); + } + + CardSettingsSwitch _buildCardSettingsSwitch_Spots() { + return CardSettingsSwitch( + key: _hasSpotsKey, + label: 'Has spots?', + initialValue: _ponyModel.hasSpots, + onSaved: (value) => _ponyModel.hasSpots = value, + onChanged: (value) { + setState(() { + _ponyModel.hasSpots = value; + }); + widget.onValueChanged('Has Spots?', value); + }, + ); + } + + CardSettingsColorPicker _buildCardSettingsColorPicker_Mane() { + return CardSettingsColorPicker( + key: _maneKey, + label: 'Mane', + initialValue: intelligentCast(_ponyModel.maneColor), + autovalidateMode: _autoValidateMode, + pickerType: CardSettingsColorPickerType.material, + validator: (value) { + if (value.computeLuminance() > .7) return 'This color is too light.'; + return null; + }, + onSaved: (value) => _ponyModel.maneColor = colorToString(value), + onChanged: (value) { + setState(() { + _ponyModel.maneColor = colorToString(value); + }); + widget.onValueChanged('Mane', value); + }, + ); + } + + CardSettingsColorPicker _buildCardSettingsColorPicker_Coat() { + return CardSettingsColorPicker( + key: _coatKey, + label: 'Coat', + initialValue: intelligentCast(_ponyModel.coatColor), + autovalidateMode: _autoValidateMode, + validator: (value) { + if (value.computeLuminance() < .3) + return 'This color is not cheery enough.'; + return null; + }, + onSaved: (value) => _ponyModel.coatColor = colorToString(value), + onChanged: (value) { + setState(() { + _ponyModel.coatColor = colorToString(value); + }); + widget.onValueChanged('Coat', value); + }, + ); + } + + CardSettingsCheckboxPicker _buildCardSettingsCheckboxPicker_Hobbies() { + return CardSettingsCheckboxPicker( + key: _hobbiesKey, + label: 'Hobbies', + initialItems: _ponyModel.hobbies, + items: allHobbies, + autovalidateMode: _autoValidateMode, + validator: (List value) { + if (value == null || value.isEmpty) + return 'You must pick at least one hobby.'; + + return null; + }, + onSaved: (value) => _ponyModel.hobbies = value, + onChanged: (value) { + setState(() { + _ponyModel.hobbies = value; + }); + widget.onValueChanged('Hobbies', value); + }, + ); + } + + CardSettingsParagraph _buildCardSettingsParagraph_Description(int lines) { + return CardSettingsParagraph( + key: _descriptionlKey, + label: 'Description', + initialValue: _ponyModel.description, + numberOfLines: lines, + focusNode: _descriptionNode, + onSaved: (value) => _ponyModel.description = value, + onChanged: (value) { + setState(() { + _ponyModel.description = value; + }); + widget.onValueChanged('Description', value); + }, + ); + } + + CardSettingsNumberPicker _buildCardSettingsNumberPicker_Age( + {TextAlign labelAlign}) { + return CardSettingsNumberPicker( + key: _ageKey, + label: 'Age', + labelAlign: labelAlign, + initialValue: _ponyModel.age, + min: 1, + max: 17, + stepInterval: 2, + validator: (value) { + if (value == null) return 'Age is required.'; + if (value > 20) return 'No grown-ups allwed!'; + if (value < 3) return 'No Toddlers allowed!'; + return null; + }, + onSaved: (value) => _ponyModel.age = value, + onChanged: (value) { + setState(() { + _ponyModel.age = value; + }); + widget.onValueChanged('Age', value); + }, + ); + } + + CardSettingsListPicker _buildCardSettingsListPicker_Type() { + return CardSettingsListPicker( + key: _typeKey, + label: 'Type', + initialItem: _ponyModel.type, + hintText: 'Select One', + autovalidateMode: _autoValidateMode, + items: ponyTypes, + validator: (PickerModel value) { + if (value == null || value.toString().isEmpty) + return 'You must pick a type.'; + return null; + }, + onSaved: (value) => _ponyModel.type = value, + onChanged: (value) { + setState(() { + _ponyModel.type = value; + }); + widget.onValueChanged('Type', value); + }, + ); + } + + CardSettingsText _buildCardSettingsText_Name() { + return CardSettingsText( + key: _nameKey, + label: 'Name', + hintText: 'something cute...', + initialValue: _ponyModel.name, + requiredIndicator: Text('*', style: TextStyle(color: Colors.red)), + autovalidateMode: _autoValidateMode, + focusNode: _nameNode, + inputAction: TextInputAction.next, + inputActionNode: _descriptionNode, + //inputMask: '000.000.000.000', + validator: (value) { + if (value == null || value.isEmpty) return 'Name is required.'; + return null; + }, + onSaved: (value) => _ponyModel.name = value, + onChanged: (value) { + setState(() { + _ponyModel.name = value; + }); + widget.onValueChanged('Name', value); + }, + ); + } + + CardSettingsText _buildCardSettingsText_Disabled() { + return CardSettingsText( + label: 'Disabled', + hintText: 'something disabled...', + enabled: false, + ); + } + + CardSettingsRadioPicker _buildCardSettingsRadioPicker_Gender() { + return CardSettingsRadioPicker( + key: _genderKey, + label: 'Gender', + initialItem: _ponyModel.gender, + hintText: 'Select One', + autovalidateMode: _autoValidateMode, + items: ponyGenders, + validator: (PickerModel value) { + if (value == null || value.toString().isEmpty) + return 'You must pick a gender.'; + return null; + }, + onSaved: (value) => _ponyModel.gender = value, + onChanged: (value) { + setState(() { + _ponyModel.gender = value; + }); + widget.onValueChanged('Gender', value); + }, + ); + } + + CardSettingsSelectionPicker _buildCardSettingsSelectionPicker_Style() { + return CardSettingsSelectionPicker( + key: _styleKey, + label: 'Style', + initialItem: _ponyModel.style, + hintText: 'Select One', + autovalidateMode: _autoValidateMode, + items: ponyStyles, + iconizer: (item) => item.icon, + validator: (PickerModel value) { + if (value == null || value.toString().isEmpty) + return 'You must pick a style.'; + return null; + }, + onSaved: (value) => _ponyModel.style = value, + onChanged: (value) { + setState(() { + _ponyModel.style = value; + }); + widget.onValueChanged('Style', value.code); + }, + ); + } + + CardSettingsSlider _buildCardSettingsDouble_Slider() { + return CardSettingsSlider( + key: _sliderKey, + label: 'Rating', + initialValue: _ponyModel.rating, + autovalidateMode: _autoValidateMode, + validator: (double value) { + if (value == null) return 'You must pick a rating.'; + return null; + }, + onSaved: (value) => _ponyModel.rating = value, + onChanged: (value) { + setState(() { + _ponyModel.rating = value; + }); + widget.onValueChanged('Rating', value); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/card_settings.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/card_settings.dart new file mode 100644 index 00000000..f1ab6890 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/card_settings.dart @@ -0,0 +1,44 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +/// Package for building card based settings forms +library card_settings; + +export 'helpers/converter_functions.dart'; +export 'widgets/action_fields/card_settings_button.dart'; +export 'widgets/card_field_layout.dart'; +export 'widgets/card_settings_widget.dart'; +export 'widgets/card_settings_field.dart'; +export 'widgets/card_settings_panel.dart'; +export 'widgets/information_fields/card_settings_header.dart'; +export 'widgets/information_fields/card_settings_instructions.dart'; +export 'widgets/numeric_fields/card_settings_currency.dart'; +export 'widgets/numeric_fields/card_settings_double.dart'; +export 'widgets/numeric_fields/card_settings_int.dart'; +export 'widgets/numeric_fields/card_settings_switch.dart'; +export 'widgets/picker_fields/card_settings_color_picker.dart'; +export 'widgets/picker_fields/card_settings_date_picker.dart'; +export 'widgets/picker_fields/card_settings_file_picker.dart'; +export 'widgets/picker_fields/card_settings_list_picker.dart'; +export 'widgets/picker_fields/card_settings_radio_picker.dart'; +export 'widgets/picker_fields/card_settings_selection_picker.dart'; +export 'widgets/picker_fields/card_settings_checkbox_picker.dart'; +export 'widgets/picker_fields/card_settings_number_picker.dart'; +export 'widgets/picker_fields/card_settings_time_picker.dart'; +export 'widgets/picker_fields/card_settings_datetime_picker.dart'; +export 'widgets/text_fields/card_settings_email.dart'; +export 'widgets/text_fields/card_settings_paragraph.dart'; +export 'widgets/text_fields/card_settings_password.dart'; +export 'widgets/text_fields/card_settings_phone.dart'; +export 'widgets/text_fields/card_settings_text.dart'; +export 'widgets/numeric_fields/card_settings_slider.dart'; +export 'widgets/card_settings_widget.dart'; + +//export 'package:flutter_material_pickers/flutter_material_pickers.dart'show PickerModel; +export 'models/picker_model.dart'; + +/// this is the default height for the cupertino scroll wheel +const double kCupertinoPickerSheetHeight = 216.0; + +/// this is the default height for a single item in cupertino picker +const double kCupertinoPickerItemHeight = 32.0; diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/converter_functions.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/converter_functions.dart new file mode 100644 index 00000000..4c7db0a2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/converter_functions.dart @@ -0,0 +1,107 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'dart:math'; +import 'dart:ui'; +import 'package:flutter/material.dart'; + +/// This attempts to intelligently cast any value to the desired type. +T intelligentCast(dynamic value) { + // instead of empty string we want to return null + if (value.toString().isEmpty) return null; + + // already expected type, return it + if (value is T) return value; + + // process bool here, since we need to return false rather than null + if (T.toString() == 'bool') return boolParse(value.toString()) as T; + + // if null, dont change it. + if (value == null) return null; + + // perform explicit parsing on the value as a string + if (T.toString() == 'double') return double.parse(value.toString()) as T; + if (T.toString() == 'double') return double.parse(value.toString()) as T; + if (T.toString() == 'int') return int.parse(value.toString()) as T; + if (T.toString() == 'int') return int.parse(value.toString()) as T; + if (T.toString() == 'Color') return colorParse(value) as T; + + throw Exception('Failed to convert $value to $T'); +} + +/// This will parse various conceptual representaitons of yes/no into a boolean +bool boolParse(String value) { + if (value == null) return false; + + if (value.toLowerCase() == 'true') return true; + if (value.toLowerCase() == 'false') return false; + + if (value.toLowerCase() == '1') return true; + if (value.toLowerCase() == '0') return false; + + if (value.toLowerCase() == 'yes') return true; + if (value.toLowerCase() == 'no') return false; + + return false; +} + +/// This will parse either a string or integer representation of a color into an actual Color +Color colorParse(dynamic value) { + // input is string (e.g. 'FF112233') convert to integer + if (value is String) { + if (value.toString().length == 6) value = 'FF' + value.toString(); + value = int.parse(value.toString(), radix: 16); + } + + // input is integer (e.g. 0xFF112233) convert to color + if (value is int) { + return Color(value).withOpacity(1.0); + } + + throw Exception('Failed to convert $value to Color'); +} + +/// This will convert a Color to a hex string (more abreviated than the .toString() method. +String colorToString(Color color) { + return color.toString().split('(0x')[1].split(')')[0]; +} + +/// Given a DateTime this will replace just the date portion leaving the time unchanged +DateTime updateJustDate(DateTime newDate, DateTime originalDateTime) { + return DateTime( + newDate.year, // year + newDate.month, // month + newDate.day, // day + originalDateTime.hour, // hour + originalDateTime.minute, // minute + originalDateTime.second, // second + originalDateTime.millisecond, // millisecond + originalDateTime.microsecond, // microsecond + ); +} + +/// Given a DateTime this will replace just the time portion leaving the date unchanged +DateTime updateJustTime(TimeOfDay newTime, DateTime originalDateTime) { + return DateTime( + originalDateTime.year, // year + originalDateTime.month, // month + originalDateTime.day, // day + newTime.hour, // hour + newTime.minute, // minute + 0, // second + 0, // millisecond + 0, // microsecond + ); +} + +/// used to reverse the value from an mask_formatter controller +String unmaskValue(String mask, String maskedValue) { + String specialCharacters = '0A@*'; + String unmaskedValue = ''; + + for (int i = 0; i < min(mask.length, maskedValue.length); i++) { + if (specialCharacters.contains(mask[i])) unmaskedValue += maskedValue[i]; + } + + return unmaskedValue; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/decimal_text_input_formatter.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/decimal_text_input_formatter.dart new file mode 100644 index 00000000..f4d849ed --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/decimal_text_input_formatter.dart @@ -0,0 +1,43 @@ +import 'dart:math' as math; +import 'package:flutter/services.dart'; + +/// Limits text entry to decimal characters only +class DecimalTextInputFormatter extends TextInputFormatter { + DecimalTextInputFormatter({this.decimalDigits}) + : assert(decimalDigits == null || decimalDigits > 0); + + final int decimalDigits; + + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, // unused. + TextEditingValue newValue, + ) { + TextSelection newSelection = newValue.selection; + String truncated = newValue.text; + + if (decimalDigits != null) { + String value = newValue.text; + + if (value.contains(".") && + value.substring(value.indexOf(".") + 1).length > decimalDigits) { + truncated = oldValue.text; + newSelection = oldValue.selection; + } else if (value == ".") { + truncated = "0."; + + newSelection = newValue.selection.copyWith( + baseOffset: math.min(truncated.length, truncated.length + 1), + extentOffset: math.min(truncated.length, truncated.length + 1), + ); + } + + return TextEditingValue( + text: truncated, + selection: newSelection, + composing: TextRange.empty, + ); + } + return newValue; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/platform_functions.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/platform_functions.dart new file mode 100644 index 00000000..e3524412 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/helpers/platform_functions.dart @@ -0,0 +1,55 @@ +import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import '../card_settings.dart'; + +/// this centralizes code to determine if we want to display the cupertino +/// version or the material version, since this can be determined by +/// several settings throughout the package +bool showCupertino( + BuildContext context, + bool showMaterialonIOS, { + bool mockIOS = false, +}) { + bool defaultValue = false; + + // don't show on web + if (kIsWeb) return defaultValue; + + // if we are on iOS then determine if we want material + if (mockIOS || Platform.isIOS) { + // if showMaterialonIOS not specified calculate it + if (showMaterialonIOS == null) { + showMaterialonIOS = defaultValue; + + if (context != null) + // set showMaterialOnIOS to parent CardSettings value + showMaterialonIOS = + CardSettings.of(context).showMaterialonIOS ?? defaultValue; + } + + return !showMaterialonIOS; + } + + // material by default + return defaultValue; +} + +/// This centralizes the style calculations for field labels, used by almost all widgets in this package +TextStyle labelStyle(BuildContext context, bool enabled) { + var theme = Theme.of(context); + var style = theme.textTheme.subtitle1; + if (!enabled) style = style?.copyWith(color: theme.disabledColor); + return style; +} + +/// This centralizes the style calculations for content, used by almost all widgets in this package +TextStyle contentStyle(BuildContext context, dynamic value, bool enabled) { + var theme = Theme.of(context); + var style = theme.textTheme.subtitle1?.copyWith( + color: + (value == null) ? theme.hintColor : theme.textTheme.subtitle1?.color); + if (!enabled) style = style?.copyWith(color: theme.disabledColor); + return style; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/common_field_properties.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/common_field_properties.dart new file mode 100644 index 00000000..47193fc0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/common_field_properties.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; + +import 'minimum_field_properties.dart'; + +/// Interface to ensure that all widgets implement this minimum +/// set of properties +abstract class ICommonFieldProperties extends IMinimumFieldSettings { + final String label = null; + final double labelWidth = null; + final TextAlign labelAlign = null; + final TextAlign contentAlign = null; + final EdgeInsetsGeometry fieldPadding = null; + final Icon icon = null; + final Widget requiredIndicator = null; + + final Function onChanged = null; + final Function onSaved = null; + final Function validator = null; + //final bool autovalidate = null; + final AutovalidateMode autovalidateMode = AutovalidateMode.onUserInteraction; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/minimum_field_properties.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/minimum_field_properties.dart new file mode 100644 index 00000000..1f26c941 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/minimum_field_properties.dart @@ -0,0 +1,10 @@ +import '../widgets/card_settings_widget.dart'; + +/// abstract class to ensure that all widgets implement the base +/// set of properties expected buy the settings panel wrapper +abstract class IMinimumFieldSettings implements CardSettingsWidget { + @override + final bool showMaterialonIOS = null; + @override + final bool visible = null; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/text_field_properties.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/text_field_properties.dart new file mode 100644 index 00000000..1b855a80 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/interfaces/text_field_properties.dart @@ -0,0 +1,5 @@ +/// Interface to ensure that all text widgets implement this +/// minimum set of properties +abstract class ITextFieldProperties { + final String hintText = null; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/models/picker_model.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/models/picker_model.dart new file mode 100644 index 00000000..eaee0866 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/models/picker_model.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; + +class PickerModel { + const PickerModel(this.name, {this.code, this.icon}); + final String name; + final Object code; + final Icon icon; + + @override + String toString() => name; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/action_fields/card_settings_button.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/action_fields/card_settings_button.dart new file mode 100755 index 00000000..04bb22c3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/action_fields/card_settings_button.dart @@ -0,0 +1,113 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; + +import '../../interfaces/minimum_field_properties.dart'; + +/// This is a button widget for inclusion in the form. +class CardSettingsButton extends StatelessWidget + implements IMinimumFieldSettings { + CardSettingsButton({ + this.label: 'Label', + @required this.onPressed, + this.visible: true, + this.backgroundColor, + this.textColor, + this.enabled = true, + this.bottomSpacing: 0.0, + this.isDestructive = false, + this.showMaterialonIOS, + }); + + /// The text to place in the button + final String label; + + /// tells the Ui the button is destructive. Helps select color. + final bool isDestructive; + + /// The background color for normal buttons + final Color backgroundColor; + + /// The text color for normal buttons + final Color textColor; + + /// allows adding extra padding at the bottom + final double bottomSpacing; + + /// If false, grays out the field and makes it unresponsive + final bool enabled; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Fires when the button is pressed + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + TextStyle buttonStyle = + Theme.of(context).textTheme.button.copyWith(color: textColor); + + if (visible) { + if (showCupertino(context, showMaterialonIOS)) + return _showCuppertinoButton(); + else + return _showMaterialButton(context, buttonStyle); + } else { + return Container(); + } + } + + Widget _showMaterialButton(BuildContext context, TextStyle buttonStyle) { + var fillColor = backgroundColor ?? Theme.of(context).buttonColor; + if (!enabled) fillColor = Colors.grey; + + return Container( + margin: EdgeInsets.only( + top: 4.0, bottom: bottomSpacing, left: 4.0, right: 4.0), + padding: EdgeInsets.all(0.0), + color: fillColor, + child: RawMaterialButton( + padding: EdgeInsets.all(0.0), + elevation: 0.0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + label, + style: buttonStyle, + ), + ], + ), + fillColor: fillColor, + onPressed: (enabled) + ? onPressed + : null, // to disable, we need to not provide an onPressed function + ), + ); + } + + Widget _showCuppertinoButton() { + return Container( + child: visible == false + ? null + : CSButton( + isDestructive + ? CSButtonType.DESTRUCTIVE + : CSButtonType.DEFAULT_CENTER, + label, + onPressed, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_field_layout.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_field_layout.dart new file mode 100644 index 00000000..40ddefe7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_field_layout.dart @@ -0,0 +1,46 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'card_settings_widget.dart'; + +/// Lays out multiple fields in a row +class CardFieldLayout extends StatelessWidget implements CardSettingsWidget { + CardFieldLayout( + this.children, { + this.flexValues, + this.visible: true, + this.showMaterialonIOS: false, + }); + + /// the field widgets to place into the layout + final List children; + + /// the values that control the relative widths of the layed out widgets + final List flexValues; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + @override + Widget build(BuildContext context) { + if (!visible) return Container(); + + int iterator = 0; + + return Row( + children: children + .map((c) => Flexible( + child: c, + flex: (flexValues == null) ? 1 : (flexValues[iterator++] ?? 1), + )) + .toList(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_field.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_field.dart new file mode 100644 index 00000000..5e6b15de --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_field.dart @@ -0,0 +1,287 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import '../interfaces/common_field_properties.dart'; +import 'card_settings_panel.dart'; + +const unimplemented = "implement in the wrapper widget"; + +/// This is the basic layout of a field in a CardSettings view. Typcially, it +/// will not be used directly. +class CardSettingsField extends StatelessWidget + implements ICommonFieldProperties { + CardSettingsField({ + this.label: 'Label', + @required this.content, + this.icon, + this.pickerIcon, + this.labelWidth, + this.contentOnNewLine = false, + this.unitLabel, + this.errorText, + this.visible: true, + @required this.labelAlign, + @required this.requiredIndicator, + this.enabled = true, + @required this.fieldPadding, + }); + + /// The text to identify the field to the user + @override + final String label; + + /// If provided, displays text to the right of the content. + final String unitLabel; + + /// The widget that is placed in the content region of the field + final Widget content; + + /// If the field is a picker, this is the icon shown to the right of the content + final IconData pickerIcon; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// Place the content below the label rather than next to the label + final bool contentOnNewLine; + + /// The text to display if the field fails validation + final String errorText; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// If false, grays out the field and makes it unresponsive + final bool enabled; + + /// padding to place around the entire field widget + @override + final EdgeInsetsGeometry fieldPadding; + + @override + TextAlign get contentAlign => throw UnimplementedError(unimplemented); + + @override + bool get showMaterialonIOS => throw UnimplementedError(unimplemented); + + @override + AutovalidateMode get autovalidateMode => throw UnimplementedError(); + + @override + Function get onChanged => throw UnimplementedError(unimplemented); + + @override + Function get onSaved => throw UnimplementedError(unimplemented); + + @override + Function get validator => throw UnimplementedError(unimplemented); + + @override + Widget build(BuildContext context) { + EdgeInsetsGeometry _fieldPadding = (fieldPadding ?? + CardSettings.of(context).fieldPadding ?? + EdgeInsets.only(left: 14.0, top: 8.0, right: 14.0, bottom: 8.0)); + + if (visible) { + return Container( + padding: _fieldPadding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildLabelBlock(context), + _buildInlineContent(context), + _buildRightDecoration() + ], + ), + _buildNewRowContent(context) + ], + ), + ); + } else { + return Container(); + } + } + + Widget _buildInlineContent(BuildContext context) { + return contentOnNewLine + ? Container() + : Expanded(child: _buildDecoratedContent(context)); + } + + Widget _buildNewRowContent(BuildContext context) { + if (contentOnNewLine) { + return Container( + padding: EdgeInsets.only(top: 10.0), + child: _buildDecoratedContent(context), + ); + } else { + return Container(); + } + } + + Widget _buildDecoratedContent(BuildContext context) { + var decoratedContent = content; + if (content is TextField || content is TextFormField) { + // do nothing, these already have built in InputDecorations + } else { + // wrap in a decorator to show validation errors + final InputDecoration decoration = const InputDecoration() + .applyDefaults(Theme.of(context).inputDecorationTheme) + .copyWith( + errorText: errorText, + contentPadding: EdgeInsets.all(0.0), + isDense: true, + border: InputBorder.none); + + decoratedContent = InputDecorator(decoration: decoration, child: content); + } + + return decoratedContent; + } + + Widget _buildLabelBlock(BuildContext context) { + var padding = + EdgeInsets.only(right: CardSettings.of(context).labelPadding ?? 6.0); + + return (contentOnNewLine) + ? Expanded( + child: Container( + padding: padding, + child: _buildLabelRow(context), + ), + ) + : Container( + width: labelWidth ?? CardSettings.of(context).labelWidth ?? 120.0, + padding: padding, + child: _buildLabelRow(context), + ); + } + + Row _buildLabelRow(BuildContext context) { + return Row( + children: [ + _buildLeftIcon(context), + _buildLabelSpacer(context), + Expanded( + child: Row( + children: [ + _buildLabelText(context), + _buildlabelRequiredIndicator(context), + ], + ), + ), + _buildLabelSuffix(context), + ], + ); + } + + Widget _buildLabelText(BuildContext context) { + // make long label to wrap to the second line + return Flexible( + child: Text( + label, + softWrap: true, + style: _buildLabelStyle(context), + ), + ); + } + + Widget _buildLabelSpacer(BuildContext context) { + return ((labelAlign ?? + CardSettings.of(context).labelAlign ?? + TextAlign.left) == + TextAlign.right) + ? Expanded(child: Container()) + : Container(); + } + + Widget _buildLabelSuffix(BuildContext context) { + return Text( + CardSettings.of(context).labelSuffix ?? '', + style: _buildLabelStyle(context), + ); + } + + Widget _buildlabelRequiredIndicator(BuildContext context) { + if (requiredIndicator == null) return Container(); + + if (requiredIndicator is Text) { + var indicatorStyle = (requiredIndicator as Text).style; + var style = _buildLabelStyle(context).merge(indicatorStyle); + + return Text( + (requiredIndicator as Text).data ?? '', + style: style, + ); + } + + return requiredIndicator; + } + + TextStyle _buildLabelStyle(BuildContext context) { + TextStyle labelStyle = TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16.0, + ); + + labelStyle = + labelStyle.merge(Theme.of(context).inputDecorationTheme.labelStyle); + if (!enabled) + labelStyle = labelStyle.copyWith(color: Theme.of(context).disabledColor); + + return labelStyle; + } + + Widget _buildLeftIcon(BuildContext context) { + TextStyle labelStyle = Theme.of(context).inputDecorationTheme.labelStyle; + + return (icon == null) + ? Container() + : Container( + // margin: EdgeInsets.all(0.0), + // padding: EdgeInsets.only(right: 4.0), + // child: Icon( + // Icon.icon, + // color: (Icon.color != null) + // ? Icon.color + // : (labelStyle == null) + // ? null + // : labelStyle.color, + // ), + ); + } + + Widget _buildRightDecoration() { + return (pickerIcon != null || unitLabel != null) + ? Container( + padding: EdgeInsets.only(left: 10), + alignment: Alignment.centerRight, + child: (pickerIcon != null) + ? Icon(pickerIcon, size: 20) + : Text( + unitLabel ?? '', + style: TextStyle(fontStyle: FontStyle.italic), + ), + ) + : Container(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_panel.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_panel.dart new file mode 100755 index 00000000..9988d43b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_panel.dart @@ -0,0 +1,257 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; + +import 'action_fields/card_settings_button.dart'; +import 'card_settings_widget.dart'; +import 'information_fields/card_settings_header.dart'; +import 'information_fields/card_settings_instructions.dart'; + +/// This is the card wrapper that all the field controls are placed into +class CardSettings extends InheritedWidget { + CardSettings({ + Key key, + this.labelAlign, + this.labelWidth, + this.labelPadding, + this.labelSuffix, + this.contentAlign: TextAlign.left, + this.padding: const EdgeInsets.all(0.0), + this.margin: const EdgeInsets.all(8.0), + this.cardElevation, + List children: const [], + this.showMaterialonIOS: false, + this.shrinkWrap = false, + this.cardless = false, + this.divider, + this.scrollable = true, + this.fieldPadding, + }) : super( + key: key, + child: _CardSettingsContent( + children: children, + showMaterialonIOS: showMaterialonIOS, + cardElevation: cardElevation, + padding: padding, + margin: margin, + shrinkWrap: shrinkWrap, + sectioned: false, + cardless: cardless, + scrollable: scrollable, + ), + ); + + /// constructor that wraps each section in it's own card + CardSettings.sectioned({ + Key key, + this.labelAlign, + this.labelWidth, + this.labelPadding, + this.labelSuffix, + this.contentAlign: TextAlign.left, + this.padding: const EdgeInsets.all(0.0), + this.margin: const EdgeInsets.fromLTRB(8, 8, 8, 0.0), + this.cardElevation, + List children: const [], + this.showMaterialonIOS: false, + this.shrinkWrap = true, + this.cardless = false, + this.divider, + this.scrollable = true, + this.fieldPadding, + }) : super( + key: key, + child: _CardSettingsContent( + children: children, + showMaterialonIOS: showMaterialonIOS, + cardElevation: cardElevation, + padding: padding, + margin: margin, + shrinkWrap: shrinkWrap, + sectioned: true, + cardless: cardless, + scrollable: scrollable, + ), + ); + + final TextAlign labelAlign; + final double labelWidth; + final double labelPadding; + final String labelSuffix; + final TextAlign contentAlign; + final EdgeInsetsGeometry padding; + final EdgeInsetsGeometry margin; + final double cardElevation; + final bool shrinkWrap; + final bool showMaterialonIOS; + final bool cardless; + final Divider divider; + final bool scrollable; + final EdgeInsetsGeometry fieldPadding; + + static CardSettings of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + /// notify child widgets if a setting changes on the overall wrapper + @override + bool updateShouldNotify(CardSettings old) { + if (labelAlign != old.labelAlign) return true; + if (labelWidth != old.labelWidth) return true; + if (labelPadding != old.labelPadding) return true; + if (labelSuffix != old.labelSuffix) return true; + if (contentAlign != old.contentAlign) return true; + return false; + } +} + +/// This provides some common properties for the content +/// area of a card settings form +class _CardSettingsContent extends StatelessWidget { + const _CardSettingsContent({ + Key key, + this.children: const [], + @required this.showMaterialonIOS, + @required this.cardElevation, + @required this.padding, + @required this.margin, + @required this.shrinkWrap, + this.sectioned: true, + this.cardless: false, + this.scrollable: true, + }) : super(key: key); + + final List children; + final bool showMaterialonIOS; + final double cardElevation; + final EdgeInsetsGeometry padding; + final EdgeInsetsGeometry margin; + final bool shrinkWrap; + final bool sectioned; + final bool cardless; + final bool scrollable; + + @override + Widget build(BuildContext context) { + return (showCupertino(null, showMaterialonIOS)) + ? _buildCupertinoWrapper() + : _buildMaterialWrapper(context); + } + + Widget _buildCupertinoWrapper() { + return CupertinoSettings( + items: children, + shrinkWrap: shrinkWrap, + ); + } + + Widget _buildMaterialWrapper(BuildContext context) { + var cards = (sectioned) + ? Column( + children: _buildMaterialSections(context), + ) + : _buildMaterialCardWrapper( + context, + content: Column(children: children), + ); + + var wrapper = (scrollable) ? SingleChildScrollView(child: cards) : cards; + + return SafeArea(child: wrapper); + } + + List _buildMaterialSections(BuildContext context) { + List _children = []; + + // build a separate card for each section + for (var section in children) { + _children.add( + _buildMaterialCardWrapper( + context, + content: section.build(context), + ), + ); + } + return _children; + } + + Widget _buildMaterialCardWrapper(BuildContext context, {Widget content}) { + return (cardless) + ? Container( + margin: margin, + padding: padding, + child: content, + ) + : Card( + margin: margin, + clipBehavior: + Theme.of(context).cardTheme.clipBehavior ?? Clip.antiAlias, + elevation: cardElevation, + child: Padding( + padding: padding ?? EdgeInsets.all(0), + child: content, + ), + ); + } +} + +/// This visually wraps a logical grouping of form widgets +class CardSettingsSection extends StatelessWidget { + CardSettingsSection({ + this.instructions, + this.children, + this.header, + this.showMaterialonIOS: false, + this.divider, + }); + + final CardSettingsHeader header; + final CardSettingsInstructions instructions; + final List children; + final bool showMaterialonIOS; + final Divider divider; + + @override + Widget build(BuildContext context) { + var _divider = divider ?? + CardSettings.of(context).divider ?? + Divider( + thickness: 1.0, + color: Theme.of(context).dividerColor, + ); + + List _children = []; + if (showCupertino(context, showMaterialonIOS)) { + if (header != null) _children.add(header); + if (children != null) _children.addAll(children); + if (instructions != null) _children.add(instructions); + } else { + if (header != null) _children.add(header); + if (instructions != null) _children.add(instructions); + + if (children != null) { + var visibleChildren = children.where((c) => c.visible ?? true); + for (var child in visibleChildren) { + _children.add(child); + + var addDivider = true; + if (child is CardSettingsButton) + addDivider = false; // don't put divider between buttons + if (child == visibleChildren.last) + addDivider = false; // don't put a divider after the last item + if (addDivider) _children.add(_divider); + } + } + } + + //return Column(children: _children); + + return Column( + children: _children, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_widget.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_widget.dart new file mode 100644 index 00000000..76f7b6fb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/card_settings_widget.dart @@ -0,0 +1,8 @@ +import 'package:flutter/material.dart'; + +/// abstract class to ensure that all widgets implement the base +/// set of properties expected by the settings panel wrapper +abstract class CardSettingsWidget extends Widget { + final bool showMaterialonIOS = null; + final bool visible = null; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/information_fields/card_settings_header.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/information_fields/card_settings_header.dart new file mode 100644 index 00000000..747d04d8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/information_fields/card_settings_header.dart @@ -0,0 +1,96 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; + +import '../card_settings_panel.dart'; +import '../card_settings_widget.dart'; + +/// This is a header to distinguish sections of the form. +class CardSettingsHeader extends StatelessWidget implements CardSettingsWidget { + CardSettingsHeader({ + this.label: 'Label', + this.labelAlign: TextAlign.left, + this.height: 44.0, + this.color, + this.showMaterialonIOS, + this.visible = true, + this.child, + this.fieldPadding, + }); + + /// the text for the header + final String label; + + /// how to align the header text + final TextAlign labelAlign; + + /// the height of the content + final double height; + + /// the background color + final Color color; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// The child to place in the content, instead of the label + final Widget child; + + /// placed padding around the entire widget + final EdgeInsetsGeometry fieldPadding; + + @override + Widget build(BuildContext context) { + if (!visible) return Container(); + if (child != null) return child ?? Container(); + + if (showCupertino(context, showMaterialonIOS)) + return _cupertinoHeader(context); + else + return _materialHeader(context); + } + + Widget _cupertinoHeader(BuildContext context) { + return Row( + children: [ + Expanded( + child: CSHeader(label), + ), + ], + ); + } + + Widget _materialHeader(BuildContext context) { + EdgeInsetsGeometry _fieldPadding = (fieldPadding ?? + CardSettings.of(context).fieldPadding ?? + EdgeInsets.only(left: 14.0, top: 8.0, right: 14.0, bottom: 8.0)); + + return Container( + margin: EdgeInsets.all(0.0), + decoration: BoxDecoration( + color: color ?? Theme.of(context).secondaryHeaderColor, + ), + height: height, + padding: _fieldPadding, + child: Row( + children: [ + Expanded( + child: Text( + label, + style: Theme.of(context).textTheme.headline6, + textAlign: labelAlign, + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/information_fields/card_settings_instructions.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/information_fields/card_settings_instructions.dart new file mode 100644 index 00000000..62952fc5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/information_fields/card_settings_instructions.dart @@ -0,0 +1,84 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; + +import '../card_settings_panel.dart'; +import '../card_settings_widget.dart'; + +/// This is a read only section of text +class CardSettingsInstructions extends StatelessWidget + implements CardSettingsWidget { + CardSettingsInstructions({ + this.text: 'Instructions here...', + this.backgroundColor, + this.textColor, + this.showMaterialonIOS, + this.visible = true, + this.fieldPadding, + }); + + /// The text for the instructions + final String text; + + /// the color for the background + final Color backgroundColor; + + /// The color of the text + final Color textColor; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// padding to place around then entire field + final EdgeInsetsGeometry fieldPadding; + + @override + Widget build(BuildContext context) { + if (!visible) return Container(); + + TextStyle textStyle = Theme.of(context) + .primaryTextTheme + .caption + .copyWith(color: textColor ?? Theme.of(context).accentColor); + if (showCupertino(context, showMaterialonIOS)) { + return Container( + padding: EdgeInsets.only(top: 8.0, left: 8.0), + child: Text( + text, + style: TextStyle(color: CupertinoColors.inactiveGray), + ), + // color: CupertinoColors.lightBackgroundGray, + ); + } else + return _materialInstruction(context, textStyle); + } + + Widget _materialInstruction(BuildContext context, TextStyle textStyle) { + EdgeInsetsGeometry _fieldPadding = (fieldPadding ?? + CardSettings.of(context).fieldPadding ?? + EdgeInsets.all(14.0)); + + return Container( + margin: EdgeInsets.all(0.0), + decoration: + BoxDecoration(color: backgroundColor ?? Theme.of(context).cardColor), + padding: _fieldPadding, + child: Row( + children: [ + Text( + text, + style: textStyle, + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_currency.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_currency.dart new file mode 100644 index 00000000..2b3d8db0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_currency.dart @@ -0,0 +1,228 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:extended_masked_text/extended_masked_text.dart'; +import 'package:intl/intl.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a currency field. +class CardSettingsCurrency extends StatefulWidget + implements ICommonFieldProperties { + CardSettingsCurrency({ + Key key, + this.label: 'Label', + this.labelAlign, + this.labelWidth, + this.contentAlign, + this.initialValue: 0.0, + this.icon, + this.requiredIndicator, + this.currencySymbol: '\$', + this.currencyName: 'USD', + this.decimalSeparator: '.', + this.thousandSeparator: ',', + this.maxLength: 16, + this.visible: true, + this.enabled: true, + this.autofocus: false, + this.obscureText: false, + this.autovalidateMode: AutovalidateMode.onUserInteraction, + this.validator, + this.onSaved, + this.onChanged, + this.controller, + this.focusNode, + this.inputAction, + this.inputActionNode, + this.keyboardType, + this.style, + this.maxLengthEnforcement: MaxLengthEnforcement.enforced, + this.onFieldSubmitted, + this.inputFormatters, + this.showMaterialonIOS, + this.fieldPadding, + this.locale, + }); + + /// The text to identify the field to the user + @override + final String label; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// The initial value to display + final double initialValue; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// The symbol to use for the currency + final String currencySymbol; + + /// the name of the currency. E.g. USD + final String currencyName; + + /// the character to use for decimal separation + final String decimalSeparator; + + /// the character to use for the thousands place. + final String thousandSeparator; + + /// The maxinum length of the value in characters + final int maxLength; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// If false, grays out the field and makes it unresponsive + final bool enabled; + + final bool autofocus; + + final bool obscureText; + + @override + final AutovalidateMode autovalidateMode; + + @override + final FormFieldValidator validator; + + @override + final FormFieldSetter onSaved; + + @override + final ValueChanged onChanged; + + final TextEditingController controller; + + final FocusNode focusNode; + + final TextInputAction inputAction; + + final FocusNode inputActionNode; + + final TextInputType keyboardType; + + final TextStyle style; + + final MaxLengthEnforcement maxLengthEnforcement; + + final ValueChanged onFieldSubmitted; + + final List inputFormatters; + + final Locale locale; + + // Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + // provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsCurrencyState createState() { + return _CardSettingsCurrencyState(); + } +} + +class _CardSettingsCurrencyState extends State { + MoneyMaskedTextController _moneyController; + + @override + void initState() { + super.initState(); + if (widget.controller == null) { + _moneyController = MoneyMaskedTextController( + decimalSeparator: widget.decimalSeparator, + thousandSeparator: widget.thousandSeparator); + _moneyController.updateValue(widget.initialValue); + } + } + + @override + Widget build(BuildContext context) { + Locale myLocale = widget.locale ?? Localizations.localeOf(context); + + var pattern = "#,###.##"; + + var formatter = NumberFormat(pattern, myLocale.languageCode); + + return CardSettingsText( + showMaterialonIOS: widget.showMaterialonIOS, + fieldPadding: widget.fieldPadding, + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + contentAlign: widget.contentAlign, + initialValue: widget.initialValue.toString(), + unitLabel: widget.currencyName, + prefixText: widget.currencySymbol, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + maxLength: widget.maxLength, + visible: widget.visible, + enabled: widget.enabled, + autofocus: widget.autofocus, + obscureText: widget.obscureText, + autovalidateMode: widget.autovalidateMode, + validator: (val) => _safeValidator(val, formatter), + onSaved: (val) => _safeOnSaved(val, formatter), + onChanged: (val) => _safeOnChanged(val, formatter), + controller: widget.controller ?? _moneyController, + focusNode: widget.focusNode, + inputAction: widget.inputAction, + inputActionNode: widget.inputActionNode, + keyboardType: widget.keyboardType ?? + TextInputType.numberWithOptions(decimal: false), + style: widget.style, + maxLengthEnforcement: widget.maxLengthEnforcement, + onFieldSubmitted: widget.onFieldSubmitted, + inputFormatters: widget.inputFormatters, + ); + } + + String _safeValidator(String value, NumberFormat formatter) { + if (widget.validator == null) return null; + num number = (value == "") ? null : formatter.parse(value); + return widget.validator(intelligentCast(number)); + } + + void _safeOnSaved(String value, NumberFormat formatter) { + if (widget.onSaved == null) return; + num number = (value == "") ? null : formatter.parse(value); + widget.onSaved(intelligentCast(number)); + } + + void _safeOnChanged(String value, NumberFormat formatter) { + if (widget.onChanged == null) return; + + if (_moneyController != null) { + widget.onChanged(_moneyController.numberValue); + } else { + num number = (value == "") ? null : formatter.parse(value); + widget.onChanged(intelligentCast(number)); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_double.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_double.dart new file mode 100644 index 00000000..92157059 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_double.dart @@ -0,0 +1,233 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; +import 'package:pattern_formatter/pattern_formatter.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +import '../../interfaces/text_field_properties.dart'; + +/// This is a phone number field. It's designed for US numbers +class CardSettingsDouble extends StatelessWidget + implements ICommonFieldProperties, ITextFieldProperties { + CardSettingsDouble({ + Key key, + this.label: 'Label', + this.labelWidth, + this.labelAlign, + this.hintText, + this.prefixText, + this.contentAlign, + this.initialValue, + this.contentOnNewLine = false, + this.maxLength = 10, + this.decimalDigits = 2, + this.icon, + this.requiredIndicator, + this.unitLabel, + this.visible: true, + this.enabled: true, + this.autofocus: false, + this.obscureText: false, + this.autovalidateMode: AutovalidateMode.onUserInteraction, + this.validator, + this.onSaved, + this.onChanged, + this.controller, + this.focusNode, + this.inputAction, + this.inputActionNode, + this.keyboardType, + this.style, + this.maxLengthEnforcement: MaxLengthEnforcement.enforced, + this.onFieldSubmitted, + this.inputFormatters, + this.showMaterialonIOS, + this.locale, + this.fieldPadding, + }); + + /// The text to identify the field to the user + @override + final String label; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + @override + + /// text to display to guide the user on what to enter + final String hintText; + + /// Text to show before the content area + final String prefixText; + + /// The initial value of the content + final double initialValue; + + /// Put the content below the label + final bool contentOnNewLine; + + /// number of digits for the value + final int maxLength; + + /// if provided, show text after the value + final String unitLabel; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// If false, grays out the field and makes it unresponsive + final bool enabled; + + /// Allows flutter to advance to this field + final bool autofocus; + + final bool obscureText; + + /// used to configure the autovalidation of this field + @override + final AutovalidateMode autovalidateMode; + + /// The function to call to validate the content + @override + final FormFieldValidator validator; + + /// This fires when the form is saved + @override + final FormFieldSetter onSaved; + + /// This fires when the value is changed + @override + final ValueChanged onChanged; + + /// You can provide a custom text controller here + final TextEditingController controller; + + /// the order for this node to receive focus + final FocusNode focusNode; + + final FocusNode inputActionNode; + + /// the type of keyboard to show + final TextInputType keyboardType; + + /// The style for the label + final TextStyle style; + + final TextInputAction inputAction; + + /// the max length of the number in characters + final MaxLengthEnforcement maxLengthEnforcement; + + /// the number of digits allowed after the decimal + final int decimalDigits; + + /// This fires when the form is submitted + final ValueChanged onFieldSubmitted; + + /// input formatters to enforce entry + final List inputFormatters; + + /// the localization region to use + final Locale locale; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + Widget build(BuildContext context) { + var myLocale = locale ?? Localizations.localeOf(context); + + var pattern = "#,###" + + ((decimalDigits > 0) ? ".".padRight(decimalDigits + 1, "#") : ""); + + var formatter = NumberFormat(pattern, myLocale.languageCode); + + String initialText = + (initialValue == null) ? null : formatter.format(initialValue); + + return CardSettingsText( + key: key, + label: label, + hintText: hintText, + showMaterialonIOS: showMaterialonIOS, + fieldPadding: fieldPadding, + labelAlign: labelAlign, + labelWidth: labelWidth, + contentAlign: contentAlign, + initialValue: initialText, + unitLabel: unitLabel, + icon: icon, + requiredIndicator: requiredIndicator, + maxLength: maxLength, + visible: visible, + enabled: enabled, + autofocus: autofocus, + obscureText: obscureText, + autovalidateMode: autovalidateMode, + validator: (val) => _safeValidator(val, formatter), + onSaved: (val) => _safeOnSaved(val, formatter), + onChanged: (val) => _safeOnChanged(val, formatter), + controller: controller, + focusNode: focusNode, + inputAction: inputAction, + inputActionNode: inputActionNode, + keyboardType: + keyboardType ?? TextInputType.numberWithOptions(decimal: true), + style: style, + maxLengthEnforcement: maxLengthEnforcement, + onFieldSubmitted: onFieldSubmitted, + inputFormatters: [ + ThousandsFormatter( + formatter: formatter, allowFraction: (decimalDigits > 0)), + LengthLimitingTextInputFormatter(maxLength), + ], + ); + } + + String _safeValidator(String value, NumberFormat formatter) { + if (validator == null) return null; + num number = (value == "") ? null : formatter.parse(value); + return validator(intelligentCast(number)); + } + + void _safeOnSaved(String value, NumberFormat formatter) { + if (onSaved == null) return; + num number = (value == "") ? null : formatter.parse(value); + onSaved(intelligentCast(number)); + } + + void _safeOnChanged(String value, NumberFormat formatter) { + if (onChanged == null) return; + num number = (value == "") ? null : formatter.parse(value); + onChanged(intelligentCast(number)); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_int.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_int.dart new file mode 100644 index 00000000..4f61662a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_int.dart @@ -0,0 +1,91 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a password field. It obscures the entered text. +class CardSettingsInt extends CardSettingsText + implements ICommonFieldProperties { + CardSettingsInt({ + Key key, + String label: 'Label', + TextAlign labelAlign, + double labelWidth, + TextAlign contentAlign, + String hintText, + int initialValue: 0, + Icon icon, + Widget requiredIndicator, + String unitLabel, + int maxLength: 10, + bool visible: true, + bool enabled: true, + bool autofocus: false, + bool obscureText: false, + bool autocorrect: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldValidator validator, + FormFieldSetter onSaved, + ValueChanged onChanged, + TextEditingController controller, + FocusNode focusNode, + TextInputAction inputAction, + FocusNode inputActionNode, + TextInputType keyboardType, + TextStyle style, + MaxLengthEnforcement maxLengthEnforcement: MaxLengthEnforcement.enforced, + ValueChanged onFieldSubmitted, + List inputFormatters, + bool showMaterialonIOS, + EdgeInsetsGeometry fieldPadding, + }) : super( + key: key, + label: label, + hintText: hintText, + labelAlign: labelAlign, + labelWidth: labelWidth, + showMaterialonIOS: showMaterialonIOS, + contentAlign: contentAlign, + initialValue: initialValue.toString(), + unitLabel: unitLabel, + icon: icon, + requiredIndicator: requiredIndicator, + maxLength: maxLength, + visible: visible, + enabled: enabled, + autofocus: autofocus, + obscureText: obscureText, + autocorrect: autocorrect, + autovalidateMode: autovalidateMode, + fieldPadding: fieldPadding, + validator: (value) { + if (validator == null) return null; + return validator(intelligentCast(value)); + }, + onSaved: (value) { + if (onSaved == null) return; + onSaved(intelligentCast(value)); + }, + onChanged: (value) { + if (onChanged == null) return; + onChanged(intelligentCast(value)); + }, + controller: controller, + focusNode: focusNode, + inputAction: inputAction, + inputActionNode: inputActionNode, + keyboardType: + keyboardType ?? TextInputType.numberWithOptions(decimal: false), + style: style, + maxLengthEnforcement: maxLengthEnforcement, + onFieldSubmitted: onFieldSubmitted, + inputFormatters: [ + LengthLimitingTextInputFormatter(maxLength), + FilteringTextInputFormatter.allow(RegExp("[0-9]+")), + ], + ); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_slider.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_slider.dart new file mode 100644 index 00000000..735c672c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_slider.dart @@ -0,0 +1,222 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a field that allows a boolean to be set via a switch widget. +class CardSettingsSlider extends FormField + implements ICommonFieldProperties { + CardSettingsSlider({ + Key key, + bool autovalidate: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldSetter onSaved, + FormFieldValidator validator, + double initialValue = 0.0, + this.enabled = true, + this.visible = true, + this.label = 'Label', + this.requiredIndicator, + this.labelAlign, + this.labelWidth, + this.icon, + this.contentAlign, + this.onChanged, + this.onChangedStart, + this.onChangedEnd, + this.min, + this.max, + this.divisions, + this.showMaterialonIOS, + this.fieldPadding, + }) : super( + key: key, + initialValue: initialValue, + onSaved: onSaved, + validator: validator, + // autovalidate: autovalidate, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsSliderState)._build(field.context)); + + /// The text to identify the field to the user + @override + final String label; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + @override + final ValueChanged onChanged; + + final ValueChanged onChangedEnd; + + final ValueChanged onChangedStart; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + /// how many divisions to have between min and max + final int divisions; + + /// The value at the minimum position + final double min; + + /// The value at the maximum position + final double max; + + @override + _CardSettingsSliderState createState() => _CardSettingsSliderState(); +} + +class _CardSettingsSliderState extends FormFieldState { + @override + CardSettingsSlider get widget => super.widget as CardSettingsSlider; + + Widget _build(BuildContext context) { + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsSlider(); + else + return _materialSettingsSlider(); + } + + Widget _cupertinoSettingsSlider() { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: CupertinoSlider( + value: value, + divisions: widget.divisions, + min: widget.min ?? 0, + max: widget.max ?? 1, + onChangeEnd: widget.onChangedEnd, + onChangeStart: widget.onChangedStart, + onChanged: (widget.enabled) + ? (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + } + : null, // to disable, we need to not provide an onChanged function + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ); + } + + Widget _materialSettingsSlider() { + return CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + visible: widget.visible, + enabled: widget.enabled, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Row(children: [ + Expanded( + child: Container( + padding: EdgeInsets.all(0.0), + child: Container( + height: 20.0, + child: SliderTheme( + data: SliderThemeData( + trackShape: _CustomTrackShape(), + ), + child: Slider( + activeColor: Theme.of(context).primaryColor, + value: value, + divisions: widget.divisions, + min: widget.min ?? 0, + max: widget.max ?? 1, + onChangeEnd: widget.onChangedEnd, + onChangeStart: widget.onChangedStart, + onChanged: (widget.enabled) + ? (value) { + didChange(value); + if (widget.onChanged != null) + widget.onChanged(value); + } + : null, // to disable, we need to not provide an onChanged function + ), + ), + ), + ), + ), + ]), + ); + } +} + +// https://github.com/flutter/flutter/issues/37057 +class _CustomTrackShape extends RoundedRectSliderTrackShape { + @override + Rect getPreferredRect({ + @required RenderBox parentBox, + Offset offset = Offset.zero, + @required SliderThemeData sliderTheme, + bool isEnabled = false, + bool isDiscrete = false, + }) { + final double trackHeight = sliderTheme.trackHeight ?? 10; + final double trackLeft = offset.dx; + final double trackTop = + offset.dy + (parentBox.size.height - trackHeight) / 2; + final double trackWidth = parentBox.size.width; + return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_switch.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_switch.dart new file mode 100644 index 00000000..e55a7638 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/numeric_fields/card_settings_switch.dart @@ -0,0 +1,180 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a field that allows a boolean to be set via a switch widget. +class CardSettingsSwitch extends FormField + implements ICommonFieldProperties { + CardSettingsSwitch({ + Key key, + // bool autovalidate: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldSetter onSaved, + FormFieldValidator validator, + bool initialValue = false, + this.enabled = true, + this.trueLabel = "Yes", + this.falseLabel = "No", + this.visible = true, + this.label = 'Label', + this.labelWidth, + this.requiredIndicator, + this.labelAlign, + this.icon, + this.contentAlign, + this.onChanged, + this.showMaterialonIOS, + this.fieldPadding, + }) : super( + key: key, + initialValue: initialValue, + onSaved: onSaved, + validator: validator, + // autovalidate: autovalidate, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsSwitchState)._build(field.context)); + + /// The text to identify the field to the user + @override + final String label; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// The text to show if the switch is "on" + final String trueLabel; + + /// The text to show if the switch if "off" + final String falseLabel; + + /// Fires when the switch state is changed + @override + final ValueChanged onChanged; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsSwitchState createState() => _CardSettingsSwitchState(); +} + +class _CardSettingsSwitchState extends FormFieldState { + @override + CardSettingsSwitch get widget => super.widget as CardSettingsSwitch; + + Widget _build(BuildContext context) { + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsSwitch(); + return _materialSettingsSwitch(); + } + + Widget _materialSettingsSwitch() { + return CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + enabled: widget.enabled, + visible: widget.visible, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Row(children: [ + Expanded( + child: Text( + value ? widget.trueLabel : widget.falseLabel, + style: contentStyle(context, value, widget.enabled), + textAlign: + widget.contentAlign ?? CardSettings.of(context).contentAlign, + ), + ), + Container( + padding: EdgeInsets.all(0.0), + height: 20.0, + child: Switch( + value: value, + onChanged: (widget.enabled) + ? (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + } + : null, // to disable, we need to not provide an onChanged function + ), + ), + ]), + ); + } + + Widget _cupertinoSettingsSwitch() { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: CupertinoSwitch( + value: value, + onChanged: (widget.enabled) + ? (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + } + : null, // to disable, we need to not provide an onChanged function + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_checkbox_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_checkbox_picker.dart new file mode 100644 index 00000000..5c9ca8fc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_checkbox_picker.dart @@ -0,0 +1,305 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter_material_pickers/flutter_material_pickers.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a selection widget that allows an arbitrary list of options to be provided. +class CardSettingsCheckboxPicker extends FormField> + implements ICommonFieldProperties { + CardSettingsCheckboxPicker({ + Key key, + List initialItems, + FormFieldSetter> onSaved, + FormFieldValidator> validator, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + this.enabled = true, + this.onChanged, + this.label = 'Select', + this.visible = true, + this.contentAlign, + this.icon, + this.labelAlign, + this.labelWidth, + this.requiredIndicator, + @required this.items, + this.showMaterialonIOS, + this.fieldPadding, + }) : super( + key: key, + initialValue: initialItems, + onSaved: onSaved, + validator: validator, + autovalidateMode: autovalidateMode, + builder: (FormFieldState> field) => + (field as _CardSettingsCheckboxPickerState)._build(field.context), + ); + + /// The text to identify the field to the user + @override + final String label; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// a list of items to display in the picker + final List items; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Fires when the picked values are changed + @override + final ValueChanged> onChanged; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsCheckboxPickerState createState() => + _CardSettingsCheckboxPickerState(); +} + +class _CardSettingsCheckboxPickerState extends FormFieldState> { + @override + CardSettingsCheckboxPicker get widget => + super.widget as CardSettingsCheckboxPicker; + + List items = List.empty(); + + void _showDialog(String label) { + if (showCupertino(context, widget.showMaterialonIOS)) + _showCupertinoSelectPicker(label); + else + _showMaterialCheckboxPicker(label); + } + + void _showMaterialCheckboxPicker(String label) { + showMaterialCheckboxPicker( + context: context, + title: label, + items: items, + selectedItems: value, + onChanged: (List selectedItems) { + if (selectedItems != null) { + didChange(selectedItems); + if (widget.onChanged != null) widget.onChanged(selectedItems); + } + }, + ); + } + + void _showCupertinoSelectPicker(String label) { + Navigator.push>( + context, + MaterialPageRoute( + builder: (context) => _CupertinoSelect( + initialItems: value, + items: items, + label: label, + ), + fullscreenDialog: true, + ), + ).then((selectedValues) { + if (selectedValues != null) { + didChange(selectedValues); + if (widget.onChanged != null) widget.onChanged(selectedValues); + } + }); + } + + Widget _build(BuildContext context) { + // make local mutable copies of values and options + items = widget.items; + + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsMultiselect(); + else + return _materialSettingsMultiselect(); + } + + Widget _cupertinoSettingsMultiselect() { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(widget.label); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: Text( + value == null || value.isEmpty + ? "none selected" + : value.length == 1 + ? "${value[0]}" + : "${value[0]} & ${value.length - 1} more", + style: contentStyle(context, value, widget.enabled), + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _materialSettingsMultiselect() { + return GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(widget.label); + }, + child: CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + enabled: widget.enabled, + visible: widget.visible, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + contentOnNewLine: true, + fieldPadding: widget.fieldPadding, + content: Wrap( + alignment: WrapAlignment.start, + spacing: 4.0, + runSpacing: 0.0, + children: value + .map( + (s) => Chip( + label: Text(s.toString(), + style: contentStyle(context, value, widget.enabled))), + ) + .toList(), + ), + pickerIcon: (widget.enabled) ? Icons.arrow_drop_down : null, + ), + ); + } +} + +class _CupertinoSelect extends StatefulWidget { + _CupertinoSelect({ + @required this.label, + this.initialItems, + @required this.items, + }); + + final List initialItems; + final List items; + final String label; + + @override + _CupertinoSelectState createState() => _CupertinoSelectState(); +} + +class _CupertinoSelectState extends State<_CupertinoSelect> { + List _selected = []; + + @override + void initState() { + _selected = widget.initialItems ?? []; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return DefaultTextStyle( + style: const TextStyle( + fontFamily: '.SF UI Text', + inherit: false, + fontSize: 17.0, + color: CupertinoColors.black, + ), + child: Scaffold( + appBar: CupertinoNavigationBar( + // We're specifying a back label here because the previous page is a + // Material page. CupertinoPageRoutes could auto-populate these back + // labels. + previousPageTitle: 'Cupertino', + middle: Text('Select ' + widget.label), + trailing: GestureDetector( + child: Text( + 'Save', + style: TextStyle( + color: CupertinoColors.activeBlue, + fontWeight: FontWeight.bold, + ), + ), + onTap: () { + Navigator.of(context, rootNavigator: true).pop(_selected); + }, + ), + ), + body: ListView.builder( + itemCount: widget.items.length, + itemBuilder: (BuildContext context, int index) { + T i = widget.items[index]; + final bool select = _selected.contains(i); + return ListTile( + leading: select + ? const Icon(CupertinoIcons.check_mark) + : Icon(Icons.info, color: Colors.transparent), + title: Text(i.toString()), + onTap: () { + setState(() { + if (select) { + _selected.remove(i); + } else { + _selected.add(i); + } + }); + }, + ); + }, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_color_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_color_picker.dart new file mode 100644 index 00000000..228eecea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_color_picker.dart @@ -0,0 +1,231 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_material_pickers/flutter_material_pickers.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This allows selection of which variant of the color picker you would like to use +enum CardSettingsColorPickerType { colors, material, block } + +/// This is the color picker field +class CardSettingsColorPicker extends FormField + implements ICommonFieldProperties { + CardSettingsColorPicker({ + Key key, + // bool autovalidate: false, + FormFieldSetter onSaved, + FormFieldValidator validator, + Color initialValue = Colors.green, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + this.enabled = true, + this.onChanged, + this.visible = true, + this.contentAlign, + this.icon, + this.labelAlign, + this.labelWidth, + this.pickerType = CardSettingsColorPickerType.colors, + this.requiredIndicator, + this.label = "Label", + this.showMaterialonIOS, + this.fieldPadding, + }) : super( + key: key, + initialValue: initialValue, + onSaved: onSaved, + validator: validator, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsColorPickerState)._build(field.context)); + + /// Fires when the color value changes + @override + final ValueChanged onChanged; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + // here for consistency, but does nothing. + @override + final TextAlign contentAlign; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// The text to identify the field to the user + @override + final String label; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + /// the specific variant of the color picker to use + final CardSettingsColorPickerType pickerType; + + @override + _CardSettingsColorPickerState createState() => + _CardSettingsColorPickerState(); +} + +class _CardSettingsColorPickerState extends FormFieldState { + @override + CardSettingsColorPicker get widget => super.widget as CardSettingsColorPicker; + + Color pickerColor = Colors.green; + + void _showDialog() { + pickerColor = value; + + var title = widget.label; + + var cupertinoColors = showCupertino(context, widget.showMaterialonIOS); + var headerColor = (cupertinoColors) ? Colors.white : null; + var textColor = (cupertinoColors) ? Colors.black : null; + + switch (widget.pickerType) { + case CardSettingsColorPickerType.colors: + showMaterialColorPicker( + context: context, + title: title, + headerColor: headerColor, + buttonTextColor: textColor, + headerTextColor: textColor, + selectedColor: pickerColor, + onChanged: (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + }, + ); + break; + case CardSettingsColorPickerType.material: + showMaterialPalettePicker( + context: context, + title: title, + headerColor: headerColor, + buttonTextColor: textColor, + headerTextColor: textColor, + selectedColor: pickerColor, + onChanged: (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + }, + ); + break; + case CardSettingsColorPickerType.block: + showMaterialSwatchPicker( + context: context, + title: title, + headerColor: headerColor, + headerTextColor: textColor, + buttonTextColor: textColor, + selectedColor: pickerColor, + onChanged: (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + }, + ); + break; + } + } + + Widget _build(BuildContext context) { + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsColorPicker(); + else + return _materialSettingsColorPicker(); + } + + Widget _cupertinoSettingsColorPicker() { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: Container( + height: 20.0, + width: 100.0, + decoration: BoxDecoration( + color: value, + borderRadius: BorderRadius.circular(8.0), + ), + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _materialSettingsColorPicker() { + return GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(); + }, + child: CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + enabled: widget.enabled, + visible: widget.visible, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Container( + height: 20.0, + decoration: BoxDecoration( + color: value, + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_date_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_date_picker.dart new file mode 100644 index 00000000..122fbbb1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_date_picker.dart @@ -0,0 +1,263 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:intl/intl.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is the date picker field +class CardSettingsDatePicker extends FormField + implements ICommonFieldProperties { + CardSettingsDatePicker({ + Key key, + // bool autovalidate: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldSetter onSaved, + FormFieldValidator validator, + DateTime initialValue, + this.enabled = true, + this.visible = true, + this.label = 'Date', + this.onChanged, + this.contentAlign, + this.icon, + this.labelAlign, + this.labelWidth, + this.requiredIndicator, + this.firstDate, + this.lastDate, + this.dateFormat, + this.style, + this.showMaterialonIOS, + this.fieldPadding, + }) : super( + key: key, + initialValue: initialValue ?? DateTime.now(), + onSaved: onSaved, + validator: validator, + // autovalidate: autovalidate, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsDatePickerState)._build(field.context)); + + /// fires when the picker value changes + @override + final ValueChanged onChanged; + + /// The text to identify the field to the user + @override + final String label; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// the first date in the selectable picker range + final DateTime firstDate; + + /// the last date in the selectable picker range + final DateTime lastDate; + + /// the format to show the date in the field + final DateFormat dateFormat; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// The label style + final TextStyle style; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsDatePickerState createState() => _CardSettingsDatePickerState(); +} + +class _CardSettingsDatePickerState extends FormFieldState { + @override + CardSettingsDatePicker get widget => super.widget as CardSettingsDatePicker; + + void _showDialog() { + DateTime _startDate = widget.firstDate ?? DateTime.now(); + if ((value ?? DateTime.now()).isBefore(_startDate)) { + _startDate = value; + } + final _endDate = widget.lastDate ?? _startDate.add(Duration(days: 1800)); + + if (showCupertino(context, widget.showMaterialonIOS)) + showCupertinoDatePicker(_startDate, _endDate); + else + showMaterialDatePicker(_startDate, _endDate); + } + + void showCupertinoDatePicker(DateTime _startDate, DateTime _endDate) { + showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return _buildBottomPicker( + CupertinoDatePicker( + minimumDate: _startDate, + minimumYear: _startDate.year, + maximumDate: _endDate, + maximumYear: _endDate.year, + mode: CupertinoDatePickerMode.date, + initialDateTime: value ?? DateTime.now(), + onDateTimeChanged: (DateTime newDateTime) { + didChange(newDateTime); + if (widget.onChanged != null) widget.onChanged(newDateTime); + }, + ), + ); + }, + ).then((_value) { + if (_value != null) { + didChange(_value); + if (widget.onChanged != null) widget.onChanged(_value); + } + }); + } + + void showMaterialDatePicker(DateTime _startDate, DateTime _endDate) { + showDatePicker( + context: context, + initialDate: value ?? DateTime.now(), + firstDate: _startDate, + lastDate: _endDate, + ).then((_value) { + if (_value != null) { + didChange(_value); + if (widget.onChanged != null) widget.onChanged(_value); + } + }); + } + + Widget _build(BuildContext context) { + String formattedValue = (value == null) + ? '' + : (widget.dateFormat == null) + ? DateFormat.yMd().format(value) + : widget.dateFormat.format(value); + + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsDatePicker(formattedValue); + else + return _materialSettingsDatePicker(formattedValue); + } + + Widget _buildBottomPicker(Widget picker) { + return Container( + height: kCupertinoPickerSheetHeight, + padding: const EdgeInsets.only(top: 6.0), + color: CupertinoColors.white, + child: DefaultTextStyle( + style: const TextStyle( + color: CupertinoColors.black, + fontSize: 22.0, + ), + child: GestureDetector( + // Blocks taps from propagating to the modal sheet and popping. + onTap: () {}, + child: SafeArea( + top: false, + child: picker, + ), + ), + ), + ); + } + + Widget _cupertinoSettingsDatePicker(String formattedValue) { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: Text( + formattedValue, + style: contentStyle(context, value, widget.enabled), + textAlign: widget.contentAlign ?? + CardSettings.of(context).contentAlign, + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _materialSettingsDatePicker(String formattedValue) { + return GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(); + }, + child: CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + enabled: widget.enabled, + visible: widget.visible, + icon: widget.icon ?? Icon(Icons.event), + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Text( + formattedValue, + style: contentStyle(context, value, widget.enabled), + textAlign: + widget.contentAlign ?? CardSettings.of(context).contentAlign, + ), + pickerIcon: (widget.enabled) ? Icons.arrow_drop_down : null, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_datetime_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_datetime_picker.dart new file mode 100644 index 00000000..d5aec75c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_datetime_picker.dart @@ -0,0 +1,294 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:intl/intl.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is the date picker field +class CardSettingsDateTimePicker extends FormField + implements ICommonFieldProperties { + CardSettingsDateTimePicker({ + Key key, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldSetter onSaved, + FormFieldValidator validator, + DateTime initialValue, + this.enabled = true, + this.visible = true, + this.label = "Date Time", + this.onChanged, + this.contentAlign, + this.icon, + this.labelAlign, + this.labelWidth, + this.requiredIndicator, + this.firstDate, + this.lastDate, + this.style, + this.showMaterialonIOS, + this.fieldPadding, + this.dateBuilder, + this.timeBuilder, + }) : super( + key: key, + initialValue: initialValue ?? DateTime.now(), + onSaved: onSaved, + validator: validator, + // autovalidate: autovalidate, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsDateTimePickerState) + ._build(field.context)); + + /// fires when the picker value is changed + @override + final ValueChanged onChanged; + + /// The text to identify the field to the user + @override + final String label; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// the first date in the selectable picker range + final DateTime firstDate; + + /// the last date in the selectable picker range + final DateTime lastDate; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// the style of the label text + final TextStyle style; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + final Widget Function(BuildContext, Widget) dateBuilder; + + final Widget Function(BuildContext, Widget) timeBuilder; + + @override + _CardSettingsDateTimePickerState createState() => + _CardSettingsDateTimePickerState(); +} + +class _CardSettingsDateTimePickerState extends FormFieldState { + @override + CardSettingsDateTimePicker get widget => + super.widget as CardSettingsDateTimePicker; + + void _showDialog() { + DateTime _startDate = widget.firstDate ?? DateTime.now(); + if ((value ?? DateTime.now()).isBefore(_startDate)) { + _startDate = value; + } + final _endDate = widget.lastDate ?? _startDate.add(Duration(days: 1800)); + + // Using platform on web will result on a crash, + if (showCupertino(context, widget.showMaterialonIOS)) + _showCupertinoDateTimePopUp(_startDate, _endDate); + else + _showMaterialDateTimePopUp(_startDate, _endDate); + } + + Future _showCupertinoDateTimePopUp( + DateTime _startDate, DateTime _endDate) { + return showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return _buildCupertinoBottomPicker( + CupertinoDatePicker( + minimumDate: _startDate, + minimumYear: _startDate.year, + maximumDate: _endDate, + maximumYear: _endDate.year, + mode: CupertinoDatePickerMode.dateAndTime, + initialDateTime: value ?? DateTime.now(), + onDateTimeChanged: (DateTime newDateTime) { + didChange(newDateTime); + if (widget.onChanged != null) widget.onChanged(newDateTime); + }, + ), + ); + }, + ).then((_value) { + if (_value != null) { + didChange(_value); + if (widget.onChanged != null) widget.onChanged(_value); + } + }); + } + + void _showMaterialDateTimePopUp(DateTime _startDate, DateTime _endDate) { + showDatePicker( + context: context, + initialDate: value ?? DateTime.now(), + firstDate: _startDate, + lastDate: _endDate, + builder: (BuildContext context, Widget child) { + return Theme( + data: Theme.of(context), + child: child, + ); + }).then((_date) async { + if (_date != null) { + await showTimePicker( + context: context, + initialTime: value != null + ? TimeOfDay(hour: value.hour, minute: value.minute) + : TimeOfDay.now(), + builder: (BuildContext context, Widget child) { + // return timeBuilder ?? + return Theme( + data: Theme.of(context), + child: child, + ); + }).then((_time) { + if (_time != null) + _date = DateTime(_date.year, _date.month, _date.day, _time.hour, + _time.minute); + }); + } + if (_date != null) { + didChange(_date); + if (widget.onChanged != null) widget.onChanged(_date); + } + }); + } + + Widget _build(BuildContext context) { + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsButton(); + else + return _materialSettingsButton(); + } + + Widget _buildCupertinoBottomPicker(Widget picker) { + return Container( + height: kCupertinoPickerSheetHeight, + padding: const EdgeInsets.only(top: 6.0), + color: CupertinoColors.white, + child: DefaultTextStyle( + style: const TextStyle( + color: CupertinoColors.black, + fontSize: 22.0, + ), + child: GestureDetector( + // Blocks taps from propagating to the modal sheet and popping. + onTap: () {}, + child: SafeArea( + top: false, + child: picker, + ), + ), + ), + ); + } + + Widget _cupertinoSettingsButton() { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: Flexible( + child: Text( + value == null + ? '' + : DateFormat.yMd().add_jm().format(value), + style: contentStyle(context, value, widget.enabled), + overflow: TextOverflow.ellipsis, + textAlign: widget.contentAlign ?? + CardSettings.of(context).contentAlign, + ), + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _materialSettingsButton() { + return GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(); + }, + child: CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + visible: widget.visible, + enabled: widget.enabled, + icon: widget.icon ?? Icon(Icons.event), + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Text( + value == null ? '' : DateFormat.yMd().add_jm().format(value), + style: contentStyle(context, value, widget.enabled), + overflow: TextOverflow.ellipsis, + textAlign: + widget.contentAlign ?? CardSettings.of(context).contentAlign, + ), + pickerIcon: (widget.enabled) ? Icons.arrow_drop_down : null, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_file_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_file_picker.dart new file mode 100644 index 00000000..8e07b6ac --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_file_picker.dart @@ -0,0 +1,311 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_material_pickers/flutter_material_pickers.dart'; + +import '../../interfaces/common_field_properties.dart'; +import '../card_settings_field.dart'; +import '../card_settings_panel.dart'; + +/// This is the file picker field +class CardSettingsFilePicker extends FormField + implements ICommonFieldProperties { + CardSettingsFilePicker({ + Key key, + // bool autovalidate: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldSetter onSaved, + FormFieldValidator validator, + Uint8List initialValue, + this.visible = true, + this.label = 'File', + this.enabled = true, + String unattachDialogTitle, + this.unattachDialogCancel = 'Cancel', + this.unattachDialogConfirm = 'Unattach', + this.onChanged, + this.contentAlign, + this.maxThumbnailWidth = 180, + this.maxThumbnailHeight = 180, + this.icon, + this.labelAlign, + this.labelWidth, + this.requiredIndicator, + this.style, + this.showMaterialonIOS, + this.fieldPadding, + this.fileType, + this.allowedExtensions, + }) : unattachDialogTitle = unattachDialogTitle ?? 'Unattach ' + label + "?", + super( + key: key, + initialValue: initialValue, + onSaved: onSaved, + validator: validator, + // autovalidate: autovalidate, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsFilePickerState)._build(field.context)); + + /// fires when the picker data is changed + @override + final ValueChanged onChanged; + + /// The text to identify the field to the user + @override + final String label; + + /// The title of the dialog when a file is unattached + final String unattachDialogTitle; + + /// The confirm label of the dialog when a file is unattached + final String unattachDialogConfirm; + + /// The cancel label of the dialog when a file is unattached + final String unattachDialogCancel; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// a restriction on the width growth of the thumbnail + final double maxThumbnailWidth; + + /// a restriction on the height growth of the thumbnail + final double maxThumbnailHeight; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// the style of the label text + final TextStyle style; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// the type of the files allowed + final FileType fileType; + + /// a list of allowed file extensions + final List allowedExtensions; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsFilePickerState createState() => _CardSettingsFilePickerState(); + + static String formatBytes(int bytes, int decimals) { + if (bytes <= 0) return "0 B"; + const suffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + var i = (log(bytes) / log(1024)).floor(); + return ((bytes / pow(1024, i)).toStringAsFixed(decimals)) + + ' ' + + suffixes[i]; + } +} + +class _CardSettingsFilePickerState extends FormFieldState { + @override + CardSettingsFilePicker get widget => super.widget as CardSettingsFilePicker; + + Widget _build(BuildContext context) { + String formattedValue = (value == null) + ? '' + : CardSettingsFilePicker.formatBytes(value.length, 2); + + if (showCupertino(context, widget.showMaterialonIOS)) + return _buildCupertinoFilePicker(formattedValue); + else + return _buildMaterialFilePicker(formattedValue); + } + + void onTap() { + if (value == null) { + showMaterialFilePicker( + fileType: widget.fileType ?? FileType.any, + allowedExtensions: widget.allowedExtensions, + onChanged: (file) => setState(() { + didChange(file.bytes); + if (widget.onChanged != null) widget.onChanged(file.bytes); + }), + ); + } else { + _showUnattachDialog(); + } + } + + void _showUnattachDialog() async { + var theme = Theme.of(context); + var showIOS = (theme.platform == TargetPlatform.iOS || + theme.platform == TargetPlatform.macOS); + + if (!showIOS) { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text( + widget.unattachDialogTitle, + style: Theme.of(context).textTheme.headline6?.copyWith( + color: Theme.of(context).textTheme.headline1?.color), + ), + actions: [ + TextButton( + child: Text( + widget.unattachDialogCancel, + ), + onPressed: () => Navigator.of(context).pop(), + ), + TextButton( + child: Text(widget.unattachDialogConfirm), + onPressed: () { + didChange(null); + if (widget.onChanged != null) widget.onChanged(null); + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } else { + return showCupertinoDialog( + context: context, + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text(widget.unattachDialogTitle), + actions: [ + CupertinoDialogAction( + child: Text(widget.unattachDialogCancel), + onPressed: () => Navigator.of(context).pop(), + ), + CupertinoDialogAction( + child: Text(widget.unattachDialogConfirm), + onPressed: () { + didChange(null); + if (widget.onChanged != null) widget.onChanged(null); + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + } + + Widget _buildCupertinoFilePicker(String formattedValue) { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + if (widget.enabled) onTap(); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text(widget.label, style: ls), + ), + contentWidget: _buildFieldContent(formattedValue), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _buildMaterialFilePicker(String formattedValue) { + return GestureDetector( + onTap: () { + if (widget.enabled) onTap(); + }, + child: CardSettingsField( + label: widget.label, + enabled: widget.enabled, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + visible: widget.visible, + icon: widget.icon ?? Icon(Icons.attach_file), + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: _buildFieldContent(formattedValue), + pickerIcon: (widget.enabled) + ? (value == null) + ? Icons.attach_file + : Icons.clear + : null, + ), + ); + } + + Widget _buildFieldContent(String formattedValue) { + var contentAlign = + widget.contentAlign ?? CardSettings.of(context).contentAlign; + + var paddingAmt = + showCupertino(context, widget.showMaterialonIOS) ? 10.0 : 0.0; + + if (widget.fileType == FileType.image && value != null) { + return ConstrainedBox( + constraints: BoxConstraints( + maxWidth: widget.maxThumbnailWidth - paddingAmt, + maxHeight: widget.maxThumbnailHeight, + minHeight: 30, + ), + child: Container( + padding: EdgeInsets.symmetric(vertical: paddingAmt), + alignment: (contentAlign == TextAlign.right) + ? Alignment.topRight + : Alignment.topLeft, + child: Image.memory(value), + )); + } else { + return Text( + formattedValue, + style: contentStyle(context, value, widget.enabled), + textAlign: contentAlign, + ); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_list_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_list_picker.dart new file mode 100644 index 00000000..a459954e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_list_picker.dart @@ -0,0 +1,260 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_material_pickers/flutter_material_pickers.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a list picker that allows an arbitrary list of options to be provided. +class CardSettingsListPicker extends FormField + implements ICommonFieldProperties { + CardSettingsListPicker({ + Key key, + T initialItem, + FormFieldSetter onSaved, + FormFieldValidator validator, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + this.enabled = true, + this.label = 'Label', + this.visible = true, + this.onChanged, + this.requiredIndicator, + this.labelAlign, + this.labelWidth, + this.icon, + this.contentAlign, + this.hintText, + @required this.items, + this.showMaterialonIOS, + this.fieldPadding, + }) : super( + key: key, + initialValue: initialItem ?? null, + onSaved: onSaved, + validator: validator, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsListPickerState)._build(field.context)); + + /// fires when the picker value is changed + @override + final ValueChanged onChanged; + + /// The text to identify the field to the user + @override + final String label; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// text to display to guide the user on what to enter + final String hintText; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// a list of items for the picker + final List items; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsListPickerState createState() => + _CardSettingsListPickerState(); +} + +class _CardSettingsListPickerState extends FormFieldState { + @override + CardSettingsListPicker get widget => + super.widget as CardSettingsListPicker; + + List items = List.empty(); + + void _showDialog(String label) { + if (showCupertino(context, widget.showMaterialonIOS)) { + int itemIndex = items.indexOf(value); + _showCupertinoBottomPicker(itemIndex); + } else { + _showMaterialScrollPicker(label, value); + } + } + + void _showCupertinoBottomPicker(int optionIndex) { + final FixedExtentScrollController scrollController = + FixedExtentScrollController(initialItem: optionIndex); + showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return _buildCupertinoBottomPicker( + CupertinoPicker( + scrollController: scrollController, + itemExtent: kCupertinoPickerItemHeight, + backgroundColor: CupertinoColors.white, + onSelectedItemChanged: (int index) { + didChange(items[index]); + widget.onChanged(items[index]); + }, + children: List.generate(items.length, (int index) { + return Center( + child: Text(items[index].toString()), + ); + }), + ), + ); + }, + ).then((item) { + if (item != null) { + didChange(item); + if (widget.onChanged != null) widget.onChanged(item); + } + }); + } + + void _showMaterialScrollPicker(String label, T selectedItem) { + showMaterialScrollPicker( + context: context, + title: label, + items: items, + selectedItem: selectedItem, + onChanged: (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + }, + ); + } + + Widget _buildCupertinoBottomPicker(Widget picker) { + return Container( + height: kCupertinoPickerSheetHeight, + padding: const EdgeInsets.only(top: 6.0), + color: CupertinoColors.white, + child: DefaultTextStyle( + style: const TextStyle( + color: CupertinoColors.black, + fontSize: 22.0, + ), + child: GestureDetector( + // Blocks taps from propagating to the modal sheet and popping. + onTap: () {}, + child: SafeArea( + top: false, + child: picker, + ), + ), + ), + ); + } + + Widget _build(BuildContext context) { + // make local mutable copies of values and options + items = widget.items; + + // get the content label from options based on value + int itemIndex = items.indexOf(value); + String content = widget.hintText ?? ''; + if (itemIndex >= 0) { + content = items[itemIndex].toString(); + } + + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsListPicker(content); + else + return _materialSettingsListPicker(content); + } + + Widget _cupertinoSettingsListPicker(String content) { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(widget.label); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: Text( + content, + style: contentStyle(context, value, widget.enabled), + textAlign: widget.contentAlign ?? + CardSettings.of(context).contentAlign, + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _materialSettingsListPicker(String content) { + return GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(widget.label); + }, + child: CardSettingsField( + label: widget.label, + enabled: widget.enabled, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + visible: widget.visible, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Text( + content, + style: contentStyle(context, value, widget.enabled), + textAlign: + widget.contentAlign ?? CardSettings.of(context).contentAlign, + ), + pickerIcon: (widget.enabled) ? Icons.arrow_drop_down : null, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_number_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_number_picker.dart new file mode 100644 index 00000000..90ade3db --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_number_picker.dart @@ -0,0 +1,141 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a list picker that allows for a range of numbers to be speficied as pptions. +class CardSettingsNumberPicker extends StatelessWidget + implements ICommonFieldProperties { + CardSettingsNumberPicker({ + Key key, + this.label: 'Label', + this.labelAlign, + this.labelWidth, + this.initialValue, + this.contentAlign, + this.icon, + this.requiredIndicator, + @required this.min, + @required this.max, + this.stepInterval: 1, + this.autovalidateMode: AutovalidateMode.onUserInteraction, + this.enabled: true, + this.validator, + this.onSaved, + this.onChanged, + this.visible: true, + this.showMaterialonIOS, + this.fieldPadding, + }) : assert(min < max); + + /// The text to identify the field to the user + @override + final String label; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// the initial value fo the picker to be placed on + final int initialValue; + + /// the lowest value that will be shown + final int min; + + /// the highest value that will be shown + final int max; + + /// the interval for the values. Default is 1 + final int stepInterval; + + /// places the field into auto validation mode + @override + final AutovalidateMode autovalidateMode; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// If false, grays out the field and makes it unresponsive + final bool enabled; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + /// fires when validation is requested + @override + final FormFieldValidator validator; + + /// vires when the enclosing for is saved + @override + final FormFieldSetter onSaved; + + /// firest when the content is changed + @override + final ValueChanged onChanged; + + @override + Widget build(BuildContext context) { + return CardSettingsListPicker( + key: key, + label: this.label, + showMaterialonIOS: showMaterialonIOS, + fieldPadding: fieldPadding, + labelAlign: labelAlign, + labelWidth: labelWidth, + contentAlign: contentAlign, + visible: visible, + enabled: enabled, + initialItem: initialValue, + icon: icon, + requiredIndicator: requiredIndicator, + items: List.generate( + (max - min) ~/ stepInterval + 1, + (i) => (i * stepInterval + min), + ), + autovalidateMode: autovalidateMode, + validator: _safeValidator, + onSaved: _safeOnSaved, + onChanged: _safeOnChanged, + ); + } + + String _safeValidator(int value) { + if (validator == null) return null; + return validator(intelligentCast(value)); + } + + void _safeOnSaved(int value) { + if (onSaved == null) return; + onSaved(intelligentCast(value)); + } + + void _safeOnChanged(int value) { + if (onChanged == null) return; + onChanged(intelligentCast(value)); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_radio_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_radio_picker.dart new file mode 100644 index 00000000..e9efe36e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_radio_picker.dart @@ -0,0 +1,262 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_material_pickers/flutter_material_pickers.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a list picker that allows an arbitrary list of options to be provided. +class CardSettingsRadioPicker extends FormField + implements ICommonFieldProperties { + CardSettingsRadioPicker({ + Key key, + T initialItem, + FormFieldSetter onSaved, + FormFieldValidator validator, + // bool autovalidate: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + this.enabled = true, + this.label = 'Label', + this.visible = true, + this.onChanged, + this.requiredIndicator, + this.labelAlign, + this.labelWidth, + this.icon, + this.contentAlign, + this.hintText, + @required this.items, + this.showMaterialonIOS, + this.fieldPadding, + }) : super( + key: key, + initialValue: initialItem ?? null, + onSaved: onSaved, + validator: validator, + // autovalidate: autovalidate, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsRadioPickerState)._build(field.context)); + + /// fires when the selection changes + @override + final ValueChanged onChanged; + + /// The text to identify the field to the user + @override + final String label; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// text to display to guide the user on what to enter + final String hintText; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// a list of options to show on the picker + final List items; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsRadioPickerState createState() => + _CardSettingsRadioPickerState(); +} + +class _CardSettingsRadioPickerState extends FormFieldState { + @override + CardSettingsRadioPicker get widget => + super.widget as CardSettingsRadioPicker; + + List items = List.empty(); + + void _showDialog(String label) { + if (showCupertino(context, widget.showMaterialonIOS)) { + int valueIndex = items.indexOf(value); + _showCupertinoBottomPicker(valueIndex); + } else { + _showMaterialRadioPicker(label, value); + } + } + + void _showCupertinoBottomPicker(int valueIndex) { + final FixedExtentScrollController scrollController = + FixedExtentScrollController(initialItem: valueIndex); + showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return _buildCupertinoBottomPicker( + CupertinoPicker( + scrollController: scrollController, + itemExtent: kCupertinoPickerItemHeight, + backgroundColor: CupertinoColors.white, + onSelectedItemChanged: (int index) { + didChange(items[index]); + widget.onChanged(items[index]); + }, + children: List.generate(items.length, (int index) { + return Center( + child: Text(items[index].toString()), + ); + }), + ), + ); + }, + ).then((item) { + if (item != null) { + didChange(item); + if (widget.onChanged != null) widget.onChanged(item); + } + }); + } + + void _showMaterialRadioPicker(String label, T selectedItem) { + showMaterialRadioPicker( + context: context, + title: label, + items: items, + selectedItem: selectedItem, + onChanged: (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + }, + ); + } + + Widget _buildCupertinoBottomPicker(Widget picker) { + return Container( + height: kCupertinoPickerSheetHeight, + padding: const EdgeInsets.only(top: 6.0), + color: CupertinoColors.white, + child: DefaultTextStyle( + style: const TextStyle( + color: CupertinoColors.black, + fontSize: 22.0, + ), + child: GestureDetector( + // Blocks taps from propagating to the modal sheet and popping. + onTap: () {}, + child: SafeArea( + top: false, + child: picker, + ), + ), + ), + ); + } + + Widget _build(BuildContext context) { + // make local mutable copies of values and options + items = widget.items; + + // get the content label from options based on value + int itemIndex = items.indexOf(value); + String content = widget.hintText ?? ''; + if (itemIndex >= 0) { + content = items[itemIndex].toString(); + } + + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsListPicker(content); + else + return _materialSettingsListPicker(content); + } + + Widget _cupertinoSettingsListPicker(String content) { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(widget.label); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: Text( + content, + style: contentStyle(context, value, widget.enabled), + textAlign: widget.contentAlign ?? + CardSettings.of(context).contentAlign, + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _materialSettingsListPicker(String content) { + return GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(widget.label); + }, + child: CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + enabled: widget.enabled, + visible: widget.visible, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Text( + content, + style: contentStyle(context, value, widget.enabled), + textAlign: + widget.contentAlign ?? CardSettings.of(context).contentAlign, + ), + pickerIcon: (widget.enabled) ? Icons.arrow_drop_down : null, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_selection_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_selection_picker.dart new file mode 100644 index 00000000..d8a17bf1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_selection_picker.dart @@ -0,0 +1,276 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter_material_pickers/flutter_material_pickers.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This is a list picker that allows an arbitrary list of options to be provided. +class CardSettingsSelectionPicker extends FormField + implements ICommonFieldProperties { + CardSettingsSelectionPicker({ + Key key, + T initialItem, + FormFieldSetter onSaved, + FormFieldValidator validator, + // bool autovalidate: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + this.enabled = true, + this.label = 'Label', + this.visible = true, + this.onChanged, + this.requiredIndicator, + this.labelAlign, + this.labelWidth, + this.icon, + this.contentAlign, + this.hintText, + @required this.items, + this.showMaterialonIOS, + this.fieldPadding, + this.iconizer, + }) : super( + key: key, + initialValue: initialItem ?? null, + onSaved: onSaved, + validator: validator, + // autovalidate: autovalidate, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsListPickerState)._build(field.context)); + + /// fires when the section is changed + @override + final ValueChanged onChanged; + + /// The text to identify the field to the user + @override + final String label; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// displayes hint text on the selection form. + final String hintText; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// a list of items to provide on the selection picker + final List items; + + /// the function that will extract the icon from the items model + final Iconizer iconizer; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsListPickerState createState() => + _CardSettingsListPickerState(); +} + +class _CardSettingsListPickerState extends FormFieldState { + @override + CardSettingsSelectionPicker get widget => + super.widget as CardSettingsSelectionPicker; + + List items = List.empty(); + + void _showDialog(String label) { + if (showCupertino(context, widget.showMaterialonIOS)) { + int itemIndex = items.indexOf(value); + _showCupertinoBottomPicker(itemIndex); + } else { + _showMaterialSelectionPicker(label, value); + } + } + + void _showCupertinoBottomPicker(int valueIndex) { + final FixedExtentScrollController scrollController = + FixedExtentScrollController(initialItem: valueIndex); + showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return _buildCupertinoBottomPicker( + CupertinoPicker( + scrollController: scrollController, + itemExtent: kCupertinoPickerItemHeight, + backgroundColor: CupertinoColors.white, + onSelectedItemChanged: (int index) { + didChange(items[index]); + widget.onChanged(items[index]); + }, + children: List.generate(items.length, (int index) { + return Center( + child: Text(items[index].toString()), + ); + }), + ), + ); + }, + ).then((item) { + if (item != null) { + didChange(item); + if (widget.onChanged != null) widget.onChanged(item); + } + }); + } + + void _showMaterialSelectionPicker(String label, T selectedItem) { + showMaterialSelectionPicker( + context: context, + title: label, + items: items, + selectedItem: selectedItem, + iconizer: widget.iconizer, + onChanged: (value) { + didChange(value); + if (widget.onChanged != null) widget.onChanged(value); + }, + ); + } + + Widget _buildCupertinoBottomPicker(Widget picker) { + return Container( + height: kCupertinoPickerSheetHeight, + padding: const EdgeInsets.only(top: 6.0), + color: CupertinoColors.white, + child: DefaultTextStyle( + style: const TextStyle( + color: CupertinoColors.black, + fontSize: 22.0, + ), + child: GestureDetector( + // Blocks taps from propagating to the modal sheet and popping. + onTap: () {}, + child: SafeArea( + top: false, + child: picker, + ), + ), + ), + ); + } + + Widget _build(BuildContext context) { + // make local mutable copies of values and options + items = widget.items; + + // get the content label from options based on value + int itemIndex = items.indexOf(value); + String content = widget.hintText ?? ''; + if (itemIndex >= 0) { + content = items[itemIndex].toString(); + } + + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsListPicker(content); + else + return _materialSettingsListPicker(content); + } + + Widget _cupertinoSettingsListPicker(String content) { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + _showDialog(widget.label); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: Text( + content, + style: Theme.of(context).textTheme.subtitle1.copyWith( + color: (value == null) + ? Theme.of(context).hintColor + : Theme.of(context).textTheme.subtitle1?.color), + textAlign: widget.contentAlign ?? + CardSettings.of(context).contentAlign, + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _materialSettingsListPicker(String content) { + var style = Theme.of(context).textTheme.subtitle1?.copyWith( + color: (value == null) + ? Theme.of(context).hintColor + : Theme.of(context).textTheme.subtitle1?.color); + if (!widget.enabled) style = style?.copyWith(color: Colors.grey); + + return GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(widget.label); + }, + child: CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + enabled: widget.enabled, + visible: widget.visible, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Text( + content, + style: style, + textAlign: + widget.contentAlign ?? CardSettings.of(context).contentAlign, + ), + pickerIcon: (widget.enabled) ? Icons.arrow_drop_down : null, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_time_picker.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_time_picker.dart new file mode 100644 index 00000000..19a1e2e4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/picker_fields/card_settings_time_picker.dart @@ -0,0 +1,238 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; + +/// This field allows a time to be selected. +class CardSettingsTimePicker extends FormField + implements ICommonFieldProperties { + CardSettingsTimePicker({ + Key key, + FormFieldSetter onSaved, + FormFieldValidator validator, + TimeOfDay initialValue, + // bool autovalidate: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + this.enabled = true, + this.visible = true, + this.onChanged, + this.contentAlign, + this.requiredIndicator, + this.labelAlign, + this.labelWidth, + this.label = 'Time', + this.icon, + this.style, + this.showMaterialonIOS, + this.fieldPadding, + }) : super( + key: key, + initialValue: initialValue ?? TimeOfDay.now(), + onSaved: onSaved, + validator: validator, + // autovalidate: autovalidate, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsTimePickerState)._build(field.context), + ); + + /// fired when the selection changes + @override + final ValueChanged onChanged; + + /// The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + /// controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + /// The icon to display to the left of the field content + @override + final Icon icon; + + /// If false the field is grayed out and unresponsive + @override + final bool enabled; + + /// A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + /// If false hides the widget on the card setting panel + @override + final bool visible; + + /// The text to identify the field to the user + @override + final String label; + + /// The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + /// the style of the text in the label + final TextStyle style; + + /// Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + /// places padding around the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + @override + _CardSettingsTimePickerState createState() => _CardSettingsTimePickerState(); +} + +class _CardSettingsTimePickerState extends FormFieldState { + @override + CardSettingsTimePicker get widget => super.widget as CardSettingsTimePicker; + + void _showDialog() { + if (showCupertino(context, widget.showMaterialonIOS)) { + _showCupertinoPopUpTimePicker(); + } else + _showMaterialPopUpTimePicker(); + } + + Widget _build(BuildContext context) { + if (showCupertino(context, widget.showMaterialonIOS)) + return _cupertinoSettingsTimePicker(); + else + return _materialSettingsTimePicker(); + } + + Widget _buildBottomPicker(Widget picker) { + return Container( + height: kCupertinoPickerSheetHeight, + padding: const EdgeInsets.only(top: 6.0), + color: CupertinoColors.white, + child: DefaultTextStyle( + style: const TextStyle( + color: CupertinoColors.black, + fontSize: 22.0, + ), + child: GestureDetector( + // Blocks taps from propagating to the modal sheet and popping. + onTap: () {}, + child: SafeArea( + top: false, + child: picker, + ), + ), + ), + ); + } + + void _showCupertinoPopUpTimePicker() { + showCupertinoModalPopup( + context: context, + builder: (BuildContext context) { + return _buildBottomPicker( + CupertinoDatePicker( + mode: CupertinoDatePickerMode.time, + initialDateTime: value == null + ? DateTime.now() + : DateTime(DateTime.now().year, DateTime.now().month, + DateTime.now().day, value.hour, value.minute), + onDateTimeChanged: (DateTime newDateTime) { + didChange(TimeOfDay.fromDateTime(newDateTime)); + if (widget.onChanged != null) + widget.onChanged(TimeOfDay.fromDateTime(newDateTime)); + }, + ), + ); + }, + ).then((_value) { + if (_value != null) { + didChange(TimeOfDay.fromDateTime(_value)); + if (widget.onChanged != null) + widget.onChanged(TimeOfDay.fromDateTime(_value)); + } + }); + } + + void _showMaterialPopUpTimePicker() { + showTimePicker( + context: context, + initialTime: value, + ).then((_value) { + if (_value != null) { + didChange(_value); + if (widget.onChanged != null) widget.onChanged(_value); + } + }); + } + + Widget _cupertinoSettingsTimePicker() { + final ls = labelStyle(context, widget.enabled); + return Container( + child: widget.visible == false + ? null + : GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(); + }, + child: CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text( + widget.label, + style: ls, + ), + ), + contentWidget: Text( + value == null ? '' : value.format(context), + style: contentStyle(context, value, widget.enabled), + textAlign: widget.contentAlign ?? + CardSettings.of(context).contentAlign, + ), + style: CSWidgetStyle(icon: widget.icon), + ), + ), + ); + } + + Widget _materialSettingsTimePicker() { + return GestureDetector( + onTap: () { + if (widget.enabled) _showDialog(); + }, + child: CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + enabled: widget.enabled, + visible: widget.visible, + icon: widget.icon ?? Icon(Icons.event), + requiredIndicator: widget.requiredIndicator, + errorText: errorText, + fieldPadding: widget.fieldPadding, + content: Text( + value == null ? '' : value.format(context), + style: contentStyle(context, value, widget.enabled), + textAlign: + widget.contentAlign ?? CardSettings.of(context).contentAlign, + ), + pickerIcon: (widget.enabled) ? Icons.arrow_drop_down : null, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_email.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_email.dart new file mode 100644 index 00000000..badef3df --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_email.dart @@ -0,0 +1,77 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; +import '../../interfaces/text_field_properties.dart'; + +/// This is a password field. It obscures the entered text. +class CardSettingsEmail extends CardSettingsText + implements ICommonFieldProperties, ITextFieldProperties { + CardSettingsEmail({ + Key key, + String label: 'Email', + bool contentOnNewLine: false, + double labelWidth, + TextAlign labelAlign, + TextAlign contentAlign, + String initialValue, + Icon icon, + Widget requiredIndicator, + int maxLength: 30, + bool visible: true, + bool enabled: true, + bool autofocus: false, + bool obscureText: false, + bool autocorrect: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldValidator validator, + FormFieldSetter onSaved, + ValueChanged onChanged, + TextEditingController controller, + FocusNode focusNode, + TextInputAction inputAction, + FocusNode inputActionNode, + TextInputType keyboardType = TextInputType.emailAddress, + TextStyle style, + MaxLengthEnforcement maxLengthEnforcement: MaxLengthEnforcement.enforced, + ValueChanged onFieldSubmitted, + List inputFormatters, + bool showMaterialonIOS, + EdgeInsetsGeometry fieldPadding, + }) : super( + key: key, + label: label, + labelWidth: labelWidth, + labelAlign: labelAlign, + showMaterialonIOS: showMaterialonIOS, + fieldPadding: fieldPadding, + contentAlign: contentAlign, + contentOnNewLine: contentOnNewLine, + initialValue: initialValue, + maxLength: maxLength, + icon: icon, + requiredIndicator: requiredIndicator, + visible: visible, + enabled: enabled, + autofocus: autofocus, + obscureText: obscureText, + autocorrect: autocorrect, + autovalidateMode: autovalidateMode, + validator: validator, + onSaved: onSaved, + onChanged: onChanged, + controller: controller, + focusNode: focusNode, + inputAction: inputAction, + inputActionNode: inputActionNode, + keyboardType: keyboardType, + style: style, + maxLengthEnforcement: maxLengthEnforcement, + onFieldSubmitted: onFieldSubmitted, + inputFormatters: inputFormatters, + ); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_paragraph.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_paragraph.dart new file mode 100644 index 00000000..d40f119d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_paragraph.dart @@ -0,0 +1,81 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; +import '../../interfaces/text_field_properties.dart'; + +/// This is a password field. It obscures the entered text. +class CardSettingsParagraph extends CardSettingsText + implements ICommonFieldProperties, ITextFieldProperties { + CardSettingsParagraph({ + Key key, + String label: 'Label', + String hintText, + TextAlign labelAlign, + TextAlign contentAlign: TextAlign.left, + String initialValue, + Icon icon, + Widget requiredIndicator, + int maxLength: 250, + int numberOfLines: 7, + bool contentOnNewLine: true, + bool visible: true, + bool enabled: true, + bool showCounter: true, + bool autofocus: false, + bool obscureText: false, + bool autocorrect: true, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldValidator validator, + FormFieldSetter onSaved, + ValueChanged onChanged, + TextEditingController controller, + FocusNode focusNode, + TextInputAction inputAction, + FocusNode inputActionNode, + TextInputType keyboardType = TextInputType.multiline, + TextStyle style, + MaxLengthEnforcement maxLengthEnforcement: MaxLengthEnforcement.enforced, + ValueChanged onFieldSubmitted, + List inputFormatters, + bool showMaterialonIOS, + EdgeInsetsGeometry fieldPadding, + }) : super( + key: key, + label: label, + labelAlign: labelAlign, + hintText: hintText, + contentAlign: contentAlign, + showMaterialonIOS: showMaterialonIOS, + fieldPadding: fieldPadding, + initialValue: initialValue, + contentOnNewLine: contentOnNewLine, + maxLength: maxLength, + icon: icon, + requiredIndicator: requiredIndicator, + numberOfLines: numberOfLines, + showCounter: (enabled == true) ? showCounter : false, + visible: visible, + enabled: enabled, + autofocus: autofocus, + obscureText: obscureText, + autocorrect: autocorrect, + autovalidateMode: autovalidateMode, + validator: validator, + onSaved: onSaved, + onChanged: onChanged, + controller: controller, + focusNode: focusNode, + inputAction: inputAction, + inputActionNode: inputActionNode, + keyboardType: keyboardType, + style: style, + maxLengthEnforcement: maxLengthEnforcement, + onFieldSubmitted: onFieldSubmitted, + inputFormatters: inputFormatters, + ); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_password.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_password.dart new file mode 100644 index 00000000..7e4fe6ac --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_password.dart @@ -0,0 +1,79 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; +import '../../interfaces/text_field_properties.dart'; + +/// This is a password field. It obscures the entered text. +class CardSettingsPassword extends CardSettingsText + implements ICommonFieldProperties, ITextFieldProperties { + CardSettingsPassword({ + Key key, + String label: 'Password', + String hintText: '', + double labelWidth, + TextAlign labelAlign, + TextAlign contentAlign, + bool contentOnNewLine: false, + String initialValue, + Icon icon, + Widget requiredIndicator, + int maxLength: 20, + bool visible: true, + bool enabled: true, + bool autofocus: false, + bool obscureText: true, + bool autocorrect: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + FormFieldValidator validator, + FormFieldSetter onSaved, + ValueChanged onChanged, + TextEditingController controller, + FocusNode focusNode, + TextInputAction inputAction, + FocusNode inputActionNode, + TextInputType keyboardType = TextInputType.text, + TextStyle style, + MaxLengthEnforcement maxLengthEnforcement: MaxLengthEnforcement.enforced, + ValueChanged onFieldSubmitted, + List inputFormatters, + bool showMaterialonIOS, + EdgeInsetsGeometry fieldPadding, + }) : super( + key: key, + label: label, + labelWidth: labelWidth, + labelAlign: labelAlign, + hintText: hintText, + showMaterialonIOS: showMaterialonIOS, + fieldPadding: fieldPadding, + contentAlign: contentAlign, + contentOnNewLine: contentOnNewLine, + initialValue: initialValue, + maxLength: maxLength, + icon: icon, + requiredIndicator: requiredIndicator, + visible: visible, + enabled: enabled, + autofocus: autofocus, + obscureText: obscureText, + autocorrect: autocorrect, + autovalidateMode: autovalidateMode, + validator: validator, + onSaved: onSaved, + onChanged: onChanged, + controller: controller, + focusNode: focusNode, + inputAction: inputAction, + inputActionNode: inputActionNode, + keyboardType: keyboardType, + style: style, + maxLengthEnforcement: maxLengthEnforcement, + onFieldSubmitted: onFieldSubmitted, + inputFormatters: inputFormatters, + ); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_phone.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_phone.dart new file mode 100644 index 00000000..aab78874 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_phone.dart @@ -0,0 +1,197 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_multi_formatter/flutter_multi_formatter.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; +import '../../interfaces/text_field_properties.dart'; + +/// This is a phone number field. It's designed for US numbers +class CardSettingsPhone extends StatelessWidget + implements ICommonFieldProperties, ITextFieldProperties { + CardSettingsPhone({ + Key key, + this.label: 'Phone', + this.labelWidth, + this.labelAlign, + this.hintText, + this.prefixText, + this.contentAlign, + this.initialValue, + this.contentOnNewLine = false, + this.maxLength = 20, + this.icon, + this.requiredIndicator, + this.visible: true, + this.enabled: true, + this.autofocus: false, + this.obscureText: false, + this.autocorrect: false, + this.autovalidateMode: AutovalidateMode.onUserInteraction, + this.validator, + this.onSaved, + this.onChanged, + this.controller, + this.focusNode, + this.inputAction, + this.inputActionNode, + this.keyboardType, + this.style, + this.maxLengthEnforcement: MaxLengthEnforcement.enforced, + this.onFieldSubmitted, + this.inputFormatters, + this.showMaterialonIOS, + this.fieldPadding, + }); + + // The text to identify the field to the user + @override + final String label; + + // The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + // The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + // controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + @override + // text to display to guide the user on what to enter + final String hintText; + + final String prefixText; + + final int initialValue; + + final bool contentOnNewLine; + + final int maxLength; + + // The icon to display to the left of the field content + @override + final Icon icon; + + // A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + // If false hides the widget on the card setting panel + @override + final bool visible; + + // If false, grays out the field and makes it unresponsive + final bool enabled; + + final bool autofocus; + + final bool obscureText; + + final bool autocorrect; + + @override + final AutovalidateMode autovalidateMode; + + @override + final FormFieldValidator validator; + + @override + final FormFieldSetter onSaved; + + @override + final ValueChanged onChanged; + + final TextEditingController controller; + + final FocusNode focusNode; + + final FocusNode inputActionNode; + + final TextInputType keyboardType; + + final TextStyle style; + + final TextInputAction inputAction; + + final MaxLengthEnforcement maxLengthEnforcement; + + final ValueChanged onFieldSubmitted; + + final List inputFormatters; + + // provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + // Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + @override + Widget build(BuildContext context) { + return CardSettingsText( + key: key, + label: label, + labelWidth: labelWidth, + labelAlign: labelAlign, + contentAlign: contentAlign, + initialValue: initialValue != null + ? formatAsPhoneNumber(initialValue.toString()) + : "", + contentOnNewLine: contentOnNewLine, + maxLength: maxLength, + hintText: hintText, + prefixText: prefixText, + icon: icon, + requiredIndicator: requiredIndicator, + visible: visible, + enabled: enabled, + autofocus: autofocus, + showMaterialonIOS: showMaterialonIOS, + obscureText: obscureText, + autocorrect: autocorrect, + autovalidateMode: autovalidateMode, + validator: _safeValidator, + onSaved: _safeOnSaved, + onChanged: _safeOnChanged, + controller: controller, + focusNode: focusNode, + fieldPadding: fieldPadding, + inputActionNode: inputActionNode, + keyboardType: + keyboardType ?? TextInputType.numberWithOptions(decimal: false), + style: style, + maxLengthEnforcement: maxLengthEnforcement, + onFieldSubmitted: onFieldSubmitted, + inputFormatters: [ + PhoneInputFormatter(), + ], + inputAction: inputAction, + ); + } + + String _safeValidator(String value) { + if (validator == null) return null; + var numbers = toNumericString(value); + return validator(intelligentCast(numbers)); + } + + void _safeOnSaved(String value) { + if (onSaved == null) return; + var numbers = toNumericString(value); + onSaved(intelligentCast(numbers)); + } + + void _safeOnChanged(String value) { + if (onChanged == null) return; + var numbers = toNumericString(value); + onChanged(intelligentCast(numbers)); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_text.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_text.dart new file mode 100644 index 00000000..a8b8bcbd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/lib/widgets/text_fields/card_settings_text.dart @@ -0,0 +1,480 @@ +// Copyright (c) 2018, codegrue. All rights reserved. Use of this source code +// is governed by the MIT license that can be found in the LICENSE file. + +import 'package:flutter_helper/samples/card_settings/lib/helpers/platform_functions.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:extended_masked_text/extended_masked_text.dart'; +import 'package:flutter_cupertino_settings/flutter_cupertino_settings.dart'; +import 'package:flutter/cupertino.dart'; + +import '../../card_settings.dart'; +import '../../interfaces/common_field_properties.dart'; +import '../../interfaces/text_field_properties.dart'; + +/// This is a standard one line text entry It's based on the [TextFormField] widget. +class CardSettingsText extends FormField + implements ICommonFieldProperties, ITextFieldProperties { + CardSettingsText({ + Key key, + String initialValue, + bool autovalidate: false, + AutovalidateMode autovalidateMode: AutovalidateMode.onUserInteraction, + this.enabled = true, + this.onSaved, + this.validator, + this.onChanged, + this.controller, + this.textCapitalization = TextCapitalization.none, + this.keyboardType = TextInputType.text, + this.maxLengthEnforcement: MaxLengthEnforcement.enforced, + this.inputMask, + this.inputFormatters, + this.onFieldSubmitted, + this.style, + this.focusNode, + this.inputAction, + this.inputActionNode, + this.label = 'Label', + this.contentOnNewLine = false, + this.maxLength = 20, + this.numberOfLines = 1, + this.showCounter = false, + this.visible = true, + this.autocorrect = true, + this.obscureText = false, + this.autofocus = false, + this.contentAlign, + this.hintText, + this.icon, + this.labelAlign, + this.labelWidth, + this.prefixText, + this.requiredIndicator, + this.unitLabel, + this.showMaterialonIOS, + this.showClearButtonIOS = OverlayVisibilityMode.never, + this.fieldPadding, + this.contentPadding = const EdgeInsets.all(0.0), + }) : assert(maxLength > 0), + assert(controller == null || inputMask == null), + super( + key: key, + initialValue: initialValue, + onSaved: onSaved, + validator: validator, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) => + (field as _CardSettingsTextState)._build(field.context), + ); + + @override + final ValueChanged onChanged; + + final TextEditingController controller; + + final String inputMask; + + final FocusNode focusNode; + + final TextInputAction inputAction; + + final FocusNode inputActionNode; + + final TextInputType keyboardType; + + final TextCapitalization textCapitalization; + + final TextStyle style; + + // If false the field is grayed out and unresponsive + @override + // If false, grays out the field and makes it unresponsive + final bool enabled; + + final MaxLengthEnforcement maxLengthEnforcement; + + final ValueChanged onFieldSubmitted; + + final List inputFormatters; + + // The text to identify the field to the user + @override + final String label; + + // The alignment of the label paret of the field. Default is left. + @override + final TextAlign labelAlign; + + // The width of the field label. If provided overrides the global setting. + @override + final double labelWidth; + + // controls how the widget in the content area of the field is aligned + @override + final TextAlign contentAlign; + + final String unitLabel; + + final String prefixText; + + @override + // text to display to guide the user on what to enter + final String hintText; + + // The icon to display to the left of the field content + @override + final Icon icon; + + // A widget to show next to the label if the field is required + @override + final Widget requiredIndicator; + + final bool contentOnNewLine; + + final int maxLength; + + final int numberOfLines; + + final bool showCounter; + + // If false hides the widget on the card setting panel + @override + final bool visible; + + final bool autofocus; + + final bool obscureText; + + final bool autocorrect; + + // Force the widget to use Material style on an iOS device + @override + final bool showMaterialonIOS; + + // provides padding to wrap the entire field + @override + final EdgeInsetsGeometry fieldPadding; + + final EdgeInsetsGeometry contentPadding; + + ///Since the CupertinoTextField does not support onSaved, please use [onChanged] or [onFieldSubmitted] instead + @override + final FormFieldSetter onSaved; + + ///In material mode this shows the validation text under the field + ///In cupertino mode, it shows a [red] [Border] around the [CupertinoTextField] + @override + final FormFieldValidator validator; + + final OverlayVisibilityMode showClearButtonIOS; + + @override + _CardSettingsTextState createState() => _CardSettingsTextState(); +} + +class _CardSettingsTextState extends FormFieldState { + TextEditingController _controller; + + @override + CardSettingsText get widget => super.widget as CardSettingsText; + + @override + void initState() { + super.initState(); + _initController(widget.initialValue); + } + + @override + void didUpdateWidget(CardSettingsText oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.controller != oldWidget.controller) { + oldWidget.controller?.removeListener(_handleControllerChanged); + _initController(oldWidget.controller?.value.toString()); + } + } + + void _initController(String initialValue) { + if (widget.controller == null) { + if (widget.inputMask == null) { + _controller = TextEditingController(text: initialValue); + } else { + _controller = + MaskedTextController(mask: widget.inputMask, text: initialValue); + } + } else { + _controller = widget.controller; + } + + _controller.addListener(_handleControllerChanged); + } + + @override + void dispose() { + widget.controller?.removeListener(_handleControllerChanged); + super.dispose(); + } + + @override + void reset() { + super.reset(); + setState(() { + _controller.text = widget.initialValue ?? ''; + }); + } + + void _handleControllerChanged() { + if (_controller.text != value) { + didChange(_controller.text); + } + } + + void _handleOnChanged(String value) { + if (widget.onChanged != null) { + // `value` doesn't apple any masks when this is called, so the controller has the actual formatted value + widget.onChanged(_controller.value.text); + } + } + + void _onFieldSubmitted(String value) { + if (this.widget.focusNode != null) this.widget.focusNode.unfocus(); + + if (this.widget.inputActionNode != null) { + this.widget.inputActionNode.requestFocus(); + return; + } + + if (this.widget.onFieldSubmitted != null) + this.widget.onFieldSubmitted(value); + } + + Widget _build(BuildContext context) { + if (showCupertino(context, widget.showMaterialonIOS)) + return _buildCupertinoTextbox(context); + else + return _buildMaterialTextbox(context); + } + + Container _buildCupertinoTextbox(BuildContext context) { + bool hasError = false; + if (widget.validator != null) { + String errorMessage = widget.validator(value); + hasError = (errorMessage != null); + } + + final ls = labelStyle(context, widget.enabled); + final _child = Container( + child: CupertinoTextField( + prefix: widget.prefixText == null + ? null + : Text( + widget.prefixText ?? '', + style: ls, + ), + suffix: widget.unitLabel == null + ? null + : Text( + widget.unitLabel ?? '', + style: ls, + ), + controller: _controller, + focusNode: widget.focusNode, + textInputAction: widget.inputAction, + keyboardType: widget.keyboardType, + textCapitalization: widget.textCapitalization, + style: contentStyle(context, value, widget.enabled), + decoration: hasError + ? BoxDecoration( + border: Border.all(color: Colors.red), + borderRadius: BorderRadius.all( + Radius.circular(4.0), + ), + ) + : BoxDecoration( + border: Border( + top: BorderSide( + color: CupertinoColors.lightBackgroundGray, + style: BorderStyle.solid, + width: 0.0, + ), + bottom: BorderSide( + color: CupertinoColors.lightBackgroundGray, + style: BorderStyle.solid, + width: 0.0, + ), + left: BorderSide( + color: CupertinoColors.lightBackgroundGray, + style: BorderStyle.solid, + width: 0.0, + ), + right: BorderSide( + color: CupertinoColors.lightBackgroundGray, + style: BorderStyle.solid, + width: 0.0, + ), + ), + borderRadius: BorderRadius.all( + Radius.circular(4.0), + ), + ), + clearButtonMode: widget.showClearButtonIOS, + placeholder: widget.hintText, + textAlign: widget.contentAlign ?? TextAlign.end, + autofocus: widget.autofocus, + obscureText: widget.obscureText, + autocorrect: widget.autocorrect, + maxLengthEnforcement: widget.maxLengthEnforcement, + maxLines: widget.numberOfLines, + maxLength: (widget.showCounter) + ? widget.maxLength + : null, // if we want counter use default behavior + onChanged: _handleOnChanged, + onSubmitted: _onFieldSubmitted, + inputFormatters: widget.inputFormatters ?? + [ + // if we don't want the counter, use this maxLength instead + LengthLimitingTextInputFormatter(widget.maxLength) + ], + enabled: widget.enabled, + ), + ); + return Container( + child: widget.visible == false + ? null + : widget.contentOnNewLine == true + ? Column( + mainAxisSize: MainAxisSize.min, + children: [ + CSControl( + nameWidget: widget.requiredIndicator != null + ? Text( + (widget.label) + ' *', + style: ls, + ) + : Text(widget.label, style: ls), + contentWidget: Container(), + style: CSWidgetStyle(icon: widget.icon), + ), + Container( + padding: EdgeInsets.all(5.0), + child: _child, + color: Theme.of(context).brightness == Brightness.dark + ? null + : CupertinoColors.white, + ), + Container( + padding: widget.showCounter ? EdgeInsets.all(5.0) : null, + color: Theme.of(context).brightness == Brightness.dark + ? null + : CupertinoColors.white, + child: widget.showCounter + ? Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "${_controller?.text.length ?? 0}/${widget.maxLength}", + style: TextStyle( + color: CupertinoColors.inactiveGray, + ), + ), + ], + ) + : null, + ), + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + children: [ + CSControl( + nameWidget: Container( + width: widget.labelWidth ?? + CardSettings.of(context).labelWidth ?? + 120.0, + child: widget.requiredIndicator != null + ? Text((widget.label) + ' *', style: ls) + : Text(widget.label, style: ls), + ), + contentWidget: Expanded( + child: Container( + padding: EdgeInsets.only(left: 10.0), + child: _child, + ), + ), + style: CSWidgetStyle(icon: widget.icon), + ), + Container( + padding: widget.showCounter ? EdgeInsets.all(5.0) : null, + color: Theme.of(context).brightness == Brightness.dark + ? null + : CupertinoColors.white, + child: widget.showCounter + ? Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "${_controller?.text.length ?? 0}/${widget.maxLength}", + style: TextStyle( + color: CupertinoColors.inactiveGray, + ), + ), + ], + ) + : null, + ), + ], + ), + ); + } + + CardSettingsField _buildMaterialTextbox(BuildContext context) { + return CardSettingsField( + label: widget.label, + labelAlign: widget.labelAlign, + labelWidth: widget.labelWidth, + visible: widget.visible, + unitLabel: widget.unitLabel, + icon: widget.icon, + requiredIndicator: widget.requiredIndicator, + contentOnNewLine: widget.contentOnNewLine, + enabled: widget.enabled, + fieldPadding: widget.fieldPadding, + content: TextField( + controller: _controller, + focusNode: widget.focusNode, + keyboardType: widget.keyboardType, + textInputAction: widget.inputAction, + textCapitalization: widget.textCapitalization, + enabled: widget.enabled, + readOnly: !widget.enabled, + style: contentStyle(context, value, widget.enabled), + decoration: InputDecoration( + contentPadding: widget.contentPadding, + border: InputBorder.none, + errorText: errorText, + prefixText: widget.prefixText, + hintText: widget.hintText, + isDense: true, + ), + textAlign: + widget.contentAlign ?? CardSettings.of(context).contentAlign, + autofocus: widget.autofocus, + obscureText: widget.obscureText, + autocorrect: widget.autocorrect, + maxLengthEnforcement: widget.maxLengthEnforcement, + maxLines: widget.numberOfLines, + maxLength: (widget.showCounter) + ? widget.maxLength + : null, // if we want counter use default behavior + onChanged: _handleOnChanged, + onSubmitted: _onFieldSubmitted, + inputFormatters: widget.inputFormatters ?? + [ + // if we don't want the counter, use this maxLength instead + LengthLimitingTextInputFormatter(widget.maxLength) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/main.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/main.dart new file mode 100644 index 00000000..d29c8d0e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/main.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +import 'plumbing/theme.dart'; + +void main() => runApp(CardSettingsApp()); + +class CardSettingsApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ExampleTheme(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/model.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/model.dart new file mode 100644 index 00000000..ef561d7f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/model.dart @@ -0,0 +1,80 @@ +// example viewmodel for the form +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/samples/card_settings/lib/models/picker_model.dart'; + +class PonyModel { + String name = 'Twilight Sparkle'; + PickerModel type = ponyTypes[1]; //double, bind by value + int age = 7; + PickerModel gender = ponyGenders[1]; //double: "F"; + String coatColor = 'D19FE4'; + String maneColor = '273873'; + bool hasSpots = false; + String spotColor = 'FF5198'; + String description = + 'An intelligent and dutiful scholar with an avid love of learning and skill in unicorn magic such as levitation, teleportation, and the creation of force fields.'; + List hobbies = [ + 'flying', + 'singing', + 'exploring', + 'hiding', + 'coloring' + ]; + double height = 3.5; + int weight = 45; + PickerModel style = ponyStyles[1]; // double: "MG"; + DateTime showDateTime = DateTime(2010, 10, 10, 20, 30); + double ticketPrice = 65.99; + int boxOfficePhone = 18005551212; + String email = 'me@nowhere.org'; + String password = 'secret1'; + double rating = 0.25; + Uint8List photo; + Uint8List video = Uint8List(1024 * 1024 * 15); + Uint8List audio = Uint8List(1024 * 4); + Uint8List customFile = Uint8List(4); + + void loadMedia() async { + photo = (await rootBundle.load('assets/twilight_sparkle.png')) + .buffer + .asUint8List(); + } +} + +const List allHobbies = [ + 'running', + 'flying', + 'coloring', + 'jumping', + 'eating', + 'hiding', + 'exploring', + 'singing', + 'dancing', + 'acting', + 'cleaning', + 'shopping', + 'sewing', + 'cooking', +]; + +const List ponyTypes = [ + PickerModel('Earth', code: 'E'), + PickerModel('Unicorn', code: 'U'), + PickerModel('Pegasi', code: 'P'), + PickerModel('Alicorn', code: 'A'), +]; + +const List ponyGenders = [ + PickerModel('Male', code: 'M'), + PickerModel('Female', code: 'F'), +]; + +const List ponyStyles = [ + PickerModel('Majestic', code: 'MG', icon: Icon(Icons.sort)), + PickerModel('Scrawny', code: 'SC', icon: Icon(Icons.clear_all)), + PickerModel('Sleek', code: 'SL', icon: Icon(Icons.swap_calls)), +]; diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/results.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/results.dart new file mode 100644 index 00000000..2cd1f08f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/results.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/card_settings/lib/card_settings.dart'; +import 'package:intl/intl.dart'; + +import 'model.dart'; + +void showResults(BuildContext context, PonyModel model) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('Updated Results'), + content: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildResultsRow('Name', model.name), + _buildResultsRow('Type', model.type), + _buildResultsRow('Gender', model.gender), + _buildResultsRow('Age', model.age), + _buildResultsRow('Description', model.description, + linebreak: true), + _buildResultsRow('Hobbies', model.hobbies, linebreak: true), + _buildResultsRow('CoatColor', model.coatColor), + _buildResultsRow('ManeColor', model.maneColor), + _buildResultsRow('Style', model.style), + _buildResultsRow('HasSpots', model.hasSpots), + _buildResultsRow('SpotColor', model.spotColor), + _buildResultsRow('Height', model.height), + _buildResultsRow('Weight', model.weight), + _buildResultsRow( + 'ShowDate', DateFormat.yMd().format(model.showDateTime)), + _buildResultsRow( + 'ShowTime', DateFormat.jm().format(model.showDateTime)), + _buildResultsRow('Phone', model.boxOfficePhone), + _buildResultsRow('Price', model.ticketPrice), + _buildResultsRow( + 'Audio', + CardSettingsFilePicker.formatBytes( + model.audio?.length ?? 0, 3)), + _buildResultsRow( + 'Photo', + CardSettingsFilePicker.formatBytes( + model.photo?.length ?? 0, 2)), + _buildResultsRow( + 'Video', + CardSettingsFilePicker.formatBytes( + model.video?.length ?? 0, 1)), + _buildResultsRow( + 'Custom file', + CardSettingsFilePicker.formatBytes( + model.customFile?.length ?? 0, 0)), + ], + ), + ), + actions: [ + TextButton( + child: Text("Close"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); +} + +void showErrors(BuildContext context) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('Form has validation errors'), + content: Text('Please fix all errors before submitting the form.'), + actions: [ + TextButton( + child: Text("Close"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); +} + +Widget _buildResultsRow(String name, dynamic value, {bool linebreak: false}) { + return Column( + children: [ + Row( + children: [ + Expanded( + child: Text( + '$name:', + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + _buildValueInline(value, linebreak), + ], + ), + _buildValueOnOwnRow(value, linebreak), + Container(height: 12.0), + ], + ); +} + +Widget _buildValueInline(dynamic value, bool linebreak) { + return (linebreak) ? Container() : Text(value.toString()); +} + +Widget _buildValueOnOwnRow(dynamic value, bool linebreak) { + return (linebreak) ? Text(value.toString()) : Container(); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/scaffold.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/scaffold.dart new file mode 100644 index 00000000..bb8a805e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/scaffold.dart @@ -0,0 +1,91 @@ +import 'dart:io'; + +import 'package:adaptive_theme/adaptive_theme.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +import '../example.dart'; + +class ExampleScaffold extends StatefulWidget { + @override + _ExampleScaffoldState createState() => _ExampleScaffoldState(); +} + +class _ExampleScaffoldState extends State { + bool _showMaterialonIOS = true; + + final GlobalKey _scaffoldKey = GlobalKey(); + final GlobalKey _formWidgetKey = + GlobalKey(); + + @override + Widget build(BuildContext context) { + var orientation = MediaQuery.of(context).orientation; + + final form = ExampleForm(orientation, _showMaterialonIOS, _scaffoldKey, + key: _formWidgetKey, onValueChanged: showSnackBar); + + return Scaffold( + key: _scaffoldKey, + backgroundColor: Theme.of(context).backgroundColor, + appBar: AppBar( + title: Text("My Little Pony"), + actions: [ + IconButton( + icon: Theme.of(context).brightness == Brightness.dark + ? Icon(Icons.brightness_7) + : Icon(Icons.brightness_4), + onPressed: () => AdaptiveTheme.of(context).toggleThemeMode(), + ), + _cupertinoSwitchButton(), + IconButton( + icon: Icon(Icons.save), + onPressed: (_formWidgetKey.currentState == null) + ? null + : _formWidgetKey.currentState.savePressed, + ), + ], + leading: IconButton( + icon: Icon(Icons.refresh), + onPressed: (_formWidgetKey.currentState == null) + ? null + : _formWidgetKey.currentState.resetPressed, + ), + ), + body: form, + ); + } + + void showSnackBar(String label, dynamic value) { + ScaffoldMessenger.of(context).removeCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + duration: Duration(seconds: 1), + content: Text(label + ' = ' + value.toString()), + ), + ); + } + + Widget _cupertinoSwitchButton() { + // dont show this button on web + if (kIsWeb) return Container(); + + return Container( + child: Platform.isIOS + ? IconButton( + icon: (_showMaterialonIOS) + ? FaIcon(FontAwesomeIcons.apple) + : Icon(Icons.android), + onPressed: () { + setState(() { + _showMaterialonIOS = !_showMaterialonIOS; + }); + }, + ) + : null, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/theme.dart b/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/theme.dart new file mode 100644 index 00000000..1390dca5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/card_settings/plumbing/theme.dart @@ -0,0 +1,66 @@ +import 'package:adaptive_theme/adaptive_theme.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import 'scaffold.dart'; + +class ExampleTheme extends StatelessWidget { + const ExampleTheme({ + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return AdaptiveTheme( + initial: AdaptiveThemeMode.light, + light: _buildTheme(Brightness.light), + dark: _buildTheme(Brightness.dark), + builder: (context, theme) { + return MaterialApp( + title: 'Card Settings Example', + theme: theme, + home: ExampleScaffold(), + ); + }, + ); + } +} + +ThemeData _buildTheme(Brightness brightness) { + if (brightness == Brightness.dark) { + return ThemeData( + primarySwatch: Colors.teal, + brightness: brightness, + visualDensity: VisualDensity.adaptivePlatformDensity, + backgroundColor: Colors.black, + textTheme: GoogleFonts.paprikaTextTheme(TextTheme()), + fontFamily: GoogleFonts.getFont('Paprika').fontFamily, + ); + } else { + return ThemeData( + primaryColor: Colors.teal, // app header background + secondaryHeaderColor: Colors.indigo[400], // card header background + cardColor: Colors.white, // card field background + backgroundColor: Colors.indigo[100], // app background color + buttonColor: Colors.lightBlueAccent[100], // button background color + textTheme: TextTheme( + button: TextStyle(color: Colors.deepPurple[900]), // button text + subtitle1: TextStyle(color: Colors.grey[800]), // input text + headline6: TextStyle(color: Colors.white), // card header text + ), + primaryTextTheme: TextTheme( + headline6: TextStyle(color: Colors.lightBlue[50]), // app header text + ), + inputDecorationTheme: InputDecorationTheme( + labelStyle: TextStyle(color: Colors.indigo[400]), // style for labels + ), + fontFamily: GoogleFonts.getFont('Paprika').fontFamily, + // cardTheme: CardTheme( + // shape: RoundedRectangleBorder( + // side: BorderSide(width: 2, color: Colors.orange), + // borderRadius: BorderRadius.circular(20), + // ), + // ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/back_card_view.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/back_card_view.dart new file mode 100644 index 00000000..6764e3e9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/back_card_view.dart @@ -0,0 +1,68 @@ +import '../constants/constanst.dart'; +import '../provider/state_provider.dart'; +import 'package:flutter/material.dart'; +import '../components/card_logo.dart'; +import 'package:provider/provider.dart'; +import 'card_cvv.dart'; +import 'card_sign.dart'; + +class BackCardView extends StatelessWidget { + final height; + final decoration; + + BackCardView({this.height, this.decoration}); + + @override + Widget build(BuildContext context) { + final currentState = + Provider.of(context, listen: false).getCurrentState(); + return Container( + margin: EdgeInsets.only(bottom: 5), + height: height, + decoration: decoration, + child: Stack( + children: [ + Container( + margin: EdgeInsets.only(top: 25), + height: 35, + color: Colors.black, + ), + Align(alignment: Alignment.centerLeft, child: CardSign()), + AnimatedOpacity( + opacity: currentState != InputState.DONE ? 1 : 0, + duration: Duration(milliseconds: 300), + child: Align( + alignment: Alignment.centerRight, + child: Container( + margin: EdgeInsets.only(right: 30), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7.5), + border: Border.all( + color: + Colors.yellow, // <--- border color + width: 1.0, + ), + ), + child: Container( + height: 45, + width: 75, + ), + )), + ), + Align( + alignment: Alignment.centerRight, + child: Container( + margin: EdgeInsets.only(right: 30), + child: CardCVV(), + )), + Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.only(bottom: 10, right: 30), + child: CardLogo(), + )), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_cvv.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_cvv.dart new file mode 100644 index 00000000..10d11295 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_cvv.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import '../constants/constanst.dart'; +import '../provider/card_cvv_provider.dart'; +import 'package:provider/provider.dart'; + +class CardCVV extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, value, child) { + return Padding( + padding: const EdgeInsets.all(3.0), + child: Container( + height: 40, + width: 70, + color: Colors.white, + child: Center( + child: Text( + value.cardCVV, + style: kCVCTextStyle, + ), + ), + ), + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_logo.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_logo.dart new file mode 100644 index 00000000..4edcaa34 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_logo.dart @@ -0,0 +1,36 @@ +import '../util/util.dart'; +import 'package:flutter/material.dart'; +import '../constants/constanst.dart'; +import '../provider/card_number_provider.dart'; +import 'package:provider/provider.dart'; + +class CardLogo extends StatelessWidget { + @override + Widget build(BuildContext context) { + String cardNumber = Provider.of(context).cardNumber; + + CardCompany cardCompany = detectCardCompany(cardNumber); + + return Stack( + children: [ + AnimatedOpacity( + opacity: cardCompany == CardCompany.VISA ? 1 : 0, + child: visa, + duration: Duration(milliseconds: 200), + ), + AnimatedOpacity( + opacity: cardCompany == CardCompany.MASTER ? 1 : 0, + child: master, + duration: Duration(milliseconds: 200)), + AnimatedOpacity( + opacity: cardCompany == CardCompany.DISCOVER ? 1 : 0, + child: discover, + duration: Duration(milliseconds: 200)), + AnimatedOpacity( + opacity: cardCompany == CardCompany.AMERICAN_EXPRESS ? 1 : 0, + child: amex, + duration: Duration(milliseconds: 200)), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_name.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_name.dart new file mode 100644 index 00000000..51929b62 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_name.dart @@ -0,0 +1,18 @@ +import '../constants/captions.dart'; +import 'package:flutter/material.dart'; +import '../constants/constanst.dart'; +import '../provider/card_name_provider.dart'; +import 'package:provider/provider.dart'; + +class CardName extends StatelessWidget { + @override + Widget build(BuildContext context) { + final defaultName = + Provider.of(context).getCaption('NAME_SURNAME').toUpperCase(); + final String name = + Provider.of(context).cardName.toUpperCase(); + + return Text(name.isNotEmpty ? name : defaultName, + style: name.isNotEmpty ? kNametextStyle : kDefaultNameTextStyle); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_number.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_number.dart new file mode 100644 index 00000000..88d345b8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_number.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import '../provider/card_number_provider.dart'; +import 'package:provider/provider.dart'; + +import '../constants/constanst.dart'; + +class CardNumber extends StatelessWidget { + @override + Widget build(BuildContext context) { + String cardNumber = + Provider.of(context, listen: true).cardNumber; + String defaultNumber = ''; + + final numberLength = cardNumber.replaceAll(" ", "").length; + + for (int i = 1; i <= 16 - numberLength; i++) { + defaultNumber = 'X' + defaultNumber; + if (i % 4 == 0 && i != 16) { + defaultNumber = ' ' + defaultNumber; + } + } + + return Container( + child: Padding( + padding: const EdgeInsets.only(left: 5), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Row( + children: [ + Text( + cardNumber, + style: kCardNumberTextStyle, + ), + Text( + defaultNumber, + style: kCardDefaultTextStyle, + ) + ], + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_sign.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_sign.dart new file mode 100644 index 00000000..49f4dc67 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_sign.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import '../provider/card_name_provider.dart'; +import 'package:provider/provider.dart'; +import '../constants/constanst.dart'; + +class CardSign extends StatelessWidget { + const CardSign({ + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, provider, child) { + String cardName = provider.cardName; + + if (cardName.isNotEmpty) { + cardName = cardName + .split(' ') + .map((e) => e.isNotEmpty + ? '${e[0].toUpperCase()}${e.substring(1).toLowerCase()}' + : e) + .join(' '); + } + + return Container( + margin: EdgeInsets.only(left: 25), + height: 40, + width: 220, + color: Colors.grey, + child: Center( + child: Text( + cardName, + style: kSignTextStyle, + ), + ), + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_valid.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_valid.dart new file mode 100644 index 00000000..8373fa5b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/card_valid.dart @@ -0,0 +1,47 @@ +import '../constants/captions.dart'; +import 'package:flutter/material.dart'; +import '../provider/card_valid_provider.dart'; +import 'package:provider/provider.dart'; +import '../constants/constanst.dart'; + +class CardValid extends StatelessWidget { + @override + Widget build(BuildContext context) { + String inputCardValid = Provider.of(context).cardValid; + + var defaultCardValid = Provider.of(context) + .getCaption('MM_YY') + .substring(inputCardValid.length); + + inputCardValid = inputCardValid.replaceAll("/", ""); + + switch (inputCardValid.length) { + case 3: + inputCardValid = + inputCardValid[0] + inputCardValid[1] + '/' + inputCardValid[2]; + break; + case 4: + inputCardValid = inputCardValid[0] + + inputCardValid[1] + + '/' + + inputCardValid[2] + + inputCardValid[3]; + break; + } + + return Container( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + inputCardValid, + style: kValidtextStyle, + ), + Text( + defaultCardValid, + style: kDefaultValidTextStyle, + ) + ], + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/front_card_view.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/front_card_view.dart new file mode 100644 index 00000000..050c9697 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/front_card_view.dart @@ -0,0 +1,80 @@ +import '../constants/captions.dart'; +import 'package:flutter/material.dart'; +import '../components/yellow_border.dart'; +import '../constants/constanst.dart'; +import 'package:provider/provider.dart'; +import 'card_logo.dart'; +import 'card_name.dart'; +import 'card_number.dart'; +import 'card_valid.dart'; + +class FrontCardView extends StatelessWidget { + final height; + final decoration; + + FrontCardView({this.height, this.decoration}); + + @override + Widget build(BuildContext context) { + final captions = Provider.of(context); + + return Container( + margin: EdgeInsets.only(bottom: 5), + height: height, + decoration: decoration, + child: Padding( + padding: const EdgeInsets.all(15.0), + child: Stack( + children: [ + YellowBorder(), + Align( + alignment: Alignment.centerLeft, + child: CardNumber(), + ), + Align(alignment: Alignment.topRight, child: CardLogo()), + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + captions.getCaption('CARDHOLDER_NAME').toUpperCase(), + style: kTextStyle, + ), + SizedBox( + height: 10, + ), + CardName(), + ], + ), + ), + ), + Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + captions.getCaption('VALID_THRU').toUpperCase(), + style: kTextStyle, + ), + SizedBox( + height: 10, + ), + CardValid(), + ], + ), + ), + ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/input_view_pager.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/input_view_pager.dart new file mode 100644 index 00000000..e07b95f0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/input_view_pager.dart @@ -0,0 +1,244 @@ +import '../constants/captions.dart'; +import '../util/util.dart'; +import 'package:flutter/material.dart'; +import '../constants/constanst.dart'; +import '../provider/card_cvv_provider.dart'; +import '../provider/card_name_provider.dart'; +import '../provider/card_valid_provider.dart'; +import '../provider/state_provider.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import '../provider/card_number_provider.dart'; + +class InputViewPager extends StatefulWidget { + final pageController; + final isAutoFoucus; + + InputViewPager({this.pageController, this.isAutoFoucus}); + + @override + _InputViewPagerState createState() => _InputViewPagerState(); +} + +class _InputViewPagerState extends State { + final List focusNodes = [ + FocusNode(), + FocusNode(), + FocusNode(), + FocusNode(), + ]; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + final captions = Provider.of(context); + + final titleMap = { + 0: captions.getCaption('CARD_NUMBER'), + 1: captions.getCaption('CARDHOLDER_NAME'), + 2: captions.getCaption('VALID_THRU'), + 3: captions.getCaption('SECURITY_CODE_CVC'), + }; + + Provider.of(context).addListener(() { + int index = Provider.of(context, listen: false) + .getCurrentState() + .index; + + if (index < focusNodes.length) { + FocusScope.of(context).requestFocus(focusNodes[index]); + } else { + FocusScope.of(context).unfocus(); + SystemChannels.textInput.invokeMethod('TextInput.hide'); + } + }); + + return Container( + height: 90, + child: PageView.builder( + physics: NeverScrollableScrollPhysics(), + controller: widget.pageController, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: InputForm( + isAutoFocus: widget.isAutoFoucus, + focusNode: focusNodes[index], + title: titleMap[index], + index: index, + pageController: widget.pageController), + ); + }, + itemCount: titleMap.length)); + } +} + +class InputForm extends StatefulWidget { + final String title; + final int index; + final PageController pageController; + final FocusNode focusNode; + final isAutoFocus; + + InputForm( + {@required this.title, + this.index, + this.pageController, + this.focusNode, + this.isAutoFocus}); + + @override + _InputFormState createState() => _InputFormState(); +} + +class _InputFormState extends State { + var opacicy = 0.3; + + int maxLength; + TextInputType textInputType; + TextEditingController textController = TextEditingController(); + + void onChange() { + setState(() { + if (widget.index == widget.pageController.page.round()) { + opacicy = 1; + } else { + opacicy = 0.3; + } + }); + } + + String value; + + @override + void initState() { + super.initState(); + + int index = Provider.of(context, listen: false) + .getCurrentState() + .index; + + if (widget.index == index) { + opacicy = 1; + } + + widget.pageController.addListener(onChange); + + if (widget.index == InputState.NUMBER.index) { + maxLength = 19; + textInputType = TextInputType.number; + } else if (widget.index == InputState.NAME.index) { + maxLength = 20; + textInputType = TextInputType.text; + } else if (widget.index == InputState.VALIDATE.index) { + maxLength = 5; + textInputType = TextInputType.number; + } else if (widget.index == InputState.CVV.index) { + String cardNumber = + Provider.of(context, listen: false).cardNumber; + + if (CardCompany.AMERICAN_EXPRESS == detectCardCompany(cardNumber)) { + maxLength = 4; + } else { + maxLength = 3; + } + textInputType = TextInputType.number; + } + } + + @override + void dispose() { + widget.pageController.removeListener(onChange); + + super.dispose(); + } + + var isInit = false; + + @override + Widget build(BuildContext context) { + String textValue = ""; + + if (widget.index == InputState.NUMBER.index) { + textValue = + Provider.of(context, listen: false).cardNumber; + } else if (widget.index == InputState.NAME.index) { + textValue = + Provider.of(context, listen: false).cardName; + } else if (widget.index == InputState.VALIDATE.index) { + textValue = + Provider.of(context, listen: false).cardValid; + } else if (widget.index == InputState.CVV.index) { + textValue = Provider.of(context).cardCVV; + } + + int index = Provider.of(context, listen: false) + .getCurrentState() + .index; + + return Opacity( + opacity: opacicy, + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.title, + style: TextStyle(fontSize: 12, color: Colors.black38), + ), + SizedBox( + height: 5, + ), + TextField( + autocorrect: false, + autofocus: widget.isAutoFocus && widget.index == index, + controller: textController + ..value = textController.value.copyWith( + text: textValue, + selection: TextSelection.fromPosition( + TextPosition(offset: textValue.length), + ), + ), + focusNode: widget.focusNode, + keyboardType: textInputType, + maxLength: maxLength, + onChanged: (String newValue) { + if (widget.index == InputState.NUMBER.index) { + Provider.of(context, listen: false) + .setNumber(newValue); + } else if (widget.index == InputState.NAME.index) { + Provider.of(context, listen: false) + .setName(newValue); + } else if (widget.index == InputState.VALIDATE.index) { + Provider.of(context, listen: false) + .setValid(newValue); + } else if (widget.index == InputState.CVV.index) { + Provider.of(context, listen: false) + .setCVV(newValue); + } + }, + decoration: InputDecoration( + isDense: true, + counter: SizedBox( + height: 0, + ), + contentPadding: + const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10), + border: OutlineInputBorder( + borderSide: BorderSide(width: 1, color: Colors.black38), + borderRadius: BorderRadius.circular(5)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(width: 1, color: Colors.black38), + borderRadius: BorderRadius.circular(5)), + ), + ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/my_appbar.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/my_appbar.dart new file mode 100644 index 00000000..65c4bb55 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/my_appbar.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +class MyAppbar extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: Icon(Icons.clear, color: Colors.black), onPressed: null), + Container( + padding: EdgeInsets.symmetric(vertical: 5, horizontal: 15), + decoration: BoxDecoration( + color: const Color(0xFFDADFE5), + borderRadius: BorderRadius.circular(20)), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + 'Scan your card ', + style: + TextStyle(color: Colors.black, fontWeight: FontWeight.bold), + ), + Icon(Icons.camera_alt) + ], + ), + ) + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/reset_button.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/reset_button.dart new file mode 100644 index 00000000..d99c9e1a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/reset_button.dart @@ -0,0 +1,55 @@ +import '../constants/captions.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class ResetButton extends StatefulWidget { + final Function onTap; + final decoration; + final textStyle; + + ResetButton({this.onTap, this.decoration, this.textStyle}); + + @override + _ResetButtonState createState() => _ResetButtonState(); +} + +class _ResetButtonState extends State { + var pressed = false; + + @override + Widget build(BuildContext context) { + final captions = Provider.of(context); + + return GestureDetector( + onTap: widget.onTap as void Function(), + onTapDown: (_) { + setState(() { + pressed = true; + }); + }, + onTapUp: (_) { + setState(() { + pressed = false; + }); + }, + child: AnimatedContainer( + margin: EdgeInsets.symmetric(horizontal: pressed ? 2.5 : 0), + duration: Duration(milliseconds: 100), + width: 95 - (pressed ? 5.0 : 0.0), + height: 45 - (pressed ? 5.0 : 0.0), + decoration: widget.decoration, + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.refresh, + color: Colors.white, + ), + Text(captions.getCaption('RESET'), style: widget.textStyle) + ], + ), + )), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/round_button.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/round_button.dart new file mode 100644 index 00000000..d567c67d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/round_button.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../constants/constanst.dart'; +import '../provider/state_provider.dart'; + +class RoundButton extends StatefulWidget { + final Function onTap; + final buttonTitle; + final decoration; + final textStyle; + + RoundButton({this.onTap, this.buttonTitle, this.decoration, this.textStyle}); + + @override + _RoundButtonState createState() => _RoundButtonState(); +} + +class _RoundButtonState extends State { + var pressed = false; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: widget.onTap as void Function(), + onTapDown: (_) { + final currentState = Provider.of(context, listen: false) + .getCurrentState(); + + if (currentState == InputState.DONE) { + return; + } + + setState(() { + pressed = true; + }); + }, + onTapUp: (_) { + final currentState = Provider.of(context, listen: false) + .getCurrentState(); + + if (currentState == InputState.DONE) { + return; + } + + setState(() { + pressed = false; + }); + }, + child: AnimatedContainer( + margin: EdgeInsets.symmetric(horizontal: pressed ? 2.5 : 0), + duration: Duration(milliseconds: 100), + width: 75 - (pressed ? 5.0 : 0.0), + height: 40 - (pressed ? 5.0 : 0.0), + decoration: widget.decoration, + child: Center( + child: Text(widget.buttonTitle, + style: widget.textStyle.copyWith( + color: !pressed + ? widget.textStyle.color + : widget.textStyle.color.withOpacity(0.2))), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/yellow_border.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/yellow_border.dart new file mode 100644 index 00000000..8c71ec1b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/components/yellow_border.dart @@ -0,0 +1,120 @@ +import 'package:flutter/material.dart'; +import '../provider/card_name_provider.dart'; +import '../provider/state_provider.dart'; +import '../util/util.dart'; +import 'package:provider/provider.dart'; + +import '../constants/constanst.dart'; + +class YellowBorder extends StatelessWidget { + @override + Widget build(BuildContext context) { + final currentState = + Provider.of(context, listen: true).getCurrentState(); + + final align = getAlign(currentState); + final height = getHeight(currentState); + final width = getWidth(context, currentState); + final margin = getMargin(currentState); + + return AnimatedOpacity( + opacity: currentState == InputState.DONE ? 0 : 1, + duration: Duration(milliseconds: 300), + child: AnimatedAlign( + child: AnimatedContainer( + margin: margin, + duration: Duration(milliseconds: 150), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7.5), + border: Border.all( + color: Colors.yellow, // <--- border color + width: 1.0, + ), + ), + height: height, + width: width, + ), + alignment: align, + duration: Duration(milliseconds: 300), + ), + ); + } + + Alignment getAlign(currentState) { + var align = Alignment.centerLeft; + switch (currentState) { + case InputState.NUMBER: + align = Alignment.centerLeft; + break; + case InputState.NAME: + align = Alignment.bottomLeft; + break; + case InputState.CVV: + case InputState.VALIDATE: + case InputState.DONE: + align = Alignment.bottomRight; + break; + } + return align; + } + + double getHeight(InputState currentState) { + var height = 0.0; + switch (currentState) { + case InputState.NUMBER: + height = textSize('1234 5678 1234', kCardNumberTextStyle).height + 15; + break; + case InputState.NAME: + height = textSize('hello world', kNametextStyle).height + 15; + break; + case InputState.CVV: + case InputState.VALIDATE: + case InputState.DONE: + height = textSize('12/12', kNametextStyle).height + 15; + break; + } + return height; + } + + double getWidth(context, currentState) { + var width = 330.0; + switch (currentState) { + case InputState.NUMBER: + width = + textSize('XXXX XXXX XXXX XXXX', kCardDefaultTextStyle).width + 10; + break; + case InputState.NAME: + String name = Provider.of(context).cardName; + if (name.isEmpty) { + name = 'NAME SURNAME'; + } + width = textSize(name.toUpperCase(), kNametextStyle).width + 10; + break; + case InputState.CVV: + case InputState.VALIDATE: + width = textSize('MM/YY', kNametextStyle).width + 10; + break; + } + return width; + } + + getMargin(InputState currentState) { + var lefrMargin = 0.0; + var rightMargin = 0.0; + switch (currentState) { + case InputState.NUMBER: + break; + case InputState.NAME: + lefrMargin = 2.5; + break; + case InputState.CVV: + case InputState.DONE: + break; + case InputState.VALIDATE: + rightMargin = 3; + + break; + } + return EdgeInsets.only(left: lefrMargin, right: rightMargin); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/constants/captions.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/constants/captions.dart new file mode 100644 index 00000000..59ca2dab --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/constants/captions.dart @@ -0,0 +1,26 @@ +class Captions { + final Map _default = { + 'PREV': 'Prev', + 'NEXT': 'Next', + 'DONE': 'Done', + 'CARD_NUMBER': 'Card Number', + 'CARDHOLDER_NAME': 'Cardholder Name', + 'VALID_THRU': 'Valid Thru', + 'SECURITY_CODE_CVC': 'Security Code (CVC)', + 'NAME_SURNAME': 'Name Surname', + 'MM_YY': 'MM/YY', + 'RESET': 'Reset', + }; + + Map _captions; + + Captions({customCaptions}) { + _captions = {}; + _captions.addAll(_default); + if (customCaptions != null) _captions.addAll(customCaptions); + } + + String getCaption(String key) { + return _captions.containsKey(key) ? _captions[key] : key; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/constants/constanst.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/constants/constanst.dart new file mode 100644 index 00000000..f30660c6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/constants/constanst.dart @@ -0,0 +1,119 @@ +import 'package:flutter/material.dart'; + +final kCardNumberTextStyle = TextStyle( + color: Colors.white, + fontFamily: 'U and I', + fontWeight: FontWeight.bold, + package: 'credit_card_input_form', + letterSpacing: 1.5, + fontSize: 25, +); + +final kCardDefaultTextStyle = TextStyle( + color: Colors.grey, + fontFamily: 'U and I', + package: 'credit_card_input_form', + fontSize: 25, + letterSpacing: 1, +); + +final kCVCTextStyle = TextStyle( + color: Colors.black, + fontFamily: 'Satisfy', + fontWeight: FontWeight.bold, + package: 'credit_card_input_form', + fontSize: 20, +); + +final kTextStyle = TextStyle( + fontSize: 8, + fontWeight: FontWeight.bold, + color: Colors.white, + fontFamily: 'U and I', + package: 'credit_card_input_form', +); + +const kNametextStyle = TextStyle( + fontSize: 15, + color: Colors.white, + fontFamily: 'U and I', + package: 'credit_card_input_form', +); + +const kDefaultNameTextStyle = TextStyle( + fontSize: 15, + color: Colors.grey, + fontFamily: 'U and I', + package: 'credit_card_input_form', +); + +const kValidtextStyle = TextStyle( + fontSize: 15, + letterSpacing: 2, + color: Colors.white, + package: 'credit_card_input_form', + fontFamily: 'U and I', +); + +const kDefaultValidTextStyle = TextStyle( + fontSize: 15, + color: Colors.grey, + fontFamily: 'U and I', + package: 'credit_card_input_form', +); + +const kSignTextStyle = TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Satisfy', + package: 'credit_card_input_form', +); + +const kDefaultButtonTextStyle = + TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 15); + +const defaultNextPrevButtonDecoration = BoxDecoration( + boxShadow: [ + BoxShadow(color: Colors.black54, blurRadius: 5.0, offset: Offset(0, 5)) + ], + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + bottomLeft: Radius.circular(30), + bottomRight: Radius.circular(30)), + gradient: LinearGradient( + colors: [ + const Color(0xff6c16c7), + const Color(0xFFB16B92), + ], + begin: const FractionalOffset(0.0, 0.0), + end: const FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp), +); + +const defaultResetButtonDecoration = BoxDecoration( + boxShadow: [ + BoxShadow(color: Colors.black54, blurRadius: 5.0, offset: Offset(0, 5)) + ], + borderRadius: BorderRadius.all(Radius.circular(30)), + gradient: LinearGradient( + colors: [ + const Color(0xff6c16c7), + const Color(0xFFB16B92), + ], + begin: const FractionalOffset(0.0, 0.0), + end: const FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp), +); + +const defaultCardDecoration = BoxDecoration( + boxShadow: [ + BoxShadow(color: Colors.black54, blurRadius: 15.0, offset: Offset(0, 8)) + ], + color: Color(0xFF5D5D5E), + borderRadius: BorderRadius.all(Radius.circular(15))); + +enum InputState { NUMBER, NAME, VALIDATE, CVV, DONE } + +enum CardCompany { VISA, MASTER, AMERICAN_EXPRESS, DISCOVER, OTHER } diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/credit_card_input_form.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/credit_card_input_form.dart new file mode 100644 index 00000000..c080e043 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/credit_card_input_form.dart @@ -0,0 +1,325 @@ +import './components/reset_button.dart'; +import 'package:flip_card/flip_card.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import './components/back_card_view.dart'; +import './components/front_card_view.dart'; +import './components/input_view_pager.dart'; +import './components/round_button.dart'; +import './constants/constanst.dart'; +import './model/card_info.dart'; +import './provider/card_cvv_provider.dart'; +import './provider/card_name_provider.dart'; +import './provider/card_number_provider.dart'; +import './provider/card_valid_provider.dart'; +import './provider/state_provider.dart'; +import 'package:provider/provider.dart'; + +import 'constants/captions.dart'; +import 'constants/constanst.dart'; + +typedef CardInfoCallback = void Function( + InputState currentState, CardInfo cardInfo); + +class CreditCardInputForm extends StatelessWidget { + CreditCardInputForm( + {this.onStateChange, + this.cardHeight, + this.frontCardDecoration, + this.backCardDecoration, + this.showResetButton = true, + this.customCaptions, + this.cardNumber = '', + this.cardName = '', + this.cardCVV = '', + this.cardValid = '', + this.initialAutoFocus = true, + this.intialCardState = InputState.NUMBER, + this.nextButtonTextStyle = kDefaultButtonTextStyle, + this.prevButtonTextStyle = kDefaultButtonTextStyle, + this.resetButtonTextStyle = kDefaultButtonTextStyle, + this.nextButtonDecoration = defaultNextPrevButtonDecoration, + this.prevButtonDecoration = defaultNextPrevButtonDecoration, + this.resetButtonDecoration = defaultResetButtonDecoration}); + + final Function onStateChange; + final double cardHeight; + final BoxDecoration frontCardDecoration; + final BoxDecoration backCardDecoration; + final bool showResetButton; + final Map customCaptions; + final BoxDecoration nextButtonDecoration; + final BoxDecoration prevButtonDecoration; + final BoxDecoration resetButtonDecoration; + final TextStyle nextButtonTextStyle; + final TextStyle prevButtonTextStyle; + final TextStyle resetButtonTextStyle; + final String cardNumber; + final String cardName; + final String cardCVV; + final String cardValid; + final initialAutoFocus; + final InputState intialCardState; + + @override + Widget build(BuildContext context) { + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => StateProvider(intialCardState), + ), + ChangeNotifierProvider( + create: (context) => CardNumberProvider(cardNumber), + ), + ChangeNotifierProvider( + create: (context) => CardNameProvider(cardName), + ), + ChangeNotifierProvider( + create: (context) => CardValidProvider(cardValid), + ), + ChangeNotifierProvider( + create: (context) => CardCVVProvider(cardCVV), + ), + Provider( + create: (_) => Captions(customCaptions: customCaptions), + ), + ], + child: CreditCardInputImpl( + onCardModelChanged: + onStateChange as void Function(InputState, CardInfo), + backDecoration: backCardDecoration, + frontDecoration: frontCardDecoration, + cardHeight: cardHeight, + initialAutoFocus: initialAutoFocus, + showResetButton: showResetButton, + prevButtonDecoration: prevButtonDecoration, + nextButtonDecoration: nextButtonDecoration, + resetButtonDecoration: resetButtonDecoration, + prevButtonTextStyle: prevButtonTextStyle, + nextButtonTextStyle: nextButtonTextStyle, + resetButtonTextStyle: resetButtonTextStyle, + initialCardState: intialCardState, + ), + ); + } +} + +class CreditCardInputImpl extends StatefulWidget { + final CardInfoCallback onCardModelChanged; + final double cardHeight; + final BoxDecoration frontDecoration; + final BoxDecoration backDecoration; + final bool showResetButton; + final BoxDecoration nextButtonDecoration; + final BoxDecoration prevButtonDecoration; + final BoxDecoration resetButtonDecoration; + final TextStyle nextButtonTextStyle; + final TextStyle prevButtonTextStyle; + final TextStyle resetButtonTextStyle; + final InputState initialCardState; + final initialAutoFocus; + + CreditCardInputImpl( + {this.onCardModelChanged, + this.cardHeight, + this.showResetButton, + this.frontDecoration, + this.backDecoration, + this.nextButtonTextStyle, + this.prevButtonTextStyle, + this.resetButtonTextStyle, + this.nextButtonDecoration, + this.prevButtonDecoration, + this.initialCardState, + this.initialAutoFocus, + this.resetButtonDecoration}); + + @override + _CreditCardInputImplState createState() => _CreditCardInputImplState(); +} + +class _CreditCardInputImplState extends State { + PageController pageController; + + final GlobalKey cardKey = GlobalKey(); + + final cardHorizontalpadding = 12; + final cardRatio = 16.0 / 9.0; + + var _currentState; + + @override + void initState() { + super.initState(); + + _currentState = widget.initialCardState; + + pageController = PageController( + viewportFraction: 0.92, + initialPage: widget.initialCardState.index, + ); + } + + @override + Widget build(BuildContext context) { + final newState = Provider.of(context).getCurrentState(); + + final name = Provider.of(context).cardName; + + final cardNumber = Provider.of(context).cardNumber; + + final valid = Provider.of(context).cardValid; + + final cvv = Provider.of(context).cardCVV; + + final captions = Provider.of(context); + + if (newState != _currentState) { + _currentState = newState; + + Future(() { + widget.onCardModelChanged( + _currentState, + CardInfo( + name: name, cardNumber: cardNumber, validate: valid, cvv: cvv)); + }); + } + + double cardWidth = + MediaQuery.of(context).size.width - (2 * cardHorizontalpadding); + + double cardHeight; + if (widget.cardHeight != null && widget.cardHeight > 0) { + cardHeight = widget.cardHeight; + } else { + cardHeight = cardWidth / cardRatio; + } + + final frontDecoration = widget.frontDecoration != null + ? widget.frontDecoration + : defaultCardDecoration; + final backDecoration = widget.backDecoration != null + ? widget.backDecoration + : defaultCardDecoration; + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: FlipCard( + speed: 300, + flipOnTouch: _currentState == InputState.DONE, + key: cardKey, + front: + FrontCardView(height: cardHeight, decoration: frontDecoration), + back: BackCardView(height: cardHeight, decoration: backDecoration), + ), + ), + Stack( + children: [ + AnimatedOpacity( + opacity: _currentState == InputState.DONE ? 0 : 1, + duration: Duration(milliseconds: 500), + child: InputViewPager( + isAutoFoucus: widget.initialAutoFocus, + pageController: pageController, + ), + ), + Align( + alignment: Alignment.center, + child: AnimatedOpacity( + opacity: widget.showResetButton && + _currentState == InputState.DONE + ? 1 + : 0, + duration: Duration(milliseconds: 500), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ResetButton( + decoration: widget.resetButtonDecoration, + textStyle: widget.resetButtonTextStyle, + onTap: () { + if (!widget.showResetButton) { + return; + } + + Provider.of(context, listen: false) + .moveFirstState(); + pageController.animateToPage(0, + duration: Duration(milliseconds: 300), + curve: Curves.easeIn); + + if (!cardKey.currentState.isFront) { + cardKey.currentState.toggleCard(); + } + }, + ), + ))), + ], + ), + Row(mainAxisAlignment: MainAxisAlignment.end, children: [ + AnimatedOpacity( + opacity: _currentState == InputState.NUMBER || + _currentState == InputState.DONE + ? 0 + : 1, + duration: Duration(milliseconds: 500), + child: RoundButton( + decoration: widget.prevButtonDecoration, + textStyle: widget.prevButtonTextStyle, + buttonTitle: captions.getCaption('PREV'), + onTap: () { + if (InputState.DONE == _currentState) { + return; + } + + if (InputState.NUMBER != _currentState) { + pageController.previousPage( + duration: Duration(milliseconds: 300), + curve: Curves.easeIn); + } + + if (InputState.CVV == _currentState) { + cardKey.currentState.toggleCard(); + } + Provider.of(context, listen: false) + .movePrevState(); + }), + ), + SizedBox( + width: 10, + ), + AnimatedOpacity( + opacity: _currentState == InputState.DONE ? 0 : 1, + duration: Duration(milliseconds: 500), + child: RoundButton( + decoration: widget.nextButtonDecoration, + textStyle: widget.nextButtonTextStyle, + buttonTitle: _currentState == InputState.CVV || + _currentState == InputState.DONE + ? captions.getCaption('DONE') + : captions.getCaption('NEXT'), + onTap: () { + if (InputState.CVV != _currentState) { + pageController.nextPage( + duration: Duration(milliseconds: 300), + curve: Curves.easeIn); + } + + if (InputState.VALIDATE == _currentState) { + cardKey.currentState.toggleCard(); + } + + Provider.of(context, listen: false) + .moveNextState(); + }), + ), + SizedBox( + width: 25, + ) + ]) + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/model/card_info.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/model/card_info.dart new file mode 100644 index 00000000..90691f41 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/model/card_info.dart @@ -0,0 +1,13 @@ +class CardInfo { + String cardNumber; + String name; + String validate; + String cvv; + + CardInfo({this.cardNumber, this.name, this.validate, this.cvv}); + + @override + String toString() { + return "cardNumber=$cardNumber, name=$name, validate=$validate, cvv=$cvv"; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_cvv_provider.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_cvv_provider.dart new file mode 100644 index 00000000..4544566a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_cvv_provider.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +class CardCVVProvider with ChangeNotifier { + var _cardCVV; + + CardCVVProvider(initValue) { + _cardCVV = initValue; + } + + void setCVV(String cvv) { + _cardCVV = cvv; + notifyListeners(); + } + + get cardCVV => _cardCVV; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_name_provider.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_name_provider.dart new file mode 100644 index 00000000..6161245d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_name_provider.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +class CardNameProvider with ChangeNotifier { + var _cardName; + + CardNameProvider(initValue) { + _cardName = initValue; + } + + void setName(String name) { + _cardName = name; + notifyListeners(); + } + + get cardName => _cardName; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_number_provider.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_number_provider.dart new file mode 100644 index 00000000..42f161ae --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_number_provider.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +class CardNumberProvider with ChangeNotifier { + var _cardNumber; + + CardNumberProvider(initValue) { + _cardNumber = addSpaceToCardNumber(initValue); + } + + void setNumber(String newValue) { + _cardNumber = addSpaceToCardNumber(newValue); + + notifyListeners(); + } + + String addSpaceToCardNumber(String newValue) { + newValue = newValue.replaceAll(RegExp(r'[^0-9]'), ''); + + if (newValue.isNotEmpty && newValue[newValue.length - 1] == ' ') { + return newValue.substring(0, newValue.length - 1); + } else { + newValue = newValue.replaceAll(" ", ""); + String cardNumber = ""; + + for (int i = 1; i <= newValue.length; i++) { + cardNumber = cardNumber + newValue[i - 1]; + if (i % 4 == 0 && i != newValue.length) { + cardNumber = cardNumber + ' '; + } + } + return cardNumber; + } + } + + get cardNumber => _cardNumber; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_valid_provider.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_valid_provider.dart new file mode 100644 index 00000000..55d6796b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/card_valid_provider.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class CardValidProvider with ChangeNotifier { + var _cardValid; + + CardValidProvider(initValue) { + _cardValid = initValue; + } + + void setValid(String newValue) { + if (newValue.length == 3) { + if (newValue.contains("/")) { + _cardValid = newValue.substring(0, 2); + } else { + _cardValid = newValue.substring(0, 2) + "/" + newValue.substring(2); + } + } else { + _cardValid = newValue; + } + notifyListeners(); + } + + get cardValid => _cardValid; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/state_provider.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/state_provider.dart new file mode 100644 index 00000000..3cc6c5a6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/provider/state_provider.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import '../constants/constanst.dart'; + +class StateProvider with ChangeNotifier { + InputState _currentState; + + StateProvider(initValue) { + _currentState = initValue; + } + + final _states = [ + InputState.NUMBER, + InputState.NAME, + InputState.VALIDATE, + InputState.CVV, + InputState.DONE + ]; + + void moveNextState() { + if (_currentState.index < _states.length - 1) { + _currentState = _states[_currentState.index + 1]; + notifyListeners(); + } + } + + void moveFirstState() { + _currentState = _states[0]; + notifyListeners(); + } + + void movePrevState() { + if (_currentState.index > 0) { + _currentState = _states[_currentState.index - 1]; + notifyListeners(); + } + } + + InputState getCurrentState() { + return _currentState; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/util/util.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/util/util.dart new file mode 100644 index 00000000..e769ca72 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/lib/util/util.dart @@ -0,0 +1,83 @@ +import '../constants/constanst.dart'; +import 'package:flutter/material.dart'; + +Size textSize(String text, TextStyle style) { + final TextPainter textPainter = TextPainter( + text: TextSpan(text: text, style: style), + maxLines: 1, + textDirection: TextDirection.ltr) + ..layout(minWidth: 0, maxWidth: double.infinity); + return textPainter.size; +} + +final master = Image.asset('images/mastercard.png', width: 50); +final visa = Image.asset('images/visacard.png', width: 50); +final discover = Image.asset('images/discover.png', width: 50); + +final amex = Image.asset('images/amex.png', width: 50); + +final others = Container(); + +final Map>> cardNumPatterns = + >>{ + CardCompany.VISA: >{ + ['4'], + }, + CardCompany.AMERICAN_EXPRESS: >{ + ['34'], + ['37'], + }, + CardCompany.DISCOVER: >{ + ['6011'], + ['622126', '622925'], + ['644', '649'], + ['65'] + }, + CardCompany.MASTER: >{ + ['51', '55'], + ['2221', '2229'], + ['223', '229'], + ['23', '26'], + ['270', '271'], + ['2720'], + }, +}; + +CardCompany detectCardCompany(String cardNumber) { + //Default card type is other + CardCompany cardType = CardCompany.OTHER; + + if (cardNumber.isEmpty) { + return cardType; + } + + cardNumPatterns.forEach( + (CardCompany type, Set> patterns) { + for (List patternRange in patterns) { + String ccPatternStr = cardNumber.replaceAll(RegExp(r'\s+\b|\b\s'), ''); + final int rangeLen = patternRange[0].length; + if (rangeLen < cardNumber.length) { + ccPatternStr = ccPatternStr.substring(0, rangeLen); + } + + if (patternRange.length > 1) { + final int ccPrefixAsInt = int.parse(ccPatternStr); + final int startPatternPrefixAsInt = int.parse(patternRange[0]); + final int endPatternPrefixAsInt = int.parse(patternRange[1]); + if (ccPrefixAsInt >= startPatternPrefixAsInt && + ccPrefixAsInt <= endPatternPrefixAsInt) { + cardType = type; + break; + } + } else { + if (ccPatternStr == patternRange[0]) { + cardType = type; + break; + } + } + } + }, + ); + + return cardType; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/main.dart b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/main.dart new file mode 100644 index 00000000..c6da1a0f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/credit_card_input_form/main.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; + +import './lib/credit_card_input_form.dart'; + +void main() { + runApp(CreditCardInputFormApp()); +} + +class CreditCardInputFormApp extends StatefulWidget { + @override + _CreditCardInputFormAppState createState() => _CreditCardInputFormAppState(); +} + +class _CreditCardInputFormAppState extends State { + // translate and customize captions + final Map customCaptions = { + 'PREV': 'Prev', + 'NEXT': 'Next', + 'DONE': 'Done', + 'CARD_NUMBER': 'Card Number', + 'CARDHOLDER_NAME': 'Cardholder Name', + 'VALID_THRU': 'Valid Thru', + 'SECURITY_CODE_CVC': 'Security Code (CVC)', + 'NAME_SURNAME': 'Name Surname', + 'MM_YY': 'MM/YY', + 'RESET': 'Reset', + }; + + final buttonStyle = BoxDecoration( + borderRadius: BorderRadius.circular(30.0), + gradient: LinearGradient( + colors: [ + const Color(0xfffcdf8a), + const Color(0xfff38381), + ], + begin: const FractionalOffset(0.0, 0.0), + end: const FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp), + ); + + final cardDecoration = BoxDecoration( + boxShadow: [ + BoxShadow(color: Colors.black54, blurRadius: 15.0, offset: Offset(0, 8)) + ], + gradient: LinearGradient( + colors: [ + Colors.red, + Colors.blue, + ], + begin: const FractionalOffset(0.0, 0.0), + end: const FractionalOffset(1.0, 0.0), + stops: [0.0, 1.0], + tileMode: TileMode.clamp), + borderRadius: BorderRadius.all(Radius.circular(15))); + + final buttonTextStyle = + TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + body: SafeArea( + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + child: Stack(children: [ + CreditCardInputForm( + showResetButton: true, + onStateChange: (currentState, cardInfo) { + print(currentState); + print(cardInfo); + }, + // initialAutoFocus: false, + // customCaptions: customCaptions, + // cardCVV: '222', + // cardName: 'Jeongtae Kim', + // cardNumber: '1111111111111111', + // cardValid: '12/12', + // intialCardState: InputState.DONE, + // frontCardDecoration: cardDecoration, + // backCardDecoration: cardDecoration, + // prevButtonStyle: buttonStyle, + // nextButtonStyle: buttonStyle, + // prevButtonTextStyle: buttonTextStyle, + // nextButtonTextStyle: buttonTextStyle, + // resetButtonTextStyle: buttonTextStyle, + ), + ]), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_container.dart b/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_container.dart new file mode 100644 index 00000000..87dd6a28 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_container.dart @@ -0,0 +1,397 @@ +import 'dart:async'; + +import 'package:rect_getter/rect_getter.dart'; + +import './direct_select_list.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +// import 'package:rect_getter/rect_getter.dart'; + +/// Root widget for direct select. +/// This widget displays lists of direct selects. +/// Usage Example +/// +/// return Scaffold( +/// body: DirectSelectContainer( +/// child: Padding( +/// padding: const EdgeInsets.all(16.0), +/// child: Column( +/// mainAxisSize: MainAxisSize.min, +/// verticalDirection: VerticalDirection.down, +/// children: [ +/// SizedBox(height: 150.0), +/// Padding( +/// padding: const EdgeInsets.all(8.0), +/// child: Column( +/// children: [ +/// Container( +/// alignment: AlignmentDirectional.centerStart, +/// margin: EdgeInsets.only(left: 4), +/// child: Text("City")), +/// Padding( +/// padding: const EdgeInsets.fromLTRB(0, 8, 0, 0), +/// child: Card( +/// child: Row( +/// mainAxisSize: MainAxisSize.max, +/// children: [ +/// Expanded( +/// child: Padding( +/// child: DirectSelectList( +/// values: _cities, +/// defaultItemIndex: 3, +/// itemBuilder: (String value) => getDropDownMenuItem(value), +/// focusedItemDecoration: _getDslDecoration(), +/// onItemSelectedListener: (item, context) { +/// Scaffold.of(context).showSnackBar(SnackBar(content: Text(item))); +/// }), +/// padding: EdgeInsets.only(left: 12))), +/// Padding( +/// padding: EdgeInsets.only(right: 8), +/// child: Icon( +/// Icons.unfold_more, +/// color: Colors.black38, +/// ), +/// ) +/// ], +/// )), +/// ), +/// ], +/// ), +/// ), +/// ], +/// ), +/// ), +/// ), +/// ); +/// +class DirectSelectContainer extends StatefulWidget { + ///Actually content of screen + final Widget child; + + ///How fast list is scrolled + final int dragSpeedMultiplier; + + ///Decoration for the DSL container + final Decoration decoration; + + const DirectSelectContainer({ + Key key, + @required this.child, + this.dragSpeedMultiplier = 2, + this.decoration, + }) : super(key: key); + + @override + State createState() { + return DirectSelectContainerState(); + } + + static DirectSelectGestureEventListeners of(BuildContext context) { + if (context.dependOnInheritedWidgetOfExactType< + _InheritedContainerListeners>() == + null) { + throw Exception( + "A DirectSelectList must inherit a DirectSelectContainer!"); + } + return context + .dependOnInheritedWidgetOfExactType<_InheritedContainerListeners>() + .listeners; + } +} + +class DirectSelectContainerState extends State + with SingleTickerProviderStateMixin + implements DirectSelectGestureEventListeners { + bool isOverlayVisible = false; + + ScrollController _scrollController; + DirectSelectList _currentList = + DirectSelectList(itemBuilder: (val) => null, values: []); + double _currentScrollLocation = 0; + + double _adjustedTopOffset = 0.0; + + AnimationController fadeAnimationController; + + int lastSelectedItem = 0; + + double listPadding = 0.0; + + final scrollToListElementAnimationDuration = Duration(milliseconds: 200); + final fadeAnimationDuration = Duration(milliseconds: 200); + + @override + void initState() { + super.initState(); + + fadeAnimationController = AnimationController( + duration: fadeAnimationDuration, + vsync: this, + ); + } + + @override + Widget build(BuildContext context) { + double topOffset = 0.0; + RenderObject object = context.findRenderObject(); + if (object?.parentData is ContainerBoxParentData) { + topOffset = (object.parentData as ContainerBoxParentData).offset.dy; + } + + listPadding = MediaQuery.of(context).size.height; + + _adjustedTopOffset = _currentScrollLocation - topOffset; + _scrollController = ScrollController( + initialScrollOffset: listPadding - + _currentScrollLocation + + topOffset + + _currentList.getSelectedItemIndex() * _currentList.itemHeight()); + + return Stack( + children: [ + _InheritedContainerListeners( + listeners: this, + child: widget.child, + ), + Visibility( + visible: isOverlayVisible, + child: FadeTransition( + opacity: fadeAnimationController + .drive(CurveTween(curve: Curves.easeOut)), + child: Column( + children: [ + Expanded( + child: Stack( + children: [ + _getListWidget(), + _getSelectionOverlayWidget(), + ], + ), + ), + ], + ), + ), + ) + ], + ); + } + + Widget _getListWidget() { + var paddingLeft = 0.0; + + if (_currentList.items.isNotEmpty) { + Rect rect = RectGetter.getRectFromKey( + _currentList.paddingItemController.paddingGlobalKey); + if (rect != null) { + paddingLeft = rect.left; + } + } + + final Decoration dslContainerDecoration = widget.decoration ?? + BoxDecoration(color: Theme.of(context).scaffoldBackgroundColor); + + return Container( + decoration: dslContainerDecoration, + child: ListView.builder( + padding: EdgeInsets.only(left: paddingLeft), + controller: _scrollController, + itemCount: _currentList.items.length + 2, + itemBuilder: (BuildContext context, int index) { + if (index == 0 || index == _currentList.items.length + 1) { + return Container(height: listPadding); + } + final item = _currentList.items[index - 1]; + final normalScale = 1.0; + if (lastSelectedItem == index - 1) { + item.updateScale(_calculateNewScale(normalScale)); + } else { + item.updateScale(normalScale); + } + return item; + }, + )); + } + + Widget _getSelectionOverlayWidget() { + return Positioned( + top: _adjustedTopOffset, + left: 0, + right: 0, + height: _currentList.itemHeight(), + child: Container( + height: _currentList.itemHeight(), + decoration: _currentList.focusedItemDecoration != null + ? _currentList.focusedItemDecoration + : BoxDecoration())); + } + + void performListDrag(double dragDy) { + try { + if (_scrollController.hasClients) { + final currentScrollOffset = _scrollController.offset; + double allowedOffset = _allowedDragDistance( + currentScrollOffset + _adjustedTopOffset, + dragDy * widget.dragSpeedMultiplier); + if (allowedOffset != 0.0) { + _scrollController.jumpTo(currentScrollOffset + allowedOffset); + + final scrollPixels = + _scrollController.offset - listPadding + _adjustedTopOffset; + final selectedItemIndex = _getCurrentListElementIndex(scrollPixels); + lastSelectedItem = selectedItemIndex; + + _performScaleTransformation(scrollPixels, selectedItemIndex); + } + } + } catch (e) { + print(e); + } + } + + double _allowedDragDistance(double currentScrollOffset, double position) { + double newPosition = currentScrollOffset + position; + double endOfListPosition = + (_currentList.items.length - 1) * _currentList.itemHeight() + + listPadding; + if (newPosition < listPadding) { + return listPadding - currentScrollOffset; + } else if (newPosition > endOfListPosition) { + return endOfListPosition - currentScrollOffset; + } else { + return position; + } + } + + void _performScaleTransformation(double scrollPixels, int selectedItemIndex) { + final neighbourDistance = _getNeighbourListElementDistance(scrollPixels); + int neighbourIncrementDirection = + neighbourScrollDirection(neighbourDistance); + + int neighbourIndex = lastSelectedItem + neighbourIncrementDirection; + + double neighbourDistanceToCurrentItem = + _getNeighbourListElementDistanceToCurrentItem(neighbourDistance); + + if (neighbourIndex < 0 || neighbourIndex > _currentList.items.length - 1) { + //incorrect neighbour index quit + return; + } + _currentList.items[selectedItemIndex].updateOpacity(1.0); + _currentList.items[neighbourIndex].updateOpacity(0.5); + + _currentList.items[selectedItemIndex] + .updateScale(_calculateNewScale(neighbourDistanceToCurrentItem)); + _currentList.items[neighbourIndex] + .updateScale(_calculateNewScale(neighbourDistance.abs())); + } + + double _calculateNewScale(double distance) => + 1.0 + distance / _currentList.items[lastSelectedItem].scaleFactor; + + int neighbourScrollDirection(double neighbourDistance) { + int neighbourScrollDirection = 0; + if (neighbourDistance > 0) { + neighbourScrollDirection = 1; + } else { + neighbourScrollDirection = -1; + } + return neighbourScrollDirection; + } + + double _getNeighbourListElementDistanceToCurrentItem( + double neighbourDistance) { + double neighbourDistanceToCurrentItem = (1 - neighbourDistance.abs()); + + if (neighbourDistanceToCurrentItem > 1 || + neighbourDistanceToCurrentItem < 0) { + neighbourDistanceToCurrentItem = 1.0; + } + return neighbourDistanceToCurrentItem; + } + + int _getCurrentListElementIndex(double scrollPixels) { + int selectedElement = (scrollPixels / _currentList.itemHeight()).round(); + final maxElementIndex = _currentList.items.length; + + if (selectedElement < 0) { + selectedElement = 0; + } + if (selectedElement >= maxElementIndex) { + selectedElement = maxElementIndex - 1; + } + return selectedElement; + } + + double _getNeighbourListElementDistance(double scrollPixels) { + double selectedElementDeviation = + (scrollPixels / _currentList.itemHeight()); + int selectedElement = _getCurrentListElementIndex(scrollPixels); + return selectedElementDeviation - selectedElement; + } + + Future toggleListOverlayVisibility( + DirectSelectList visibleList, double location) async { + if (isOverlayVisible) { + try { + await _scrollController.animateTo( + listPadding - + _adjustedTopOffset + + lastSelectedItem * _currentList.itemHeight(), + duration: scrollToListElementAnimationDuration, + curve: Curves.ease, + ); + } catch (e) {} finally { + _currentList.setSelectedItemIndex(lastSelectedItem); + await Future.delayed(Duration(milliseconds: 200)); + await fadeAnimationController.reverse(); + setState(() { + _hideListOverlay(); + }); + } + } else { + setState(() { + _showListOverlay(visibleList, location); + }); + } + } + + _showListOverlay(DirectSelectList visibleList, double location) async { + _currentList = visibleList; + _currentScrollLocation = location; + lastSelectedItem = _currentList.getSelectedItemIndex(); + _currentList.items[lastSelectedItem].updateOpacity(1.0); + isOverlayVisible = true; + await fadeAnimationController.forward(from: 0.0); + } + + void _hideListOverlay() { + _scrollController.dispose(); + _currentList.items[lastSelectedItem].updateScale(1.0); + _currentScrollLocation = 0; + _adjustedTopOffset = 0; + isOverlayVisible = false; + } +} + +class DirectSelectGestureEventListeners { + toggleListOverlayVisibility(DirectSelectList list, double location) => + throw 'Not implemented.'; + + performListDrag(double dragDy) => throw 'Not implemented'; +} + +/// Allows Direct Select List implementations to +class _InheritedContainerListeners extends InheritedWidget { + final DirectSelectGestureEventListeners listeners; + + _InheritedContainerListeners({ + Key key, + @required this.listeners, + @required Widget child, + }) : super(key: key, child: child); + + @override + bool updateShouldNotify(_InheritedContainerListeners old) => + old.listeners != listeners; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_item.dart b/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_item.dart new file mode 100644 index 00000000..fe9518a7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_item.dart @@ -0,0 +1,158 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:rect_getter/rect_getter.dart'; + +/// Widget that defines direct select list appearance +/// Usage Example +/// +/// DirectSelectItem getDropDownMenuItem(String value) { +/// return DirectSelectItem( +/// itemHeight: 56, +/// value: value, +/// itemBuilder: (context, value) { +/// return Text(value); +/// }); +/// } +/// +class DirectSelectItem extends StatefulWidget { + ///Value of item + final T value; + + ///Defines is this item is selected + final isSelected; + + ///Height of items in list + final double itemHeight; + + ///Initial item scale + final scale = ValueNotifier(1.0); + + ///Opacity unselected item + final opacity = ValueNotifier(0.5); + + ///the more value the MORE max scale DECREASES + final scaleFactor; + + ///Item builder + final Widget Function(BuildContext context, T value) itemBuilder; + + DirectSelectItem({ + Key key, + this.scaleFactor = 4.0, + @required this.value, + @required this.itemBuilder, + this.itemHeight = 48.0, + this.isSelected = false, + }) : super(key: key); + + @override + State createState() { + return DirectSelectItemState(isSelected: isSelected); + } + + void updateScale(double scale) { + this.scale.value = scale; + } + + void updateOpacity(double opacity) { + this.opacity.value = opacity; + } + + Widget getSelectedItem(GlobalKey animatedStateKey, + dynamic paddingGlobalKey) { + return RectGetter( + key: paddingGlobalKey, + child: DirectSelectItem( + value: value, + key: animatedStateKey, + itemHeight: itemHeight, + itemBuilder: itemBuilder, + isSelected: true, + ), + ); + } +} + +class DirectSelectItemState extends State> + with SingleTickerProviderStateMixin { + final bool isSelected; + + AnimationController animationController; + Animation _animation; + Tween _tween; + + DirectSelectItemState({this.isSelected = false}); + + bool isScaled = false; + + Future runScaleTransition({@required bool reverse}) { + if (reverse) { + return animationController.reverse(); + } else { + return animationController.forward(from: 0.0); + } + } + + @override + void initState() { + super.initState(); + + animationController = + AnimationController(duration: Duration(milliseconds: 150), vsync: this); + _tween = Tween(begin: 1.0, end: 1 + 1 / widget.scaleFactor); + _animation = _tween.animate(animationController) + ..addListener(() { + setState(() {}); + }); + } + + @override + Widget build(BuildContext context) { + if (isSelected) { + return Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + color: Colors.transparent, + height: widget.itemHeight, + alignment: AlignmentDirectional.centerStart, + child: Transform.scale( + scale: _animation.value, + alignment: Alignment.topLeft, + child: widget.itemBuilder(context, widget.value)), + ), + ), + ], + ); + } else { + return Material( + color: Colors.transparent, + child: Container( + child: ValueListenableBuilder( + valueListenable: widget.scale, + builder: (context, value, child) { + return Opacity( + opacity: widget.opacity.value, + child: Container( + height: widget.itemHeight, + child: Transform.scale( + scale: value, + alignment: Alignment.topLeft, + child: widget.itemBuilder(context, widget.value)), + alignment: AlignmentDirectional.centerStart), + ); + }, + ), + ), + ); + } + } + + @override + void dispose() { + super.dispose(); + animationController.dispose(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_list.dart b/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_list.dart new file mode 100644 index 00000000..be6c970f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/lib/direct_select_list.dart @@ -0,0 +1,238 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:rect_getter/rect_getter.dart'; +// import 'package:rect_getter/rect_getter.dart'; + +import 'direct_select_container.dart'; +import 'direct_select_item.dart'; + +typedef DirectSelectItemsBuilder = DirectSelectItem Function(T value); + +class PaddingItemController { + var paddingGlobalKey = RectGetter.createGlobalKey(); +} + +typedef ItemSelected = Future Function( + DirectSelectList owner, double location); + +/// Widget that contains items and responds to user's interaction +/// Usage Example +/// +/// final dsl2 = DirectSelectList( +/// values: _numbers, +/// itemBuilder: (String value) => getDropDownMenuItem(value), +/// focusedItemDecoration: _getDslDecoration()); +/// +class DirectSelectList extends StatefulWidget { + ///Item widgets + final List> items; + + ///Current focused item overlay + final Decoration focusedItemDecoration; + + ///Default selected item index + final int defaultItemIndex; + + ///Notifies state about new item selected + final ValueNotifier selectedItem; + + ///Function to execute when item selected + final Function(T value, int selectedIndex, BuildContext context) + onItemSelectedListener; + + ///Callback for action when user just tapped instead of hold and scroll + final VoidCallback onUserTappedListener; + + ///Holds [GlobalKey] for [RectGetter] + final PaddingItemController paddingItemController = PaddingItemController(); + + DirectSelectList({ + Key key, + @required List values, + @required DirectSelectItemsBuilder itemBuilder, + this.onItemSelectedListener, + this.focusedItemDecoration, + this.defaultItemIndex = 0, + this.onUserTappedListener, + }) : items = values.map((val) => itemBuilder(val)).toNotNullableList(), + selectedItem = ValueNotifier(defaultItemIndex), + assert(defaultItemIndex + 1 <= values.length + 1), + super(key: key); + + @override + State createState() { + return DirectSelectState(); + } + + //double pass item height in this class and build items with that height + double itemHeight() { + if (items.isNotEmpty) { + return items.first.itemHeight; + } + return 0.0; + } + + int getSelectedItemIndex() { + return selectedItem.value; + } + + void setSelectedItemIndex(int index) { + if (index != selectedItem.value) { + selectedItem.value = index; + } + } + + T getSelectedItem() { + return items[selectedItem.value].value; + } +} + +class DirectSelectState extends State> { + final GlobalKey animatedStateKey = + GlobalKey(); + + Future Function(DirectSelectList, double) onTapEventListener; + void Function(double) onDragEventListener; + + bool isOverlayVisible = false; + int lastSelectedItem; + + bool _isShowUpAnimationRunning = false; + + Map selectedItemWidgets = Map(); + + @override + void initState() { + super.initState(); + lastSelectedItem = widget.defaultItemIndex; + _updateSelectItemWidget(); + } + + @override + void didUpdateWidget(DirectSelectList oldWidget) { + widget.paddingItemController.paddingGlobalKey = + oldWidget.paddingItemController.paddingGlobalKey; + _updateSelectItemWidget(); + super.didUpdateWidget(widget); + } + + void _updateSelectItemWidget() { + selectedItemWidgets.clear(); + for (int index = 0; index < widget.items.length; index++) { + selectedItemWidgets.putIfAbsent( + index, + () => widget.items[index].getSelectedItem( + animatedStateKey, + widget.paddingItemController.paddingGlobalKey, + ), + ); + } + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final dsListener = DirectSelectContainer.of(context); + + this.onTapEventListener = dsListener.toggleListOverlayVisibility + as Future Function(DirectSelectList, double); + this.onDragEventListener = + dsListener.performListDrag; + } + + @override + Widget build(BuildContext context) { + widget.selectedItem.addListener(() { + if (widget.onItemSelectedListener != null) { + widget.onItemSelectedListener.call( + widget.items[widget.selectedItem.value].value, + widget.selectedItem.value, + this.context); + } + }); + + bool transitionEnded = false; + + return ValueListenableBuilder( + valueListenable: widget.selectedItem, + builder: (context, value, child) { + final selectedItem = selectedItemWidgets[value]; + return GestureDetector( + child: selectedItem, + onTap: () { + if (widget.onUserTappedListener != null) { + widget.onUserTappedListener.call(); + } + }, + onTapDown: (tapDownDetails) async { + if (!isOverlayVisible) { + transitionEnded = false; + _isShowUpAnimationRunning = true; + await animatedStateKey.currentState + .runScaleTransition(reverse: false); + if (!transitionEnded) { + await _showListOverlay(_getItemTopPosition(context)); + _isShowUpAnimationRunning = false; + lastSelectedItem = value; + } + } + }, + onTapUp: (tapUpDetails) async { + await _hideListOverlay(_getItemTopPosition(context)); + animatedStateKey.currentState + .runScaleTransition(reverse: true); + }, + onVerticalDragEnd: (dragDetails) async { + transitionEnded = true; + _dragEnd(); + }, + onHorizontalDragEnd: (horizontalDetails) async { + transitionEnded = true; + _dragEnd(); + }, + onVerticalDragUpdate: (dragInfo) { + if (!_isShowUpAnimationRunning) { + _showListOverlay(dragInfo.primaryDelta); + } + }); + }); + } + + void _dragEnd() async { + await _hideListOverlay(_getItemTopPosition(context)); + animatedStateKey.currentState.runScaleTransition(reverse: true); + } + + double _getItemTopPosition(BuildContext context) { + final RenderBox itemBox = context.findRenderObject() as RenderBox; + final Rect itemRect = itemBox.localToGlobal(Offset.zero) & itemBox.size; + return itemRect.top; + } + + _hideListOverlay(double dy) async { + if (isOverlayVisible) { + isOverlayVisible = false; + //double fix to prevent stuck scale if selected item is the same as previous + await onTapEventListener(widget, dy); + if (lastSelectedItem == widget.selectedItem.value) { + animatedStateKey.currentState.runScaleTransition(reverse: true); + } + } + } + + _showListOverlay(double dy) { + if (!isOverlayVisible) { + isOverlayVisible = true; + onTapEventListener(widget, _getItemTopPosition(context)); + } else if (dy != null) { + onDragEventListener(dy); + } + } +} + +extension _ListHelper on Iterable { + List toNotNullableList() { + var data = this.toList(); + return data.contains(null) ? List.empty() : data.cast(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/main.dart b/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/main.dart new file mode 100644 index 00000000..e6ebe0d5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/direct_select_flutter/main.dart @@ -0,0 +1,443 @@ +import 'package:flutter/material.dart'; + +import 'lib/direct_select_container.dart'; +import 'lib/direct_select_item.dart'; +import 'lib/direct_select_list.dart'; + +void main() => runApp(DirectSelectFlutterApp()); + +class DirectSelectFlutterApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, @required this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +List _meals = [ + "Breakfast1", + "Breakfast2", + "Lunch1", + "Lunch2", + "Dinner1", + "Dinner2", +]; + +class _MyHomePageState extends State { + List _food = ["Chicken", "Pork", "Vegetables", "Cheese", "Bread"]; + + List _foodVariants = [ + "Chicken grilled", + "Pork grilled", + "Vegetables as is", + "Cheese as is", + "Bread tasty" + ]; + + List _portionSize = [ + "Small portion", + "Medium portion", + "Large portion", + "Huge portion" + ]; + + List _numbers = ["1.0", "2.0", "3.0", "4.0", "5.0", "6.0", "7.0"]; + + int selectedFoodVariants = 0; + int selectedPortionCounts = 0; + int selectedPortionSize = 0; + + DirectSelectItem getDropDownMenuItem(String value) { + return DirectSelectItem( + itemHeight: 56, + value: value, + itemBuilder: (context, value) { + return Text(value); + }); + } + + _getDslDecoration() { + return BoxDecoration( + border: BorderDirectional( + bottom: BorderSide(width: 1, color: Colors.black12), + top: BorderSide(width: 1, color: Colors.black12), + ), + ); + } + + final GlobalKey scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + final appBar = PreferredSize( + child: Container( + decoration: BoxDecoration( + color: Color.fromRGBO(246, 247, 249, 1), + border: BorderDirectional( + bottom: BorderSide(width: 1, color: Colors.black12))), + child: Padding( + padding: EdgeInsets.only(left: 16, bottom: 24), + child: Column( + verticalDirection: VerticalDirection.up, + children: [ + Container( + alignment: AlignmentDirectional.centerStart, + child: Text("Add Food", + style: TextStyle( + fontSize: 26, + color: Colors.black, + fontWeight: FontWeight.bold))), + Container( + alignment: AlignmentDirectional.centerStart, + child: Text("Journal", + style: TextStyle( + fontSize: 12, + color: Colors.black38, + fontWeight: FontWeight.bold))) + ])), + ), + preferredSize: Size.fromHeight(90)); + + return Scaffold( + appBar: appBar, + key: scaffoldKey, + body: DirectSelectContainer( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.down, + children: [ + SizedBox(height: 20.0), + Container( + padding: const EdgeInsets.only(left: 8.0), + alignment: AlignmentDirectional.centerStart, + margin: EdgeInsets.only(left: 4), + child: Column( + children: [ + Text(_foodVariants[selectedFoodVariants], + style: TextStyle( + fontSize: 26, fontWeight: FontWeight.bold)) + ], + )), + Container( + padding: const EdgeInsets.only(left: 8.0), + alignment: AlignmentDirectional.centerStart, + margin: EdgeInsets.only(left: 4), + child: Column( + children: [ + Text(_numbers[selectedPortionCounts] + + " " + + _portionSize[selectedPortionSize]) + ], + )), + SizedBox(height: 5.0), + _getFoodContainsRow(), + SizedBox(height: 20.0), + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + MealSelector(data: _meals, label: "To which meal?"), + SizedBox(height: 20.0), + MealSelector( + data: _food, label: "Search our database by name"), + Padding( + padding: EdgeInsets.fromLTRB(0, 8, 0, 0), + child: Container( + decoration: _getShadowDecoration(), + child: Card( + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + child: DirectSelectList( + values: _foodVariants, + onUserTappedListener: () { + _showScaffold(); + }, + defaultItemIndex: + selectedFoodVariants, + itemBuilder: (String value) => + getDropDownMenuItem(value), + focusedItemDecoration: + _getDslDecoration(), + onItemSelectedListener: + (item, index, context) { + setState(() { + selectedFoodVariants = index; + }); + }), + padding: EdgeInsets.only(left: 22))), + Padding( + padding: EdgeInsets.only(right: 8), + child: _getDropdownIcon(), + ) + ], + )), + ), + ), + SizedBox(height: 15.0), + Container( + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), + margin: EdgeInsets.only(left: 4), + alignment: AlignmentDirectional.centerStart, + child: Text("How Much?")), + Row(children: [ + Expanded( + flex: 2, + child: Container( + decoration: _getShadowDecoration(), + child: Card( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + child: DirectSelectList( + onUserTappedListener: () { + _showScaffold(); + }, + values: _numbers, + defaultItemIndex: + selectedPortionCounts, + itemBuilder: (String value) => + getDropDownMenuItem(value), + focusedItemDecoration: + _getDslDecoration(), + onItemSelectedListener: + (item, index, context) { + setState(() { + selectedPortionCounts = index; + }); + }), + padding: EdgeInsets.only(left: 22))), + ], + )), + )), + Expanded( + flex: 8, + child: Container( + decoration: _getShadowDecoration(), + child: Card( + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + child: DirectSelectList( + values: _portionSize, + defaultItemIndex: + selectedPortionSize, + itemBuilder: (String value) => + getDropDownMenuItem(value), + focusedItemDecoration: + _getDslDecoration(), + onItemSelectedListener: + (item, index, context) { + setState(() { + selectedPortionSize = index; + }); + }), + padding: EdgeInsets.only(left: 22))), + Padding( + padding: EdgeInsets.only(right: 8), + child: _getDropdownIcon(), + ) + ], + )), + )), + ]), + Row(children: [ + Expanded( + child: RaisedButton( + child: const Text('ADD TO JOURNAL', + style: TextStyle(color: Colors.blueAccent)), + onPressed: () {}, + )) + ]), + ], + ), + ), + ], + ), + ), + ), + ), + ); + } + + void _showScaffold() { + final snackBar = SnackBar(content: Text('Hold and drag instead of tap')); + scaffoldKey.currentState?.showSnackBar(snackBar); + } + + Icon _getDropdownIcon() { + return Icon( + Icons.unfold_more, + color: Colors.blueAccent, + ); + } + + BoxDecoration _getShadowDecoration() { + return BoxDecoration( + boxShadow: [ + new BoxShadow( + color: Colors.black.withOpacity(0.06), + spreadRadius: 4, + offset: new Offset(0.0, 0.0), + blurRadius: 15.0, + ), + ], + ); + } +} + +class MealSelector extends StatelessWidget { + final buttonPadding = const EdgeInsets.fromLTRB(0, 8, 0, 0); + + final List data; + final String label; + + MealSelector({@required this.data, @required this.label}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + alignment: AlignmentDirectional.centerStart, + margin: EdgeInsets.only(left: 4), + child: Text(label)), + Padding( + padding: buttonPadding, + child: Container( + decoration: _getShadowDecoration(), + child: Card( + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + child: DirectSelectList( + values: data, + defaultItemIndex: 0, + itemBuilder: (String value) => + getDropDownMenuItem(value), + focusedItemDecoration: _getDslDecoration(), + ), + padding: EdgeInsets.only(left: 12))), + Padding( + padding: EdgeInsets.only(right: 8), + child: _getDropdownIcon(), + ) + ], + )), + ), + ), + ], + ); + } + + DirectSelectItem getDropDownMenuItem(String value) { + return DirectSelectItem( + itemHeight: 56, + value: value, + itemBuilder: (context, value) { + return Text(value); + }); + } + + _getDslDecoration() { + return BoxDecoration( + border: BorderDirectional( + bottom: BorderSide(width: 1, color: Colors.black12), + top: BorderSide(width: 1, color: Colors.black12), + ), + ); + } + + BoxDecoration _getShadowDecoration() { + return BoxDecoration( + boxShadow: [ + new BoxShadow( + color: Colors.black.withOpacity(0.06), + spreadRadius: 4, + offset: new Offset(0.0, 0.0), + blurRadius: 15.0, + ), + ], + ); + } + + Icon _getDropdownIcon() { + return Icon( + Icons.unfold_more, + color: Colors.blueAccent, + ); + } +} + +Widget _getFoodContainsRow() { + final cardSize = 80.0; + final cardColor = Colors.blueGrey[100]; + return Padding( + padding: EdgeInsets.only(left: 8, right: 8), + child: Row( + children: [ + Expanded( + child: Container( + child: Center(child: Text("226")), + height: cardSize, + margin: EdgeInsets.only(right: 3), + decoration: BoxDecoration( + color: cardColor, + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(10.0), + bottomLeft: const Radius.circular(10.0)))), + ), + Expanded( + child: Container( + child: Center(child: Text("41")), + height: cardSize, + margin: EdgeInsets.only(right: 3), + decoration: BoxDecoration(color: cardColor)), + ), + Expanded( + child: Container( + child: Center(child: Text("0")), + height: cardSize, + margin: EdgeInsets.only(right: 3), + decoration: BoxDecoration(color: cardColor)), + ), + Expanded( + child: Container( + child: Center(child: Text("4.5")), + height: cardSize, + decoration: BoxDecoration( + color: cardColor, + borderRadius: BorderRadius.only( + topRight: const Radius.circular(10.0), + bottomRight: const Radius.circular(10.0)))), + ), + ], + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/custom_dough_demo.dart b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/custom_dough_demo.dart new file mode 100644 index 00000000..49b4ba4b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/custom_dough_demo.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/dough/lib/dough.dart'; + +/// This page demonstrates how to create a custom [Dough] widget. +/// +/// In this example, the widget tells the dough to stretched based on +/// if a toggle is switched on or not. See [_CustomDoughDemoState] for +/// how it does this. +class CustomDoughDemo extends StatefulWidget { + @override + _CustomDoughDemoState createState() => _CustomDoughDemoState(); +} + +/// The state of your custom dough widget. +class _CustomDoughDemoState extends State { + /// The controller that determines when the dough should stretch. + final doughController = DoughController(); + + /// A flag to indicate whether the dough should stretch or not. + bool isStretched = false; + + @override + Widget build(BuildContext context) { + // Our widget that we're gonna squish. + final myCustomDough = DoughRecipe( + /// Make how long it takes to start stretching a bit longer. + data: DoughRecipe.of(context).copyWith( + entryDuration: Duration(milliseconds: 250), + ), + child: Dough( + child: Container( + height: 100, + width: 100, + // An image of a cookie. + child: Image.network( + 'https://i.pinimg.com/originals/21/51/b8/2151b8dbdd5aba485f09dd5b74d679c9.png', + ), + ), + controller: doughController, + // transformer: You can create your own transformer to change how the dough morphs, + // but you'll have to read the source code to understand how to do this. This is a + // bit more complicated and requires a general knowledge of linear algebra. + ), + ); + + // A toggle for our dough stretching. Realistically, you'll probably want + // to use a GestureDetector or Listener to determine where to start and end presses + // based on user input. But for the sake of the demo this will be used instead. + final doughToggle = Switch( + value: isStretched, + onChanged: (value) { + // Toggle our stretch variable. + setState(() { + isStretched = !isStretched; + + // Start or stop a stretch based on our isStretched value. + if (isStretched) { + doughController.start( + origin: Offset(0, 0), + target: Offset(500, 500), + ); + } else { + doughController.stop(); + } + }); + }, + ); + + return Scaffold( + appBar: AppBar( + title: Text('Custom Dough'), + ), + body: SizedBox.expand( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Toggle this to manipulate the dough!'), + doughToggle, + myCustomDough, + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/dough_recipe_demo.dart b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/dough_recipe_demo.dart new file mode 100644 index 00000000..75a07c9e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/dough_recipe_demo.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/dough/lib/dough.dart'; + +class DoughRecipeDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + final myDraggableChild = Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.blue, + ), + width: 100, + height: 100, + child: Center( + child: Text( + 'Draggable', + textAlign: TextAlign.center, + style: Theme.of(context).accentTextTheme.bodyText2, + ), + ), + ); + + // This is the widget that gets dragged around. + final myFeedbackWidget = Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.green, + ), + width: 100, + height: 100, + child: Center( + child: Text( + 'Feedback', + textAlign: TextAlign.center, + style: Theme.of(context).accentTextTheme.bodyText2, + ), + ), + ); + + // The default draggable dough widget. + final myDefaultDraggableDough = DraggableDough( + data: 'My data!', + child: myDraggableChild, + feedback: myFeedbackWidget, + childWhenDragging: Container(), + ); + + // To override the default draggable dough feel, just wrap it in a + // DoughRecipe widget and you're good to go! For this widget we're + // enabling `usePerspectiveWarp` to create a sense of mass for the + // dough and make it feel more jiggly. + final myDraggableDoughWithNewSettings = DoughRecipe( + data: DoughRecipeData( + adhesion: 4, + viscosity: 300, + usePerspectiveWarp: true, + perspectiveWarpDepth: 0.02, + exitDuration: Duration(milliseconds: 600), + draggablePrefs: DraggableDoughPrefs( + breakDistance: 100, + useHapticsOnBreak: true, + ), + ), + child: myDefaultDraggableDough, + ); + + // Display the draggable in the center of the page. + return Scaffold( + appBar: AppBar( + title: Text('Dough Recipe'), + ), + body: Center( + child: myDraggableDoughWithNewSettings, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/draggable_dough_demo.dart b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/draggable_dough_demo.dart new file mode 100644 index 00000000..5b4639d4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/draggable_dough_demo.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/dough/lib/dough.dart'; + + +/// This page demonstrates how to use the [DraggableDough] widget. +class DraggableDoughDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + // This is the widget that appears before being dragged around. + final myDraggableChild = Container( + color: Colors.blue, + width: 100, + height: 100, + child: Center( + child: Text( + 'Draggable', + textAlign: TextAlign.center, + style: Theme.of(context).accentTextTheme.bodyText2, + ), + ), + ); + + // This is the widget that gets dragged around. + final myFeedbackWidget = Container( + color: Colors.green, + width: 100, + height: 100, + child: Center( + child: Text( + 'Squishy feedback', + textAlign: TextAlign.center, + style: Theme.of(context).accentTextTheme.bodyText2, + ), + ), + ); + + // Create the draggable dough widget using our child and feedback widgets. + // Also apply a custom dough recipe to make this widget feel awesome :) + final myDraggableDough = DoughRecipe( + data: DoughRecipeData( + adhesion: 4, + viscosity: 500, + draggablePrefs: DraggableDoughPrefs( + breakDistance: 80, + useHapticsOnBreak: true, + ), + ), + child: DraggableDough( + data: 'My data!', + child: myDraggableChild, + feedback: myFeedbackWidget, + longPress: false, + onDoughBreak: () { + // This callback is raised when the dough snaps from its hold at its origin. + print('Demo dough snapped and is freely being dragged!'); + }, + ), + ); + + // DraggableDough works just like the Flutter Draggable widget, except + // it's squishy! So you can just use the already built drag widgets that + // Flutter provides, no problem. + final myDragTarget = DragTarget( + builder: (context, candidateData, rejectedData) { + return Container( + height: 100, + width: 100, + color: candidateData.length > 0 ? Colors.lightGreen : Colors.grey, + child: Center( + child: Text( + 'Drag target', + textAlign: TextAlign.center, + style: Theme.of(context).accentTextTheme.bodyText2, + ), + ), + ); + }, + onWillAccept: (value) => value == 'My data!', + onAccept: (value) { + print('the value "$value" was accepted!'); + }, + ); + + // Now just use the DraggableDough widget however you'd normally use + // Flutter's native Draggable widget. + return Scaffold( + appBar: AppBar( + title: Text('Draggable Dough'), + ), + body: Stack( + children: [ + Positioned( + left: 50, + top: 50, + child: myDraggableDough, + ), + Positioned( + right: 50, + bottom: 50, + child: myDragTarget, + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/gyro_dough_demo.dart b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/gyro_dough_demo.dart new file mode 100644 index 00000000..3655f9cc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/gyro_dough_demo.dart @@ -0,0 +1,62 @@ +import 'package:flutter_helper/samples/dough/lib/dough.dart'; +import 'package:flutter/material.dart'; + +/// This page demonstrates how to use the [GyroDough] widget. +class GyroDoughDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + final myWidgetToSquish = Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.green, + ), + width: 100, + height: 100, + child: Center( + child: Text( + 'Shake the phone', + textAlign: TextAlign.center, + style: Theme.of(context).accentTextTheme.bodyText2, + ), + ), + ); + + // Create a squishy widget which reacts to physical + // phone movement! + final mySquishyGyroWidget = DoughRecipe( + data: DoughRecipeData( + adhesion: 21, + ), + child: GyroDough( + child: myWidgetToSquish, + ), + ); + + return Scaffold( + appBar: AppBar( + title: Text('Gyro Dough'), + ), + body: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'NOTE', + style: Theme.of(context).textTheme.headline6, + textAlign: TextAlign.left, + ), + Text( + 'This widget only works on devices that ' + 'have accelerometer/gyroscope features...', + textAlign: TextAlign.left, + ), + Spacer(), + Center(child: mySquishyGyroWidget), + Spacer(), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/pressable_dough_demo.dart b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/pressable_dough_demo.dart new file mode 100644 index 00000000..cde70d5c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/dough_widget_demos/pressable_dough_demo.dart @@ -0,0 +1,65 @@ +import 'package:flutter_helper/samples/dough/lib/dough.dart'; +import 'package:flutter/material.dart'; + +/// This page demonstrates how to use the [PressableDough] widget. +class PressableDoughDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + // Just a regular old floating action button. + final fab = FloatingActionButton( + onPressed: () {}, + child: Icon(Icons.fingerprint), + ); + + // Now the floating action button is smooshy! + final doughFab = PressableDough( + child: fab, + ); + + // Just a regular old container + final centerContainer = Container( + width: 100, + height: 100, + child: Center( + child: Text( + 'Drag me around!', + textAlign: TextAlign.center, + style: Theme.of(context).accentTextTheme.bodyText1, + ), + ), + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(10), + ), + ); + + // Now let's say we want to make the center container + // squishy, but we want a different kind of squish. To do + // that we just wrap the dough widget in another recipe! + // Easy peasy. + final doughCenterContainer = DoughRecipe( + data: DoughRecipeData( + viscosity: 3000, + expansion: 1.025, + ), + child: PressableDough( + child: centerContainer, + onReleased: (details) { + // This callback is raised when the user release their + // hold on the pressable dough. + print('I was released with ${details.delta} delta!'); + }, + ), + ); + + return Scaffold( + appBar: AppBar( + title: Text('Pressable Dough'), + ), + body: Center( + child: doughCenterContainer, + ), + floatingActionButton: doughFab, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/dough.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/dough.dart new file mode 100644 index 00000000..e3e485d3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/dough.dart @@ -0,0 +1,14 @@ +export 'src/dough/dough.dart'; +export 'src/dough/dough_controller.dart'; +export 'src/dough/dough_recipe.dart'; +export 'src/dough/dough_transformer.dart'; +export 'src/dough/draggable.dart'; +export 'src/dough/draggable_recipe.dart'; +export 'src/dough/gyro.dart'; +export 'src/dough/gyro_recipe.dart'; +export 'src/dough/list.dart'; +export 'src/dough/list_recipe.dart'; +export 'src/dough/pressable.dart'; +export 'src/dough/pressable_recipe.dart'; +export 'src/dough/reorderable_list.dart'; +export 'src/dough/reorderable_list_recipe.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough.dart new file mode 100644 index 00000000..926cde3c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough.dart @@ -0,0 +1,191 @@ +import '../../utils.dart'; +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart' as vmath; + +import 'dough_controller.dart'; +import 'dough_recipe.dart'; +import 'dough_transformer.dart'; + +/// Squishes the provided [child] widget based on the provided +/// [controller] widget in a dough-like fashion. +class Dough extends StatefulWidget { + /// Creates a [Dough] widget. + const Dough({ + @required key, + @required this.child, + @required this.controller, + this.transformer, + this.axis, + }) : super(key: key); + + /// The child to squish. + final Widget child; + + /// Manages when the [child] will smoosh around. + final DoughController controller; + + /// The strategy for how to transform the [child]. This controls **how** + /// the [child] gets smooshed. You can create your own transformers by + /// inheriting from [DoughTransformer] or use one of the provided + /// transformers. If no transformer is specified, a default transformer + /// of type [BasicDoughTransformer] will be used. + final DoughTransformer transformer; + + /// The axis on which to constrain any stretching. If no axis is specified, + /// the [Dough] will not be constrained to any access. + /// + /// **Note that this feature is still under development.** + final Axis axis; + + @override + _DoughState createState() => _DoughState(); +} + +/// The state of a [Dough] widget which manages an animation controller +/// to gracefully transform a widget over time. +class _DoughState extends State with SingleTickerProviderStateMixin { + /// A fallback [DoughTransformer] which will be used if none is specified. + /// This is not static because it's values are modified based on the state + /// of this widget. + final _fallbackTransformer = BasicDoughTransformer(); + + /// The controller to drive the squish animation. + AnimationController _animCtrl; + + /// The current normalized time into the squish animation. + double _effectiveT = 0.0; + + /// The curve along which the squish will animate. + Curve _effectiveCurve = Curves.linear; + + @override + void initState() { + super.initState(); + + _animCtrl = AnimationController(vsync: this) + ..addListener(_onAnimCtrlUpdated) + ..addStatusListener(_onAnimCtrlStatusUpdated); + + widget.controller + ..addStatusListener(_onDoughCtrlStatusUpdated) + ..addListener(_onDoughCtrlUpdated); + + Tween(begin: 0.0, end: 1.0).animate(_animCtrl); + + // If the controller was active on start, inform this widget that it + // should start squishing (as soon as the context is usable). + if (widget.controller.isActive) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (widget.controller.isActive) { + _onDoughCtrlStatusUpdated(widget.controller.status); + } + }); + } + } + + @override + void dispose() { + _animCtrl + ..removeListener(_onAnimCtrlUpdated) + ..removeStatusListener(_onAnimCtrlStatusUpdated) + ..dispose(); + + widget.controller + ..removeStatusListener(_onDoughCtrlStatusUpdated) + ..removeListener(_onDoughCtrlUpdated); + + super.dispose(); + } + + @override + void didUpdateWidget(covariant Dough oldWidget) { + super.didUpdateWidget(oldWidget); + + final lastController = oldWidget.controller; + final nextController = widget.controller; + + lastController + ..removeListener(_onDoughCtrlUpdated) + ..removeStatusListener(_onDoughCtrlStatusUpdated); + + nextController + ..addListener(_onDoughCtrlUpdated) + ..addStatusListener(_onDoughCtrlStatusUpdated); + } + + @override + Widget build(BuildContext context) { + final recipe = DoughRecipe.watch(context); + final controller = widget.controller; + final axis = widget.axis; + final delta = VectorUtils.offsetToVector(controller.delta); + final effTrfm = widget.transformer ?? _fallbackTransformer; + final deltaAngle = VectorUtils.computeFullCircleAngle( + toDirection: delta, + fromDirection: vmath.Vector2(1, 1), + ); + + final tContext = DoughTransformerContext( + rawT: _animCtrl.value, + t: _effectiveT, + recipe: recipe, + origin: VectorUtils.offsetToVector(controller.origin), + target: VectorUtils.offsetToVector(controller.target), + delta: delta, + deltaAngle: deltaAngle, + controller: controller, + axis: axis, + ); + + // Run the transform life-cycle. + effTrfm.onPreTransform(tContext); + final transform = effTrfm.transform(tContext); + effTrfm.onPostTransform(tContext); + + return Transform( + alignment: Alignment.center, + transform: transform, + child: widget.child, + ); + } + + void _onAnimCtrlUpdated() { + setState(() { + _effectiveT = _effectiveCurve.transform(_animCtrl.value); + }); + } + + void _onAnimCtrlStatusUpdated(AnimationStatus status) { + setState(() { + if (status == AnimationStatus.completed) { + _effectiveT = _effectiveCurve.transform(1.0); + } + }); + } + + void _onDoughCtrlUpdated() { + setState(() {}); + } + + void _onDoughCtrlStatusUpdated(DoughStatus status) { + final recipe = DoughRecipe.read(context); + + setState(() { + if (status == DoughStatus.started) { + _effectiveCurve = recipe.entryCurve; + _animCtrl + ..duration = recipe.entryDuration + ..stop() + ..forward(from: _effectiveT); + } else if (status == DoughStatus.stopped) { + _effectiveCurve = recipe.exitCurve; + _animCtrl + ..duration = recipe.exitDuration + ..stop() + ..reverse(from: _effectiveT); + } else { + throw UnimplementedError('Status $status not implemented.'); + } + }); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_controller.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_controller.dart new file mode 100644 index 00000000..3905746d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_controller.dart @@ -0,0 +1,125 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import 'dough.dart'; + +/// A callback used to indicate a change in [DoughStatus]. +typedef DoughStatusCallback = void Function(DoughStatus status); + +/// Represents the state of a [Dough] widget's animation based on its +/// associated [DoughController]. +enum DoughStatus { + /// Indicates that the [DoughController] has entered an active state + /// and [DoughController.isActive] has been set to true. + started, + + /// Indicates that the [DoughController] has exited an active state + /// and [DoughController.isActive] has been set to false. + stopped, +} + +/// Controls a [Dough] widget. Use this to control when a [Dough] widget should +/// squish around. +/// +/// - Use [DoughController.start] to start a squish. +/// - Use [DoughController.update] to update a squish. +/// - Use [DoughController.stop] to finish a squish. +class DoughController with ChangeNotifier { + /// Creates a [DoughController]. + DoughController() : super(); + + final _statusListeners = ObserverList(); + bool _isActive = false; + Offset _origin = Offset.zero; + Offset _target = Offset.zero; + DoughStatus _status = DoughStatus.stopped; + + /// Whether a "squish" on the [Dough] widget is active. + bool get isActive => _isActive; + + /// The starting point of the squish or where the [Dough] is stretching + /// from. + Offset get origin => _origin; + + /// The ending point of the squish or where the [Dough] is trying + /// to stretch to. + Offset get target => _target; + + /// The difference between the [target] and the [origin]. The [Dough] + /// widget uses this to determine which direction to smoosh its [Dough.child]. + Offset get delta => target - origin; + + /// The last [DoughStatus] that was raised. + DoughStatus get status => _status; + + /// Adds a status listener. + void addStatusListener(DoughStatusCallback callback) { + _statusListeners.add(callback); + } + + /// Removes a status listener. + void removeStatusListener(DoughStatusCallback callback) { + _statusListeners.remove(callback); + } + + /// Begin squishing the dough. Sets [isActive] to true. Informs all status + /// listeners that the [status] has changed to [DoughStatus.started]. + /// + /// - If no [origin] is provided, the old [origin] will be used instead. + /// - If no [target] is provided, the old [target] will be used instead. + /// + /// **A squish can't already be active when calling this function.** + void start({ + Offset origin, + Offset target, + }) { + assert(!isActive); + + _isActive = true; + _origin = origin ?? _origin; + _target = target ?? _target; + _status = DoughStatus.started; + + notifyListeners(); + _notifyStatusListeners(_status); + } + + /// Update the currently active squish. + /// + /// - If no [origin] is provided, the old [origin] will be used instead. + /// - If no [target] is provided, the old [target] will be used instead. + /// + /// **A squish must already be active when calling this function.** + void update({ + Offset origin, + Offset target, + }) { + assert(isActive); + + _origin = origin ?? _origin; + _target = target ?? _target; + + notifyListeners(); + } + + /// Stops squishing the [Dough]. Sets [isActive] to false. Informs all status + /// listeners that the [status] has changed to [DoughStatus.stopped]. The + /// [Dough] will snap back to the origin and its original shape. + /// + /// **A squish must already be active when calling this function.** + void stop() { + assert(isActive); + + _isActive = false; + _status = DoughStatus.stopped; + + notifyListeners(); + _notifyStatusListeners(_status); + } + + void _notifyStatusListeners(DoughStatus status) { + for (final listener in _statusListeners) { + listener.call(status); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_recipe.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_recipe.dart new file mode 100644 index 00000000..3d43cc1b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_recipe.dart @@ -0,0 +1,205 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import 'dough.dart'; +import 'dough_controller.dart'; +import 'draggable.dart'; +import 'draggable_recipe.dart'; +import 'gyro.dart'; +import 'gyro_recipe.dart'; + +/// Inherited settings for [Dough] widgets. Use this to override +/// the default [Dough] settings. +@immutable +class DoughRecipe extends StatelessWidget { + /// Creates a [DoughRecipe] widget. + const DoughRecipe({ + @required key, + @required this.child, + this.data, + }) : super(key: key); + + /// The fallback recipe. + static final DoughRecipeData _kFallbackRecipe = DoughRecipeData.fallback(); + + /// This widget's child. Any [Dough] widget below this widget will inherit + /// the [data] provided in this recipe. + final Widget child; + + /// The settings to be applied to all [Dough] widgets below this widget. + final DoughRecipeData data; + + /// Gets the inherited [DoughRecipeData]. If no recipe is found, + /// a default one will be returned instead. + static DoughRecipeData of( + BuildContext context, [ + bool listen = true, + ]) { + try { + return Provider.of(context, listen: listen); + } on ProviderNotFoundException catch (_) { + return _kFallbackRecipe; + } + } + + /// Gets the inherited [DoughRecipeData] without listening to it. If no + /// recipe is found, a default one will be returned instead. + static DoughRecipeData read(BuildContext context) { + return of(context, false); + } + + /// Gets the inherited [DoughRecipeData] and listens to it. If no recipe + /// is found, a default one will be returned instead. + static DoughRecipeData watch(BuildContext context) { + return of(context, true); + } + + @override + Widget build(BuildContext context) { + return Provider.value( + value: data ?? _kFallbackRecipe, + child: child, + ); + } +} + +/// Settings which will be applied to the [Dough] widget at runtime. +@immutable +class DoughRecipeData extends Equatable { + /// Creates a raw recipe, all values must be specified. + const DoughRecipeData.raw({ + @required this.viscosity, + @required this.adhesion, + @required this.expansion, + @required this.usePerspectiveWarp, + @required this.perspectiveWarpDepth, + @required this.entryDuration, + @required this.entryCurve, + @required this.exitDuration, + @required this.exitCurve, + @required this.draggablePrefs, + @required this.gyroPrefs, + }); + + /// Creates a recipe. Defaults are implied for any values not + /// specified. + factory DoughRecipeData({ + double viscosity, + double adhesion, + double expansion, + bool usePerspectiveWarp, + double perspectiveWarpDepth, + Duration entryDuration, + Curve entryCurve, + Duration exitDuration, + Curve exitCurve, + DraggableDoughPrefs draggablePrefs, + GyroDoughPrefs gyroPrefs, + }) { + return DoughRecipeData.raw( + viscosity: viscosity ?? 7000, + adhesion: adhesion ?? 12, + expansion: expansion ?? 1, + usePerspectiveWarp: usePerspectiveWarp ?? false, + perspectiveWarpDepth: perspectiveWarpDepth ?? 0.015, + entryDuration: entryDuration ?? const Duration(milliseconds: 20), + entryCurve: entryCurve ?? Curves.easeInOut, + exitDuration: exitDuration ?? const Duration(milliseconds: 500), + exitCurve: exitCurve ?? Curves.elasticIn, + draggablePrefs: draggablePrefs ?? DraggableDoughPrefs.fallback(), + gyroPrefs: gyroPrefs ?? GyroDoughPrefs.fallback(), + ); + } + + /// Creates the fallback recipe. + factory DoughRecipeData.fallback() => DoughRecipeData(); + + /// How 'thick' a [Dough] widget is. Higher values make for harder/less + /// elastic [Dough]. A typical value would be something like 7000. Lower + /// values like 100 will result in unexpected behaviors. + final double viscosity; + + /// How sticky a [Dough] widget is. Higher values result in [Dough] that + /// doesn't move around a lot when its dragged. Lower values result in + /// really "slippery" [Dough]. A typical value would be something like 12. + final double adhesion; + + /// The factor by which a [Dough] widget expands when activated. + final double expansion; + + /// Whether perspective warping should be used. When enabled, [Dough] widgets + /// will perform a 3D rotation slightly towards [DoughController.delta]. This + /// will give the illusion that the dough has mass and make it feel more + /// jiggly. + final bool usePerspectiveWarp; + + /// The depth of the perspective warp. A typical value would be something + /// like 0.015. + final double perspectiveWarpDepth; + + /// How long a [Dough] widget takes to transition into a squished state. + final Duration entryDuration; + + /// The curve by which a [Dough] widget enters a squished state. + final Curve entryCurve; + + /// How long a [Dough] widget takes to transition out of a squished state. + final Duration exitDuration; + + /// The curve by which a [Dough] widget exits a squished state. + final Curve exitCurve; + + /// Default settings applied to [DraggableDough] widgets. + final DraggableDoughPrefs draggablePrefs; + + /// Default settings applied to [GyroDough] widgets. + final GyroDoughPrefs gyroPrefs; + + /// Copies the current recipe with some new values. + DoughRecipeData copyWith({ + double viscosity, + double adhesion, + double expansion, + bool usePerspectiveWarp, + double perspectiveWarpDepth, + Duration entryDuration, + Curve entryCurve, + Duration exitDuration, + Curve exitCurve, + DraggableDoughPrefs draggablePrefs, + GyroDoughPrefs gyroPrefs, + }) { + return DoughRecipeData.raw( + viscosity: viscosity ?? this.viscosity, + adhesion: adhesion ?? this.adhesion, + expansion: expansion ?? this.expansion, + usePerspectiveWarp: usePerspectiveWarp ?? this.usePerspectiveWarp, + perspectiveWarpDepth: perspectiveWarpDepth ?? this.perspectiveWarpDepth, + entryDuration: entryDuration ?? this.entryDuration, + entryCurve: entryCurve ?? this.entryCurve, + exitDuration: exitDuration ?? this.exitDuration, + exitCurve: exitCurve ?? this.exitCurve, + draggablePrefs: draggablePrefs ?? this.draggablePrefs, + gyroPrefs: gyroPrefs ?? this.gyroPrefs, + ); + } + + @override + List get props => [ + viscosity, + adhesion, + expansion, + usePerspectiveWarp, + perspectiveWarpDepth, + entryDuration, + entryCurve, + exitDuration, + exitCurve, + draggablePrefs, + gyroPrefs, + ]; + + @override + bool get stringify => true; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_transformer.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_transformer.dart new file mode 100644 index 00000000..ebd74f7b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/dough_transformer.dart @@ -0,0 +1,324 @@ +import 'dart:ui' as ui; + +import 'package:equatable/equatable.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart' as vmath; + +import 'dough.dart'; +import 'dough_controller.dart'; +import 'dough_recipe.dart'; + +/// A context passed to a [DoughTransformer]. This will contain a context +/// to inform the [DoughTransformer] on how to transform a widget. +class DoughTransformerContext extends Equatable { + /// Creates an instance of a [DoughTransformerContext]. + const DoughTransformerContext({ + @required this.rawT, + @required this.t, + @required this.recipe, + @required this.origin, + @required this.target, + @required this.delta, + @required this.deltaAngle, + @required this.controller, + @required this.axis, + }); + + /// The unscaled animation time clamped between 0 and 1. + final double rawT; + + /// The scaled animation time, based on [rawT], which has been transformed + /// by the [DoughRecipeData.entryCurve] or [DoughRecipeData.exitCurve]. + final double t; + + /// The contexual recipe applied to the associated [Dough] widget. + final DoughRecipeData recipe; + + /// The origin of the dough squish. This value is equivalent to + /// [DoughController.origin], but is a vector instead of an offset. + final vmath.Vector2 origin; + + /// The target of the dough squish. This value is equivalent to + /// [DoughController.target], but is a vector instead of an offset. + final vmath.Vector2 target; + + /// The delta of the dough squish. This value is equivalent to + /// [DoughController.delta], but is a vector instead of an offset. + final vmath.Vector2 delta; + + /// The full-circle delta angle of the [delta] value, relative to the + /// [Dough] widgets up direction. This value ranges between 0 radians + /// and 2PI radians. + final double deltaAngle; + + /// The controller for the associated [Dough] widget. + final DoughController controller; + + /// The axis on which to constrain any stretching. + final Axis axis; + + /// Whether or not this transformer has an axis to constrain to. + bool get hasAxis => axis != null; + + @override + List get props => [ + rawT, + t, + recipe, + origin, + target, + delta, + deltaAngle, + controller, + axis, + ]; +} + +/// A utility for common dough transformations. +class DoughTransformations { + const DoughTransformations._(); + + /// A utility method which creates a [Matrix4] that scales widgets by a + /// factor of the `DoughRecipe.expansion` property. + static Matrix4 expansion(DoughTransformerContext context) { + final scaleMag = ui.lerpDouble( + 1, + context.recipe.expansion, + context.t, + ); + return Matrix4.identity()..scale(scaleMag); + } + + /// A utility method which creates a [Matrix4] that perspectively rotates + /// wigets around their yaw and pitch axes based on + /// [DoughTransformerContext.delta] and `DoughRecipe.viscosity`. + static Matrix4 perspectiveWarp(DoughTransformerContext context) { + if (!context.recipe.usePerspectiveWarp) { + return Matrix4.identity(); + } + + final perspDelta = -context.delta * context.t / context.recipe.viscosity; + return Matrix4.identity() + ..setEntry(3, 2, context.recipe.perspectiveWarpDepth) + ..rotateY(-perspDelta.x) + ..rotateX(perspDelta.y) + ..scale(perspDelta.length / context.recipe.viscosity + 1); + } + + /// A utility method which creates a [Matrix4] that skews widgets in the + /// direction of the [DoughTransformerContext.delta] based on the + /// `DoughRecipe.viscosity`. If an [DoughTransformerContext.axis] is + /// specified, the resulting matrix will be constrained to the provided axis. + static Matrix4 viscositySkew(DoughTransformerContext context) { + final skewSize = + context.t * context.delta.length / context.recipe.viscosity; + + if (context.axis == Axis.vertical) { + return Matrix4.identity()..scale(1, skewSize, 1); + } else if (context.axis == Axis.horizontal) { + return Matrix4.identity()..scale(skewSize, 1, 1); + } + + final rotateAway = Matrix4.rotationZ(-context.deltaAngle); + final rotateTowards = Matrix4.rotationZ(context.deltaAngle); + final skew = Matrix4.columns( + vmath.Vector4(1, skewSize, 0, 0), + vmath.Vector4(skewSize, 1, 0, 0), + vmath.Vector4(0, 0, 1, 0), + vmath.Vector4(0, 0, 0, 1), + ); + + return rotateAway * skew * rotateTowards; + } + + /// A utility method which creates the default dough squishing [Matrix4]. + /// The resulting [Matrix4] doesn't apply translations, only other warping + /// deformations based on the [DoughTransformerContext.recipe]. + /// + /// You can basically think of this as the core squish behavior. + static Matrix4 squishDeformation(DoughTransformerContext context) { + return perspectiveWarp(context) * + viscositySkew(context) * + expansion(context); + } +} + +/// The strategy for how to transform the [Dough.child] widget. Override +/// this class to create your own dough-like squish effects. You can apply +/// your custom [DoughTransformer] strategy using the [Dough.transformer] +/// property. +/// +/// See [BasicDoughTransformer] for an example on how to do this. +abstract class DoughTransformer { + /// Creates a DoughTransformer. + DoughTransformer() : super(); + + DoughTransformerContext _context; + + /// A callback raised after a transform has been invoked. + @mustCallSuper + void onPreTransform(DoughTransformerContext context) { + // For backwards compatability. + _context = context; + } + + /// Creates the [Matrix4] which will be used to transform the [Dough.child] + /// widget. + Matrix4 transform(DoughTransformerContext context); + + /// A callback raised after a transform has been invoked. + @mustCallSuper + void onPostTransform(DoughTransformerContext context) {} + + /// See `DoughTransformations.expansion`. + @protected + @Deprecated('Use DoughTransformations.expansion instead.') + Matrix4 createExpansionMatrix() { + return DoughTransformations.expansion(_context); + } + + /// See `DoughTransformations.perspectiveWarp`. + @protected + @Deprecated('Use DoughTransformations.perspectiveWarp instead.') + Matrix4 createPerspectiveWarpMatrix() { + return DoughTransformations.perspectiveWarp(_context); + } + + /// See `DoughTransformations.viscositySkew`. + @protected + @Deprecated('Use DoughTransformations.viscositySkew instead.') + Matrix4 createViscositySkewMatrix() { + return DoughTransformations.viscositySkew(_context); + } + + /// See `DoughTransformations.squishDeformation`. + @protected + @Deprecated('Use DoughTransformations.squishDeformation instead.') + Matrix4 createSquishDeformationMatrix() { + return DoughTransformations.squishDeformation(_context); + } + + /// The unscaled animation time clamped between 0 and 1. + @Deprecated('Access this value using the context instead.') + double get rawT => _context.rawT; + + /// The scaled animation time, based on [rawT], which has been transformed + /// by the [DoughRecipeData.entryCurve] or [DoughRecipeData.exitCurve]. + @Deprecated('Access this value using the context instead.') + double get t => _context.t; + + /// The contexual recipe applied to the associated [Dough] widget. + @Deprecated('Access this value using the context instead.') + DoughRecipeData get recipe => _context.recipe; + + /// The origin of the dough squish. This value is equivalent to + /// [DoughController.origin], but is a vector instead of an offset. + @Deprecated('Access this value using the context instead.') + vmath.Vector2 get origin => _context.origin; + + /// The target of the dough squish. This value is equivalent to + /// [DoughController.target], but is a vector instead of an offset. + @Deprecated('Access this value using the context instead.') + vmath.Vector2 get target => _context.target; + + /// The delta of the dough squish. This value is equivalent to + /// [DoughController.delta], but is a vector instead of an offset. + @Deprecated('Access this value using the context instead.') + vmath.Vector2 get delta => _context.delta; + + /// The full-circle delta angle of the [delta] value, relative to the + /// [Dough] widgets up direction. This value ranges between 0 radians + /// and 2PI radians. + @Deprecated('Access this value using the context instead.') + double get deltaAngle => _context.deltaAngle; + + /// The controller for the associated [Dough] widget. + @Deprecated('Access this value using the context instead.') + DoughController get controller => _context.controller; + + /// The axis on which to constrain any stretching. + @Deprecated('Access this value using the context instead.') + Axis get axis => _context.axis; + + /// Creates the [Matrix4] which will be used to transform the [Dough.child] + /// widget. + @Deprecated('Use DoughTransformer.transform instead') + Matrix4 createDoughMatrix() { + return transform(_context); + } +} + +/// Transforms [Dough.child] widgets such that they stretch from their origin +/// towards the target with resistance pulling the widget back towards its +/// origin. +class BasicDoughTransformer extends DoughTransformer { + /// Creates a BasicDoughTransformer. + BasicDoughTransformer() : super(); + + @override + Matrix4 transform(DoughTransformerContext context) { + final translate = Matrix4.translationValues( + context.delta.x * context.t / context.recipe.adhesion, + context.delta.y * context.t / context.recipe.adhesion, + 0, + ); + + return translate * DoughTransformations.squishDeformation(context); + } +} + +/// Transforms [Dough.child] widgets such that they stretch towards their +/// target with adhesion applied. Additionally this transformer allows you +/// to apply offset to the child widget while being dragged to give the +/// illusion that the draggable widget is "resisting" being dragged until +/// [DoughController.stop] is called. +class DraggableOverlayDoughTransformer extends DoughTransformer { + /// Creates a DraggableOverlayDoughTransformer. + DraggableOverlayDoughTransformer({ + @required this.applyDelta, + @required this.snapToTargetOnStop, + }) : super(); + + /// Whether the controller's delta should be applied to the widget. + /// This will offset the widget being dragged by + /// [DoughTransformerContext.delta]. + final bool applyDelta; + + /// If [applyDelta] is true, this determines whether the widget should + /// snap towards the target when [DoughController.stop] is called. + final bool snapToTargetOnStop; + + @override + Matrix4 transform(DoughTransformerContext context) { + final adhesiveDelta = context.delta * context.t / context.recipe.adhesion; + + Matrix4 translate; + if (applyDelta) { + if (snapToTargetOnStop) { + final effDelta = + -context.delta * (context.controller.isActive ? 1 : context.t); + + translate = Matrix4.translationValues( + effDelta.x + adhesiveDelta.x, + effDelta.y + adhesiveDelta.y, + 0, + ); + } else { + translate = Matrix4.translationValues( + -context.delta.x + adhesiveDelta.x, + -context.delta.y + adhesiveDelta.y, + 0, + ); + } + } else { + translate = Matrix4.translationValues( + adhesiveDelta.x, + adhesiveDelta.y, + 0, + ); + } + + return translate * DoughTransformations.squishDeformation(context); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/draggable.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/draggable.dart new file mode 100644 index 00000000..6f1068fc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/draggable.dart @@ -0,0 +1,340 @@ +import 'dart:collection'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'dough.dart'; +import 'dough_controller.dart'; +import 'dough_recipe.dart'; +import 'dough_transformer.dart'; +import 'draggable_recipe.dart'; + +/// A widget which mimics the behavior of Flutter's [Draggable] widget, only +/// this one is squishy! For details on what each field does for this widget, +/// view [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html) +/// for the [Draggable] widget. +class DraggableDough extends StatefulWidget { + /// Creates a [DraggableDough] widget. + const DraggableDough({ + @required key, + this.prefs, + this.onDoughBreak, + @required this.child, + @required this.feedback, + this.data, + this.axis, + this.childWhenDragging, + this.feedbackOffset = Offset.zero, + this.dragAnchor = DragAnchor.child, + this.affinity, + this.maxSimultaneousDrags, + this.onDragStarted, + this.onDraggableCanceled, + this.onDragEnd, + this.onDragCompleted, + this.ignoringFeedbackSemantics = true, + this.longPress = false, + }) : assert(maxSimultaneousDrags == null || maxSimultaneousDrags >= 0), + super(key: key); + + /// Preferences for the behavior of this [DraggableDough] widget. This can + /// be specified here or in the context of a [DoughRecipe] widget. This will + /// override the contextual [DoughRecipeData.draggablePrefs] if provided. + final DraggableDoughPrefs prefs; + + /// A callback raised when the user drags the feedback widget beyond the + /// [DraggableDoughPrefs.breakDistance] and the [Dough] snaps back into + /// its original form. + final VoidCallback onDoughBreak; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final T data; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final Axis axis; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final Widget child; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final Widget childWhenDragging; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final Widget feedback; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final Offset feedbackOffset; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final DragAnchor dragAnchor; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final bool ignoringFeedbackSemantics; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final Axis affinity; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final int maxSimultaneousDrags; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final VoidCallback onDragStarted; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final DraggableCanceledCallback onDraggableCanceled; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final VoidCallback onDragCompleted; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/Draggable-class.html). + final DragEndCallback onDragEnd; + + /// See [Flutter's docs](https://api.flutter.dev/flutter/widgets/LongPressDraggable-class.html). + /// + /// **NOTE:** There is a known issue where, if enabled, the [onDoughBreak] + /// callback will still be triggered, even if the draggable widget + /// does not become visible. This behavior will be fixed in a future + /// update, but it will be a breaking change. + final bool longPress; + + @override + _DraggableDoughState createState() => _DraggableDoughState(); +} + +/// The state of a [DraggableDough] widget which controls how the [Dough] morphs +/// as the feedback is dragged around. +class _DraggableDoughState extends State> { + final _controllerTracker = _DragControllerTracker(); + + @override + void initState() { + super.initState(); + _controllerTracker.reset(); + } + + @override + void dispose() { + super.dispose(); + _controllerTracker.reset(); + } + + @override + void didUpdateWidget(covariant DraggableDough oldWidget) { + super.didUpdateWidget(oldWidget); + _controllerTracker.reset(); + } + + @override + Widget build(BuildContext context) { + final recipe = DoughRecipe.watch(context); + final prefs = widget.prefs ?? recipe.draggablePrefs; + + // The feedback widget won't share the same context once the [Draggable] + // widget instantiates it as an overlay. The [DoughRecipe] has to be copied + // directly so it will exist in the overlay's context as well. + final doughFeedback = DoughRecipe( + data: recipe, + child: _DragFeedback( + controllerTracker: _controllerTracker, + child: widget.feedback, + ), + ); + Widget draggable; + if (widget.longPress) { + draggable = LongPressDraggable( + child: widget.child, + feedback: doughFeedback, + data: widget.data, + axis: widget.axis, + childWhenDragging: widget.childWhenDragging, + feedbackOffset: widget.feedbackOffset, + dragAnchor: widget.dragAnchor, + maxSimultaneousDrags: widget.maxSimultaneousDrags, + ignoringFeedbackSemantics: widget.ignoringFeedbackSemantics, + onDraggableCanceled: widget.onDraggableCanceled, + onDragEnd: widget.onDragEnd, + onDragCompleted: widget.onDragCompleted, + onDragStarted: widget.onDragStarted, + ); + } else { + draggable = Draggable( + child: widget.child, + feedback: doughFeedback, + data: widget.data, + axis: widget.axis, + childWhenDragging: widget.childWhenDragging, + feedbackOffset: widget.feedbackOffset, + dragAnchor: widget.dragAnchor, + affinity: widget.affinity, + maxSimultaneousDrags: widget.maxSimultaneousDrags, + ignoringFeedbackSemantics: widget.ignoringFeedbackSemantics, + onDraggableCanceled: widget.onDraggableCanceled, + onDragEnd: widget.onDragEnd, + onDragCompleted: widget.onDragCompleted, + onDragStarted: widget.onDragStarted, + ); + } + + return Listener( + child: draggable, + onPointerDown: (event) { + _controllerTracker.enqueueHintControllerID(event.pointer); + _controllerTracker.initController(event.pointer) + ..start( + origin: event.position, + target: event.position, + ); + }, + onPointerMove: (event) { + // This should never happen. But just in case, be safe. + if (!_controllerTracker.containsController(event.pointer)) { + return; + } + + final controller = _controllerTracker.getcontroller(event.pointer); + if (controller.isActive) { + final sqrBreakThresh = prefs.breakDistance * prefs.breakDistance; + if (controller.delta.distanceSquared > sqrBreakThresh) { + controller.stop(); + widget.onDoughBreak?.call(); + if (prefs.useHapticsOnBreak) { + HapticFeedback.selectionClick(); + } + } else { + controller.update( + target: event.position, + ); + } + } + }, + onPointerUp: (event) { + if (_controllerTracker.containsController(event.pointer)) { + _controllerTracker.tearDownController(event.pointer); + } + }, + onPointerCancel: (event) { + if (_controllerTracker.containsController(event.pointer)) { + _controllerTracker.tearDownController(event.pointer); + } + }, + ); + } +} + +/// A helper drag feedback widget which maintains a pointer ID to control +/// the Dough. +class _DragFeedback extends StatefulWidget { + /// Creates a [_DragFeedback] widget. + const _DragFeedback({ + @required key, + @required this.controllerTracker, + @required this.child, + }) : super(key: key); + + /// The widget being dragged. + final Widget child; + + /// A reference to track pointer IDs. + final _DragControllerTracker controllerTracker; + + @override + _DragFeedbackState createState() => _DragFeedbackState(); +} + +/// The state of a [_DragFeedback] widget. +class _DragFeedbackState extends State<_DragFeedback> { + int _controllerID; + + @override + void initState() { + super.initState(); + + // Save the next hint to determine which controller to bind to. + assert(widget.controllerTracker.hasHintControllerID); + _controllerID = widget.controllerTracker.dequeueHintControllerID(); + } + + @override + Widget build(BuildContext context) { + return Dough( + child: widget.child, + controller: widget.controllerTracker.getcontroller(_controllerID), + transformer: DraggableOverlayDoughTransformer( + snapToTargetOnStop: true, + applyDelta: true, + ), + ); + } +} + +/// A helper class to keep track of various dough controllers based on +/// the pointer IDs they're associated with when being dragged. +class _DragControllerTracker { + final _controllers = {}; + final _hintControllerIDs = ListQueue(); + + /// Whether a hint controller was specified. + bool get hasHintControllerID => !_hintControllerIDs.isEmpty; + + /// Enqueues an [id] to hint at the [DoughController] that the next + /// [_DragFeedback] widget should use when smooshing the dough. + void enqueueHintControllerID(int id) { + _hintControllerIDs.addLast(id); + } + + /// Dequeues an `id` that hints at which [DoughController] to use next, + /// (ensures that the hint is valid). + int dequeueHintControllerID() { + while (!_hintControllerIDs.isEmpty) { + final id = _hintControllerIDs.removeFirst(); + if (containsController(id)) { + return id; + } + } + + return -1; + } + + /// Initializes a [DoughController] for the specified [id]. + DoughController initController(int id) { + assert(!containsController(id)); + final controller = DoughController(); + _controllers[id] = controller; + return controller; + } + + /// Returns whether a [DoughController] with the specified [id] exists. + bool containsController(int id) { + return _controllers.containsKey(id); + } + + /// Gets a [DoughController] for the specified [id]. + DoughController getcontroller(int id) { + assert(containsController(id)); + return _controllers[id]; + } + + /// Tears down the [DoughController] cached at the specified [id]. + DoughController tearDownController(int id) { + assert(containsController(id)); + final controller = getcontroller(id); + if (controller.isActive) { + controller.stop(); + } + + return _controllers.remove(id); + } + + /// Cleans up the controller and hint cache. + void reset() { + for (final id in _controllers.keys) { + final controller = getcontroller(id); + if (controller.isActive) { + controller.stop(); + } + } + + _hintControllerIDs.clear(); + _controllers.clear(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/draggable_recipe.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/draggable_recipe.dart new file mode 100644 index 00000000..ad48ff30 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/draggable_recipe.dart @@ -0,0 +1,56 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +import 'draggable.dart'; + +/// Preferences applied to [DraggableDough] widgets. +class DraggableDoughPrefs extends Equatable { + /// Creates raw [DraggableDough] preferences, all values must be specified. + const DraggableDoughPrefs.raw({ + @required this.breakDistance, + @required this.useHapticsOnBreak, + }); + + /// Creates [DraggableDough] preferences. + factory DraggableDoughPrefs({ + double breakDistance, + bool useHapticsOnBreak, + }) { + return DraggableDoughPrefs.raw( + breakDistance: breakDistance ?? 80, + useHapticsOnBreak: useHapticsOnBreak ?? true, + ); + } + + /// Creates fallback [DraggableDough] preferences. + factory DraggableDoughPrefs.fallback() => DraggableDoughPrefs(); + + /// The logical pixel distance at which the [DraggableDough] should + /// elastically break its hold on the origin and enter a freely movable + /// state. + final double breakDistance; + + /// Whether [DraggableDough] widgets should trigger haptic feedback when + /// the dough breaks its hold on the origin. + final bool useHapticsOnBreak; + + /// Copies these preferences with some new values. + DraggableDoughPrefs copyWith({ + double breakDistance, + bool useHapticsOnBreak, + }) { + return DraggableDoughPrefs.raw( + breakDistance: breakDistance ?? this.breakDistance, + useHapticsOnBreak: useHapticsOnBreak ?? this.useHapticsOnBreak, + ); + } + + @override + List get props => [ + breakDistance, + useHapticsOnBreak, + ]; + + @override + bool get stringify => true; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/gyro.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/gyro.dart new file mode 100644 index 00000000..42c4189f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/gyro.dart @@ -0,0 +1,118 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:sensors/sensors.dart'; + +import 'dough.dart'; +import 'dough_controller.dart'; +import 'dough_recipe.dart'; + +/// A widget that stretches its child in a dough-like fashion based +/// on physical device accelerometer inputs (e.g. the [Dough] jiggles +/// when you move your phone around). +/// +/// **This widget ONLY works on devices that have accelerometers.** +/// +/// Please note that this widget will be moved over to a separate package +/// to remove a platform depedency. +class GyroDough extends StatefulWidget { + /// Creates a [GyroDough] widget. + const GyroDough({ + @required key, + @required this.child, + }) : super(key: key); + + /// The child to stretch based on physical device motion. + final Widget child; + + @override + _GyroDoughState createState() => _GyroDoughState(); +} + +/// The state of a gyro dough widget which is used to track and interpret +/// accelerometer values. +class _GyroDoughState extends State { + final _controller = DoughController(); + + List _rollingSamples; + Offset _rollingSum; + int _rollingIndex; + bool _hasInitialized = false; + StreamSubscription _accelSub; + + @override + void initState() { + _accelSub = accelerometerEvents.listen(_onAccelEvent); + _controller.start( + origin: Offset.zero, + target: Offset.zero, + ); + + super.initState(); + } + + @override + void dispose() { + _accelSub?.cancel(); + _accelSub = null; + super.dispose(); + } + + @override + void didChangeDependencies() { + final prefs = DoughRecipe.watch(context).gyroPrefs; + + if (!_hasInitialized) { + _rollingSum = Offset.zero; + _rollingIndex = 0; + _rollingSamples = List.filled( + prefs.sampleCount, + Offset.zero, + ); + + _hasInitialized = true; + } else { + _rollingSum = Offset.zero; + + final oldSamples = _rollingSamples; + final newSamples = List.filled( + prefs.sampleCount, + Offset.zero, + ); + + // Sync the samples to the new gyro preferences. + for (var i = 0; i < newSamples.length; ++i) { + newSamples[i] = oldSamples[i % oldSamples.length]; + _rollingSum += newSamples[i]; + } + + _rollingSamples = newSamples; + _rollingIndex = _rollingIndex % newSamples.length; + } + + super.didChangeDependencies(); + } + + @override + Widget build(BuildContext context) { + return Dough( + controller: _controller, + child: widget.child, + ); + } + + void _onAccelEvent(AccelerometerEvent event) { + final prefs = DoughRecipe.read(context).gyroPrefs; + final sample = Offset(-event.x, event.y) * prefs.gyroMultiplier; + + _rollingIndex = (_rollingIndex + 1) % _rollingSamples.length; + _rollingSum -= _rollingSamples[_rollingIndex]; + _rollingSamples[_rollingIndex] = sample; + _rollingSum += sample; + + // Apply a low-pass filter to smooth out the accelerometer values. + _controller.update( + target: _rollingSum / _rollingSamples.length.toDouble(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/gyro_recipe.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/gyro_recipe.dart new file mode 100644 index 00000000..c36c05fa --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/gyro_recipe.dart @@ -0,0 +1,69 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +import 'dough.dart'; +import 'gyro.dart'; + +/// Preferences applied to [GyroDough] widgets. +/// +/// Please note that this widget will be moved over to a separate package +/// to remove a platform depedency. +class GyroDoughPrefs extends Equatable { + /// Creates raw [GyroDough] preferences, all values must be specified. + const GyroDoughPrefs.raw({ + @required this.sampleCount, + @required this.gyroMultiplier, + }); + + /// Creates [GyroDough] preferences. + factory GyroDoughPrefs({ + int sampleCount, + double gyroMultiplier, + }) { + return GyroDoughPrefs.raw( + sampleCount: sampleCount ?? 10, + gyroMultiplier: gyroMultiplier ?? 100, + ); + } + + /// Creates fallback [GyroDough] preferences. + factory GyroDoughPrefs.fallback() => GyroDoughPrefs(); + + /// The number of samples to use in the final gyro output. In technical + /// terms, this value controls the intensity of 'low-pass filter' applied + /// to a device's accelerometer. + /// + /// Higher values result in smoother gyro effects (slow-ish [Dough]), while + /// lower values result in quick (and possibly more jagged) [Dough] effects. + /// + /// A typical value would be something like `10`. The minimum accepted + /// sample count is `1`. + final int sampleCount; + + /// The value by which accelerometer values are multiplied. Higher + /// [gyroMultiplier] values will result in [Dough] that is more sensitive to + /// motion. + /// + /// A typical value would be something like `100`. + final double gyroMultiplier; + + /// Copies these preferences with some new values. + GyroDoughPrefs copyWith({ + int sampleCount, + double gyroMultiplier, + }) { + return GyroDoughPrefs.raw( + sampleCount: sampleCount ?? this.sampleCount, + gyroMultiplier: gyroMultiplier ?? this.gyroMultiplier, + ); + } + + @override + List get props => [ + sampleCount, + gyroMultiplier, + ]; + + @override + bool get stringify => true; +} diff --git a/base/consumer-rules.pro b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/list.dart similarity index 100% rename from base/consumer-rules.pro rename to FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/list.dart diff --git a/bitmap/bitmapdemo/consumer-rules.pro b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/list_recipe.dart similarity index 100% rename from bitmap/bitmapdemo/consumer-rules.pro rename to FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/list_recipe.dart diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/pressable.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/pressable.dart new file mode 100644 index 00000000..c1ca5ec4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/pressable.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +import 'dough.dart'; +import 'dough_controller.dart'; +import 'dough_transformer.dart'; + +/// Details for a [PressableDoughReleaseCallback]. +@immutable +class PressableDoughReleaseDetails { + /// Creates a [PressableDoughReleaseDetails]. + const PressableDoughReleaseDetails({ + @required this.delta, + @required this.position, + }); + + /// How far the dough was dragged before it was released. + final Offset delta; + + /// The global position of where the user released their hold on dough. + final Offset position; +} + +/// Raised when a user releases their hold on a [PressableDough] widget. +typedef PressableDoughReleaseCallback = void Function( + PressableDoughReleaseDetails details, +); + +/// A smooshable dough widget that morphs into different shapes based +/// on how the user presses on it. +class PressableDough extends StatefulWidget { + /// Creates a [PressableDough] widget. + const PressableDough({ + @required key, + @required this.child, + this.onStart, + this.onReleased, + }) : super(key: key); + + /// The child to smoosh. + final Widget child; + + /// A callback raised when a user starts a hold on the widget and has + /// begun to squish it around. + final VoidCallback onStart; + + /// A callback raised when the user releases their hold on the widget + /// (e.g. the user stopped smooshing the widget). + final PressableDoughReleaseCallback onReleased; + + @override + _PressableDoughState createState() => _PressableDoughState(); +} + +/// The state of a [PressableDough] widget which updates a [Dough] widget +/// based on user input. +class _PressableDoughState extends State { + final _controller = DoughController(); + + @override + Widget build(BuildContext context) { + final pressableInterface = GestureDetector( + onPanStart: (details) { + _controller.start( + origin: details.globalPosition, + target: details.globalPosition, + ); + widget.onStart?.call(); + }, + onPanUpdate: (details) { + _controller.update( + target: details.globalPosition, + ); + }, + onPanEnd: (details) { + if (_controller.isActive) { + _controller.stop(); + } + + widget.onReleased?.call( + PressableDoughReleaseDetails( + delta: _controller.delta, + position: _controller.target, + ), + ); + }, + onPanCancel: () { + if (_controller.isActive) { + _controller.stop(); + } + }, + child: widget.child, + behavior: HitTestBehavior.translucent, + ); + + return Dough( + child: pressableInterface, + controller: _controller, + transformer: BasicDoughTransformer(), + ); + } +} diff --git a/bitmap/lottie/consumer-rules.pro b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/pressable_recipe.dart similarity index 100% rename from bitmap/lottie/consumer-rules.pro rename to FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/pressable_recipe.dart diff --git a/confictJD/src/main/assets/package/components/controller/controller.less b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/reorderable_list.dart similarity index 100% rename from confictJD/src/main/assets/package/components/controller/controller.less rename to FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/reorderable_list.dart diff --git a/confictJD/src/main/assets/package/components/controller/controller.scss b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/reorderable_list_recipe.dart similarity index 100% rename from confictJD/src/main/assets/package/components/controller/controller.scss rename to FlutterHelper/flutter_helper/lib/samples/dough/lib/src/dough/reorderable_list_recipe.dart diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/utils/vector.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/utils/vector.dart new file mode 100644 index 00000000..b3ed09c0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/src/utils/vector.dart @@ -0,0 +1,32 @@ +import 'dart:math' as math; + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart' as vmath; + +/// A Vector utility class. +class VectorUtils { + const VectorUtils._(); + + /// Computes the angle between [toDirection] and [fromDirection], + /// with the result ranging between 0 and 2π radians. + static double computeFullCircleAngle({ + @required vmath.Vector2 toDirection, + vmath.Vector2 fromDirection, + }) { + final a = fromDirection ?? vmath.Vector2(1, 0); + final b = toDirection; + + final rawAngle = -a.angleToSigned(b); + if (rawAngle < 0.0) { + return 2 * math.pi + rawAngle; + } else { + return rawAngle; + } + } + + /// Converts an [Offset] to a [vmath.Vector2]. + static vmath.Vector2 offsetToVector(Offset offset) { + return vmath.Vector2(offset.dx, offset.dy); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/lib/utils.dart b/FlutterHelper/flutter_helper/lib/samples/dough/lib/utils.dart new file mode 100644 index 00000000..3edfbe8d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/lib/utils.dart @@ -0,0 +1 @@ +export 'src/utils/vector.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/main.dart b/FlutterHelper/flutter_helper/lib/samples/dough/main.dart new file mode 100644 index 00000000..18221bc3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/main.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; + +import 'lib/dough.dart'; +import 'routes.dart'; + +void main() { + runApp(DoughApp()); +} + +class DoughApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + final app = MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + routes: Routes.define(), + initialRoute: Routes.kHome, + ); + + // Optionally, apply your own default dough recipe to your + // whole app if you don't like the built in recipe. All dough + // widgets will then default to use these settings. + return DoughRecipe( + data: DoughRecipeData( + viscosity: 5000, + adhesion: 14, + ), + child: app, + ); + } +} + +/// This page just provides links to the different dough widget examples. +class HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final nav = Navigator.of(context); + + final pageList = [ + ListTile( + title: Text('Dough Recipe'), + onTap: () => nav.pushNamed(Routes.kDoughRecipeDemo), + ), + Divider(), + ListTile( + title: Text('Pressable Dough'), + onTap: () => nav.pushNamed(Routes.kPressableDough), + ), + ListTile( + title: Text('Draggable Dough'), + onTap: () => nav.pushNamed(Routes.kDraggableDough), + ), + ListTile( + title: Text('Gyro Dough'), + onTap: () => nav.pushNamed(Routes.kGyroDoughDemo), + ), + Divider(), + ListTile( + title: Text('Custom Dough'), + onTap: () => nav.pushNamed(Routes.kCustomDough), + ), + ]; + + return Scaffold( + appBar: AppBar( + title: Text('Flutter Demo Home Page'), + ), + body: ListView(children: pageList), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/dough/routes.dart b/FlutterHelper/flutter_helper/lib/samples/dough/routes.dart new file mode 100644 index 00000000..bcb6645f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/dough/routes.dart @@ -0,0 +1,25 @@ +import 'main.dart'; + +import 'dough_widget_demos/custom_dough_demo.dart'; +import 'dough_widget_demos/gyro_dough_demo.dart'; +import 'dough_widget_demos/pressable_dough_demo.dart'; +import 'dough_widget_demos/draggable_dough_demo.dart'; +import 'dough_widget_demos/dough_recipe_demo.dart'; + +class Routes { + static final kHome = '/'; + static final kCustomDough = '/custom-dough'; + static final kPressableDough = '/pressable-dough'; + static final kDraggableDough = '/draggable-dough'; + static final kGyroDoughDemo = '/gyro-dough'; + static final kDoughRecipeDemo = '/dough-recipe'; + + static define() => { + kHome: (context) => HomePage(), + kCustomDough: (context) => CustomDoughDemo(), + kPressableDough: (context) => PressableDoughDemo(), + kDraggableDough: (context) => DraggableDoughDemo(), + kGyroDoughDemo: (context) => GyroDoughDemo(), + kDoughRecipeDemo: (context) => DoughRecipeDemo(), + }; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/fb_reaction_box/fb_reaction_box.dart b/FlutterHelper/flutter_helper/lib/samples/fb_reaction_box/fb_reaction_box.dart new file mode 100644 index 00000000..70f369c7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/fb_reaction_box/fb_reaction_box.dart @@ -0,0 +1,1205 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:audioplayers/audioplayers.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:path_provider/path_provider.dart'; + +class FbReactionBox extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text( + 'FB REACTION', + style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold), + ), + centerTitle: true, + ), + body: FbReaction()); + } +} + +class FbReaction extends StatefulWidget { + @override + createState() => FbReactionState(); +} + +class FbReactionState extends State with TickerProviderStateMixin { + AudioPlayer audioPlayer; + + int durationAnimationBox = 500; + int durationAnimationBtnLongPress = 150; + int durationAnimationBtnShortPress = 500; + int durationAnimationIconWhenDrag = 150; + int durationAnimationIconWhenRelease = 1000; + + // For long press btn + AnimationController animControlBtnLongPress, animControlBox; + Animation zoomIconLikeInBtn, tiltIconLikeInBtn, zoomTextLikeInBtn; + Animation fadeInBox; + Animation moveRightGroupIcon; + Animation pushIconLikeUp, pushIconLoveUp, pushIconHahaUp, pushIconWowUp, pushIconSadUp, pushIconAngryUp; + Animation zoomIconLike, zoomIconLove, zoomIconHaha, zoomIconWow, zoomIconSad, zoomIconAngry; + + // For short press btn + AnimationController animControlBtnShortPress; + Animation zoomIconLikeInBtn2, tiltIconLikeInBtn2; + + // For zoom icon when drag + AnimationController animControlIconWhenDrag; + AnimationController animControlIconWhenDragInside; + AnimationController animControlIconWhenDragOutside; + AnimationController animControlBoxWhenDragOutside; + Animation zoomIconChosen, zoomIconNotChosen; + Animation zoomIconWhenDragOutside; + Animation zoomIconWhenDragInside; + Animation zoomBoxWhenDragOutside; + Animation zoomBoxIcon; + + // For jump icon when release + AnimationController animControlIconWhenRelease; + Animation zoomIconWhenRelease, moveUpIconWhenRelease; + Animation moveLeftIconLikeWhenRelease, + moveLeftIconLoveWhenRelease, + moveLeftIconHahaWhenRelease, + moveLeftIconWowWhenRelease, + moveLeftIconSadWhenRelease, + moveLeftIconAngryWhenRelease; + + Duration durationLongPress = Duration(milliseconds: 250); + Timer holdTimer; + bool isLongPress = false; + bool isLiked = false; + + // 0 = nothing, 1 = like, 2 = love, 3 = haha, 4 = wow, 5 = sad, 6 = angry + int whichIconUserChoose = 0; + + // 0 = nothing, 1 = like, 2 = love, 3 = haha, 4 = wow, 5 = sad, 6 = angry + int currentIconFocus = 0; + int previousIconFocus = 0; + bool isDragging = false; + bool isDraggingOutside = false; + bool isJustDragInside = true; + + @override + void initState() { + super.initState(); + + audioPlayer = AudioPlayer(); + + // Button Like + initAnimationBtnLike(); + + // Box and Icons + initAnimationBoxAndIcons(); + + // Icon when drag + initAnimationIconWhenDrag(); + + // Icon when drag outside + initAnimationIconWhenDragOutside(); + + // Box when drag outside + initAnimationBoxWhenDragOutside(); + + // Icon when first drag + initAnimationIconWhenDragInside(); + + // Icon when release + initAnimationIconWhenRelease(); + } + + initAnimationBtnLike() { + // long press + animControlBtnLongPress = + AnimationController(vsync: this, duration: Duration(milliseconds: durationAnimationBtnLongPress)); + zoomIconLikeInBtn = Tween(begin: 1.0, end: 0.85).animate(animControlBtnLongPress); + tiltIconLikeInBtn = Tween(begin: 0.0, end: 0.2).animate(animControlBtnLongPress); + zoomTextLikeInBtn = Tween(begin: 1.0, end: 0.85).animate(animControlBtnLongPress); + + zoomIconLikeInBtn.addListener(() { + setState(() {}); + }); + tiltIconLikeInBtn.addListener(() { + setState(() {}); + }); + zoomTextLikeInBtn.addListener(() { + setState(() {}); + }); + + // short press + animControlBtnShortPress = + AnimationController(vsync: this, duration: Duration(milliseconds: durationAnimationBtnShortPress)); + zoomIconLikeInBtn2 = Tween(begin: 1.0, end: 0.2).animate(animControlBtnShortPress); + tiltIconLikeInBtn2 = Tween(begin: 0.0, end: 0.8).animate(animControlBtnShortPress); + + zoomIconLikeInBtn2.addListener(() { + setState(() {}); + }); + tiltIconLikeInBtn2.addListener(() { + setState(() {}); + }); + } + + initAnimationBoxAndIcons() { + animControlBox = AnimationController(vsync: this, duration: Duration(milliseconds: durationAnimationBox)); + + // General + moveRightGroupIcon = Tween(begin: 0.0, end: 10.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.0, 1.0)), + ); + moveRightGroupIcon.addListener(() { + setState(() {}); + }); + + // Box + fadeInBox = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.7, 1.0)), + ); + fadeInBox.addListener(() { + setState(() {}); + }); + + // Icons + pushIconLikeUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.0, 0.5)), + ); + zoomIconLike = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.0, 0.5)), + ); + + pushIconLoveUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.1, 0.6)), + ); + zoomIconLove = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.1, 0.6)), + ); + + pushIconHahaUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.2, 0.7)), + ); + zoomIconHaha = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.2, 0.7)), + ); + + pushIconWowUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.3, 0.8)), + ); + zoomIconWow = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.3, 0.8)), + ); + + pushIconSadUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.4, 0.9)), + ); + zoomIconSad = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.4, 0.9)), + ); + + pushIconAngryUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.5, 1.0)), + ); + zoomIconAngry = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.5, 1.0)), + ); + + pushIconLikeUp.addListener(() { + setState(() {}); + }); + zoomIconLike.addListener(() { + setState(() {}); + }); + pushIconLoveUp.addListener(() { + setState(() {}); + }); + zoomIconLove.addListener(() { + setState(() {}); + }); + pushIconHahaUp.addListener(() { + setState(() {}); + }); + zoomIconHaha.addListener(() { + setState(() {}); + }); + pushIconWowUp.addListener(() { + setState(() {}); + }); + zoomIconWow.addListener(() { + setState(() {}); + }); + pushIconSadUp.addListener(() { + setState(() {}); + }); + zoomIconSad.addListener(() { + setState(() {}); + }); + pushIconAngryUp.addListener(() { + setState(() {}); + }); + zoomIconAngry.addListener(() { + setState(() {}); + }); + } + + initAnimationIconWhenDrag() { + animControlIconWhenDrag = + AnimationController(vsync: this, duration: Duration(milliseconds: durationAnimationIconWhenDrag)); + + zoomIconChosen = Tween(begin: 1.0, end: 1.8).animate(animControlIconWhenDrag); + zoomIconNotChosen = Tween(begin: 1.0, end: 0.8).animate(animControlIconWhenDrag); + zoomBoxIcon = Tween(begin: 50.0, end: 40.0).animate(animControlIconWhenDrag); + + zoomIconChosen.addListener(() { + setState(() {}); + }); + zoomIconNotChosen.addListener(() { + setState(() {}); + }); + zoomBoxIcon.addListener(() { + setState(() {}); + }); + } + + initAnimationIconWhenDragOutside() { + animControlIconWhenDragOutside = + AnimationController(vsync: this, duration: Duration(milliseconds: durationAnimationIconWhenDrag)); + zoomIconWhenDragOutside = Tween(begin: 0.8, end: 1.0).animate(animControlIconWhenDragOutside); + zoomIconWhenDragOutside.addListener(() { + setState(() {}); + }); + } + + initAnimationBoxWhenDragOutside() { + animControlBoxWhenDragOutside = + AnimationController(vsync: this, duration: Duration(milliseconds: durationAnimationIconWhenDrag)); + zoomBoxWhenDragOutside = Tween(begin: 40.0, end: 50.0).animate(animControlBoxWhenDragOutside); + zoomBoxWhenDragOutside.addListener(() { + setState(() {}); + }); + } + + initAnimationIconWhenDragInside() { + animControlIconWhenDragInside = + AnimationController(vsync: this, duration: Duration(milliseconds: durationAnimationIconWhenDrag)); + zoomIconWhenDragInside = Tween(begin: 1.0, end: 0.8).animate(animControlIconWhenDragInside); + zoomIconWhenDragInside.addListener(() { + setState(() {}); + }); + animControlIconWhenDragInside.addStatusListener((status) { + if (status == AnimationStatus.completed) { + isJustDragInside = false; + } + }); + } + + initAnimationIconWhenRelease() { + animControlIconWhenRelease = + AnimationController(vsync: this, duration: Duration(milliseconds: durationAnimationIconWhenRelease)); + + zoomIconWhenRelease = Tween(begin: 1.8, end: 0.0) + .animate(CurvedAnimation(parent: animControlIconWhenRelease, curve: Curves.decelerate)); + + moveUpIconWhenRelease = Tween(begin: 180.0, end: 0.0) + .animate(CurvedAnimation(parent: animControlIconWhenRelease, curve: Curves.decelerate)); + + moveLeftIconLikeWhenRelease = Tween(begin: 20.0, end: 10.0) + .animate(CurvedAnimation(parent: animControlIconWhenRelease, curve: Curves.decelerate)); + moveLeftIconLoveWhenRelease = Tween(begin: 68.0, end: 10.0) + .animate(CurvedAnimation(parent: animControlIconWhenRelease, curve: Curves.decelerate)); + moveLeftIconHahaWhenRelease = Tween(begin: 116.0, end: 10.0) + .animate(CurvedAnimation(parent: animControlIconWhenRelease, curve: Curves.decelerate)); + moveLeftIconWowWhenRelease = Tween(begin: 164.0, end: 10.0) + .animate(CurvedAnimation(parent: animControlIconWhenRelease, curve: Curves.decelerate)); + moveLeftIconSadWhenRelease = Tween(begin: 212.0, end: 10.0) + .animate(CurvedAnimation(parent: animControlIconWhenRelease, curve: Curves.decelerate)); + moveLeftIconAngryWhenRelease = Tween(begin: 260.0, end: 10.0) + .animate(CurvedAnimation(parent: animControlIconWhenRelease, curve: Curves.decelerate)); + + zoomIconWhenRelease.addListener(() { + setState(() {}); + }); + moveUpIconWhenRelease.addListener(() { + setState(() {}); + }); + + moveLeftIconLikeWhenRelease.addListener(() { + setState(() {}); + }); + moveLeftIconLoveWhenRelease.addListener(() { + setState(() {}); + }); + moveLeftIconHahaWhenRelease.addListener(() { + setState(() {}); + }); + moveLeftIconWowWhenRelease.addListener(() { + setState(() {}); + }); + moveLeftIconSadWhenRelease.addListener(() { + setState(() {}); + }); + moveLeftIconAngryWhenRelease.addListener(() { + setState(() {}); + }); + } + + @override + void dispose() { + super.dispose(); + animControlBtnLongPress.dispose(); + animControlBox.dispose(); + animControlIconWhenDrag.dispose(); + animControlIconWhenDragInside.dispose(); + animControlIconWhenDragOutside.dispose(); + animControlBoxWhenDragOutside.dispose(); + animControlIconWhenRelease.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + child: Column( + children: [ + // Just a top space + Container( + width: double.infinity, + height: 100.0, + ), + + // main content + Container( + child: Stack( + children: [ + // Box and icons + Stack( + children: [ + // Box + renderBox(), + + // Icons + renderIcons(), + ], + alignment: Alignment.bottomCenter, + ), + + // Button like + renderBtnLike(), + + // Icons when jump + // Icon like + whichIconUserChoose == 1 && !isDragging + ? Container( + child: Transform.scale( + child: Image.asset( + 'images/like.gif', + width: 40.0, + height: 40.0, + ), + scale: this.zoomIconWhenRelease.value, + ), + margin: EdgeInsets.only( + top: processTopPosition(this.moveUpIconWhenRelease.value), + left: this.moveLeftIconLikeWhenRelease.value, + ), + ) + : Container(), + + // Icon love + whichIconUserChoose == 2 && !isDragging + ? Container( + child: Transform.scale( + child: Image.asset( + 'images/love.gif', + width: 40.0, + height: 40.0, + ), + scale: this.zoomIconWhenRelease.value, + ), + margin: EdgeInsets.only( + top: processTopPosition(this.moveUpIconWhenRelease.value), + left: this.moveLeftIconLoveWhenRelease.value, + ), + ) + : Container(), + + // Icon haha + whichIconUserChoose == 3 && !isDragging + ? Container( + child: Transform.scale( + child: Image.asset( + 'images/haha.gif', + width: 40.0, + height: 40.0, + ), + scale: this.zoomIconWhenRelease.value, + ), + margin: EdgeInsets.only( + top: processTopPosition(this.moveUpIconWhenRelease.value), + left: this.moveLeftIconHahaWhenRelease.value, + ), + ) + : Container(), + + // Icon Wow + whichIconUserChoose == 4 && !isDragging + ? Container( + child: Transform.scale( + child: Image.asset( + 'images/wow.gif', + width: 40.0, + height: 40.0, + ), + scale: this.zoomIconWhenRelease.value, + ), + margin: EdgeInsets.only( + top: processTopPosition(this.moveUpIconWhenRelease.value), + left: this.moveLeftIconWowWhenRelease.value, + ), + ) + : Container(), + + // Icon sad + whichIconUserChoose == 5 && !isDragging + ? Container( + child: Transform.scale( + child: Image.asset( + 'images/sad.gif', + width: 40.0, + height: 40.0, + ), + scale: this.zoomIconWhenRelease.value, + ), + margin: EdgeInsets.only( + top: processTopPosition(this.moveUpIconWhenRelease.value), + left: this.moveLeftIconSadWhenRelease.value, + ), + ) + : Container(), + + // Icon angry + whichIconUserChoose == 6 && !isDragging + ? Container( + child: Transform.scale( + child: Image.asset( + 'images/angry.gif', + width: 40.0, + height: 40.0, + ), + scale: this.zoomIconWhenRelease.value, + ), + margin: EdgeInsets.only( + top: processTopPosition(this.moveUpIconWhenRelease.value), + left: this.moveLeftIconAngryWhenRelease.value, + ), + ) + : Container(), + ], + ), + margin: EdgeInsets.only(left: 20.0, right: 20.0), + // Area of the content can drag + // decoration: BoxDecoration(border: Border.all(color: Colors.grey)), + width: double.infinity, + height: 350.0, + ), + ], + ), + onHorizontalDragEnd: onHorizontalDragEndBoxIcon, + onHorizontalDragUpdate: onHorizontalDragUpdateBoxIcon, + ); + } + + Widget renderBox() { + return Opacity( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(30.0), + border: Border.all(color: Colors.grey[300], width: 0.3), + boxShadow: [ + BoxShadow( + color: Colors.grey, + blurRadius: 5.0, + // LTRB + offset: Offset.lerp(Offset(0.0, 0.0), Offset(0.0, 0.5), 10.0)), + ], + ), + width: 300.0, + height: isDragging + ? (previousIconFocus == 0 ? this.zoomBoxIcon.value : 40.0) + : isDraggingOutside ? this.zoomBoxWhenDragOutside.value : 50.0, + margin: EdgeInsets.only(bottom: 130.0, left: 10.0), + ), + opacity: this.fadeInBox.value, + ); + } + + Widget renderIcons() { + return Container( + child: Row( + children: [ + // icon like + Transform.scale( + child: Container( + child: Column( + children: [ + currentIconFocus == 1 + ? Container( + child: Text( + 'Like', + style: TextStyle(fontSize: 8.0, color: Colors.white), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), color: Colors.black.withOpacity(0.3)), + padding: EdgeInsets.only(left: 7.0, right: 7.0, top: 2.0, bottom: 2.0), + margin: EdgeInsets.only(bottom: 8.0), + ) + : Container(), + Image.asset( + 'images/like.gif', + width: 40.0, + height: 40.0, + fit: BoxFit.contain, + ), + ], + ), + margin: EdgeInsets.only(bottom: pushIconLikeUp.value), + width: 40.0, + height: currentIconFocus == 1 ? 70.0 : 40.0, + ), + scale: isDragging + ? (currentIconFocus == 1 + ? this.zoomIconChosen.value + : (previousIconFocus == 1 + ? this.zoomIconNotChosen.value + : isJustDragInside ? this.zoomIconWhenDragInside.value : 0.8)) + : isDraggingOutside ? this.zoomIconWhenDragOutside.value : this.zoomIconLike.value, + ), + + // icon love + Transform.scale( + child: Container( + child: Column( + children: [ + currentIconFocus == 2 + ? Container( + child: Text( + 'Love', + style: TextStyle(fontSize: 8.0, color: Colors.white), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), color: Colors.black.withOpacity(0.3)), + padding: EdgeInsets.only(left: 7.0, right: 7.0, top: 2.0, bottom: 2.0), + margin: EdgeInsets.only(bottom: 8.0), + ) + : Container(), + Image.asset( + 'images/love.gif', + width: 40.0, + height: 40.0, + fit: BoxFit.contain, + ), + ], + ), + margin: EdgeInsets.only(bottom: pushIconLoveUp.value), + width: 40.0, + height: currentIconFocus == 2 ? 70.0 : 40.0, + ), + scale: isDragging + ? (currentIconFocus == 2 + ? this.zoomIconChosen.value + : (previousIconFocus == 2 + ? this.zoomIconNotChosen.value + : isJustDragInside ? this.zoomIconWhenDragInside.value : 0.8)) + : isDraggingOutside ? this.zoomIconWhenDragOutside.value : this.zoomIconLove.value, + ), + + // icon haha + Transform.scale( + child: Container( + child: Column( + children: [ + currentIconFocus == 3 + ? Container( + child: Text( + 'Haha', + style: TextStyle(fontSize: 8.0, color: Colors.white), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), color: Colors.black.withOpacity(0.3)), + padding: EdgeInsets.only(left: 7.0, right: 7.0, top: 2.0, bottom: 2.0), + margin: EdgeInsets.only(bottom: 8.0), + ) + : Container(), + Image.asset( + 'images/haha.gif', + width: 40.0, + height: 40.0, + fit: BoxFit.contain, + ), + ], + ), + margin: EdgeInsets.only(bottom: pushIconHahaUp.value), + width: 40.0, + height: currentIconFocus == 3 ? 70.0 : 40.0, + ), + scale: isDragging + ? (currentIconFocus == 3 + ? this.zoomIconChosen.value + : (previousIconFocus == 3 + ? this.zoomIconNotChosen.value + : isJustDragInside ? this.zoomIconWhenDragInside.value : 0.8)) + : isDraggingOutside ? this.zoomIconWhenDragOutside.value : this.zoomIconHaha.value, + ), + + // icon wow + Transform.scale( + child: Container( + child: Column( + children: [ + currentIconFocus == 4 + ? Container( + child: Text( + 'Wow', + style: TextStyle(fontSize: 8.0, color: Colors.white), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), color: Colors.black.withOpacity(0.3)), + padding: EdgeInsets.only(left: 7.0, right: 7.0, top: 2.0, bottom: 2.0), + margin: EdgeInsets.only(bottom: 8.0), + ) + : Container(), + Image.asset( + 'images/wow.gif', + width: 40.0, + height: 40.0, + fit: BoxFit.contain, + ), + ], + ), + margin: EdgeInsets.only(bottom: pushIconWowUp.value), + width: 40.0, + height: currentIconFocus == 4 ? 70.0 : 40.0, + ), + scale: isDragging + ? (currentIconFocus == 4 + ? this.zoomIconChosen.value + : (previousIconFocus == 4 + ? this.zoomIconNotChosen.value + : isJustDragInside ? this.zoomIconWhenDragInside.value : 0.8)) + : isDraggingOutside ? this.zoomIconWhenDragOutside.value : this.zoomIconWow.value, + ), + + // icon sad + Transform.scale( + child: Container( + child: Column( + children: [ + currentIconFocus == 5 + ? Container( + child: Text( + 'Sad', + style: TextStyle(fontSize: 8.0, color: Colors.white), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), color: Colors.black.withOpacity(0.3)), + padding: EdgeInsets.only(left: 7.0, right: 7.0, top: 2.0, bottom: 2.0), + margin: EdgeInsets.only(bottom: 8.0), + ) + : Container(), + Image.asset( + 'images/sad.gif', + width: 40.0, + height: 40.0, + fit: BoxFit.contain, + ), + ], + ), + margin: EdgeInsets.only(bottom: pushIconSadUp.value), + width: 40.0, + height: currentIconFocus == 5 ? 70.0 : 40.0, + ), + scale: isDragging + ? (currentIconFocus == 5 + ? this.zoomIconChosen.value + : (previousIconFocus == 5 + ? this.zoomIconNotChosen.value + : isJustDragInside ? this.zoomIconWhenDragInside.value : 0.8)) + : isDraggingOutside ? this.zoomIconWhenDragOutside.value : this.zoomIconSad.value, + ), + + // icon angry + Transform.scale( + child: Container( + child: Column( + children: [ + currentIconFocus == 6 + ? Container( + child: Text( + 'Angry', + style: TextStyle(fontSize: 8.0, color: Colors.white), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), color: Colors.black.withOpacity(0.3)), + padding: EdgeInsets.only(left: 7.0, right: 7.0, top: 2.0, bottom: 2.0), + margin: EdgeInsets.only(bottom: 8.0), + ) + : Container(), + Image.asset( + 'images/angry.gif', + width: 40.0, + height: 40.0, + fit: BoxFit.contain, + ), + ], + ), + margin: EdgeInsets.only(bottom: pushIconAngryUp.value), + width: 40.0, + height: currentIconFocus == 6 ? 70.0 : 40.0, + ), + scale: isDragging + ? (currentIconFocus == 6 + ? this.zoomIconChosen.value + : (previousIconFocus == 6 + ? this.zoomIconNotChosen.value + : isJustDragInside ? this.zoomIconWhenDragInside.value : 0.8)) + : isDraggingOutside ? this.zoomIconWhenDragOutside.value : this.zoomIconAngry.value, + ), + ], + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + ), + width: 300.0, + height: 250.0, + margin: EdgeInsets.only(left: this.moveRightGroupIcon.value, top: 50.0), + // uncomment here to see area of draggable + // color: Colors.amber.withOpacity(0.5), + ); + } + + Widget renderBtnLike() { + return Container( + child: GestureDetector( + onTapDown: onTapDownBtn, + onTapUp: onTapUpBtn, + onTap: onTapBtn, + child: Container( + child: Row( + children: [ + // Icon like + Transform.scale( + child: Transform.rotate( + child: Image.asset( + getImageIconBtn(), + width: 25.0, + height: 25.0, + fit: BoxFit.contain, + color: getTintColorIconBtn(), + ), + angle: + !isLongPress ? handleOutputRangeTiltIconLike(tiltIconLikeInBtn2.value) : tiltIconLikeInBtn.value, + ), + scale: + !isLongPress ? handleOutputRangeZoomInIconLike(zoomIconLikeInBtn2.value) : zoomIconLikeInBtn.value, + ), + + // Text like + Transform.scale( + child: Text( + getTextBtn(), + style: TextStyle( + color: getColorTextBtn(), + fontSize: 14.0, + fontWeight: FontWeight.bold, + ), + ), + scale: + !isLongPress ? handleOutputRangeZoomInIconLike(zoomIconLikeInBtn2.value) : zoomTextLikeInBtn.value, + ), + ], + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + ), + padding: EdgeInsets.all(10.0), + color: Colors.transparent, + ), + ), + width: 100.0, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4.0), + color: Colors.white, + border: Border.all(color: getColorBorderBtn()), + ), + margin: EdgeInsets.only(top: 190.0), + ); + } + + String getTextBtn() { + if (isDragging) { + return 'Like'; + } + switch (whichIconUserChoose) { + case 1: + return 'Like'; + case 2: + return 'Love'; + case 3: + return 'Haha'; + case 4: + return 'Wow'; + case 5: + return 'Sad'; + case 6: + return 'Angry'; + default: + return 'Like'; + } + } + + Color getColorTextBtn() { + if ((!isLongPress && isLiked)) { + return Color(0xff3b5998); + } else if (!isDragging) { + switch (whichIconUserChoose) { + case 1: + return Color(0xff3b5998); + case 2: + return Color(0xffED5167); + case 3: + case 4: + case 5: + return Color(0xffFFD96A); + case 6: + return Color(0xffF6876B); + default: + return Colors.grey; + } + } else { + return Colors.grey; + } + } + + String getImageIconBtn() { + if (!isLongPress && isLiked) { + return 'images/ic_like_fill.png'; + } else if (!isDragging) { + switch (whichIconUserChoose) { + case 1: + return 'images/ic_like_fill.png'; + case 2: + return 'images/love2.png'; + case 3: + return 'images/haha2.png'; + case 4: + return 'images/wow2.png'; + case 5: + return 'images/sad2.png'; + case 6: + return 'images/angry2.png'; + default: + return 'images/ic_like.png'; + } + } else { + return 'images/ic_like.png'; + } + } + + Color getTintColorIconBtn() { + if (!isLongPress && isLiked) { + return Color(0xff3b5998); + } else if (!isDragging && whichIconUserChoose != 0) { + return null; + } else { + return Colors.grey; + } + } + + double processTopPosition(double value) { + // margin top 100 -> 40 -> 160 (value from 180 -> 0) + if (value >= 120.0) { + return value - 80.0; + } else { + return 160.0 - value; + } + } + + Color getColorBorderBtn() { + if ((!isLongPress && isLiked)) { + return Color(0xff3b5998); + } else if (!isDragging) { + switch (whichIconUserChoose) { + case 1: + return Color(0xff3b5998); + case 2: + return Color(0xffED5167); + case 3: + case 4: + case 5: + return Color(0xffFFD96A); + case 6: + return Color(0xffF6876B); + default: + return Colors.grey; + } + } else { + return Colors.grey[400]; + } + } + + void onHorizontalDragEndBoxIcon(DragEndDetails dragEndDetail) { + isDragging = false; + isDraggingOutside = false; + isJustDragInside = true; + previousIconFocus = 0; + currentIconFocus = 0; + + onTapUpBtn(null); + } + + void onHorizontalDragUpdateBoxIcon(DragUpdateDetails dragUpdateDetail) { + // return if the drag is drag without press button + if (!isLongPress) return; + + // the margin top the box is 150 + // and plus the height of toolbar and the status bar + // so the range we check is about 200 -> 500 + + if (dragUpdateDetail.globalPosition.dy >= 200 && dragUpdateDetail.globalPosition.dy <= 500) { + isDragging = true; + isDraggingOutside = false; + + if (isJustDragInside && !animControlIconWhenDragInside.isAnimating) { + animControlIconWhenDragInside.reset(); + animControlIconWhenDragInside.forward(); + } + + if (dragUpdateDetail.globalPosition.dx >= 20 && dragUpdateDetail.globalPosition.dx < 83) { + if (currentIconFocus != 1) { + handleWhenDragBetweenIcon(1); + } + } else if (dragUpdateDetail.globalPosition.dx >= 83 && dragUpdateDetail.globalPosition.dx < 126) { + if (currentIconFocus != 2) { + handleWhenDragBetweenIcon(2); + } + } else if (dragUpdateDetail.globalPosition.dx >= 126 && dragUpdateDetail.globalPosition.dx < 180) { + if (currentIconFocus != 3) { + handleWhenDragBetweenIcon(3); + } + } else if (dragUpdateDetail.globalPosition.dx >= 180 && dragUpdateDetail.globalPosition.dx < 233) { + if (currentIconFocus != 4) { + handleWhenDragBetweenIcon(4); + } + } else if (dragUpdateDetail.globalPosition.dx >= 233 && dragUpdateDetail.globalPosition.dx < 286) { + if (currentIconFocus != 5) { + handleWhenDragBetweenIcon(5); + } + } else if (dragUpdateDetail.globalPosition.dx >= 286 && dragUpdateDetail.globalPosition.dx < 340) { + if (currentIconFocus != 6) { + handleWhenDragBetweenIcon(6); + } + } + } else { + whichIconUserChoose = 0; + previousIconFocus = 0; + currentIconFocus = 0; + isJustDragInside = true; + + if (isDragging && !isDraggingOutside) { + isDragging = false; + isDraggingOutside = true; + animControlIconWhenDragOutside.reset(); + animControlIconWhenDragOutside.forward(); + animControlBoxWhenDragOutside.reset(); + animControlBoxWhenDragOutside.forward(); + } + } + } + + void handleWhenDragBetweenIcon(int currentIcon) { + playSound('icon_focus.mp3'); + whichIconUserChoose = currentIcon; + previousIconFocus = currentIconFocus; + currentIconFocus = currentIcon; + animControlIconWhenDrag.reset(); + animControlIconWhenDrag.forward(); + } + + void onTapDownBtn(TapDownDetails tapDownDetail) { + holdTimer = Timer(durationLongPress, showBox); + } + + void onTapUpBtn(TapUpDetails tapUpDetail) { + if (isLongPress) { + if (whichIconUserChoose == 0) { + playSound('box_down.mp3'); + } else { + playSound('icon_choose.mp3'); + } + } + + Timer(Duration(milliseconds: durationAnimationBox), () { + isLongPress = false; + }); + + holdTimer.cancel(); + + animControlBtnLongPress.reverse(); + + setReverseValue(); + animControlBox.reverse(); + + animControlIconWhenRelease.reset(); + animControlIconWhenRelease.forward(); + } + + // when user short press the button + void onTapBtn() { + if (!isLongPress) { + if (whichIconUserChoose == 0) { + isLiked = !isLiked; + } else { + whichIconUserChoose = 0; + } + if (isLiked) { + playSound('short_press_like.mp3'); + animControlBtnShortPress.forward(); + } else { + animControlBtnShortPress.reverse(); + } + } + } + + double handleOutputRangeZoomInIconLike(double value) { + if (value >= 0.8) { + return value; + } else if (value >= 0.4) { + return 1.6 - value; + } else { + return 0.8 + value; + } + } + + double handleOutputRangeTiltIconLike(double value) { + if (value <= 0.2) { + return value; + } else if (value <= 0.6) { + return 0.4 - value; + } else { + return -(0.8 - value); + } + } + + void showBox() { + playSound('box_up.mp3'); + isLongPress = true; + + animControlBtnLongPress.forward(); + + setForwardValue(); + animControlBox.forward(); + } + + // We need to set the value for reverse because if not + // the angry-icon will be pulled down first, not the like-icon + void setReverseValue() { + // Icons + pushIconLikeUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.5, 1.0)), + ); + zoomIconLike = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.5, 1.0)), + ); + + pushIconLoveUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.4, 0.9)), + ); + zoomIconLove = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.4, 0.9)), + ); + + pushIconHahaUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.3, 0.8)), + ); + zoomIconHaha = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.3, 0.8)), + ); + + pushIconWowUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.2, 0.7)), + ); + zoomIconWow = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.2, 0.7)), + ); + + pushIconSadUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.1, 0.6)), + ); + zoomIconSad = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.1, 0.6)), + ); + + pushIconAngryUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.0, 0.5)), + ); + zoomIconAngry = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.0, 0.5)), + ); + } + + // When set the reverse value, we need set value to normal for the forward + void setForwardValue() { + // Icons + pushIconLikeUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.0, 0.5)), + ); + zoomIconLike = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.0, 0.5)), + ); + + pushIconLoveUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.1, 0.6)), + ); + zoomIconLove = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.1, 0.6)), + ); + + pushIconHahaUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.2, 0.7)), + ); + zoomIconHaha = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.2, 0.7)), + ); + + pushIconWowUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.3, 0.8)), + ); + zoomIconWow = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.3, 0.8)), + ); + + pushIconSadUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.4, 0.9)), + ); + zoomIconSad = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.4, 0.9)), + ); + + pushIconAngryUp = Tween(begin: 30.0, end: 60.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.5, 1.0)), + ); + zoomIconAngry = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: animControlBox, curve: Interval(0.5, 1.0)), + ); + } + + Future playSound(String nameSound) async { + // Sometimes multiple sound will play the same time, so we'll stop all before play the + await audioPlayer.stop(); + final file = File('${(await getTemporaryDirectory()).path}/$nameSound'); + await file.writeAsBytes((await loadAsset(nameSound)).buffer.asUint8List()); + await audioPlayer.play(file.path, isLocal: true); + } + + Future loadAsset(String nameSound) async { + return await rootBundle.load('sounds/$nameSound'); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/fb_reaction_box/main.dart b/FlutterHelper/flutter_helper/lib/samples/fb_reaction_box/main.dart new file mode 100644 index 00000000..8a197fa7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/fb_reaction_box/main.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +import 'fb_reaction_box.dart'; + +void main() => runApp(FbReactionBoxApp()); + +class FbReactionBoxApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Facebook Reactions by Flutter', + theme: ThemeData(primaryColor: Color(0xff3b5998), accentColor: Color(0xff3b5998)), + debugShowCheckedModeBanner: false, + home: Scaffold( + appBar: AppBar( + title: Text('MAIN'), + centerTitle: true, + ), + body: MainScreen())); + } +} + +class MainScreen extends StatefulWidget { + @override + State createState() => MainScreenState(); +} + +class MainScreenState extends State { + static List timeDelays = [1.0, 2.0, 3.0, 4.0, 5.0]; + int selectedIndex = 0; + + onSpeedSettingPress(int index) { + timeDilation = timeDelays[index]; + setState(() { + selectedIndex = index; + }); + } + + buildList() { + final List list = [ + Text( + 'SPEED:', + style: TextStyle(fontSize: 12.0, fontWeight: FontWeight.bold), + ) + ]; + + timeDelays.asMap().forEach((index, delay) { + list.add(Container( + child: GestureDetector( + onTap: () => onSpeedSettingPress(index), + child: Container( + child: Text(delay.toString(), style: TextStyle(color: Colors.white)), + padding: EdgeInsets.all(10.0), + decoration: BoxDecoration( + color: index == selectedIndex ? Color(0xff3b5998) : Color(0xffDAA520), + borderRadius: BorderRadius.circular(20.0), + ), + ), + ), + margin: EdgeInsets.all(5.0), + )); + }); + + return list; + } + + @override + Widget build(BuildContext context) { + return Material( + child: Center( + child: Column( + children: [ + Container( + child: Row(children: buildList()), + margin: EdgeInsets.only(left: 20.0, right: 20.0, top: 20.0, bottom: 10.0), + ), + Container( + height: 15.0, + ), + buildButton(context, 'Facebook reactions animation', FbReactionBox()) + ], + )), + ); + } + + Widget buildButton(BuildContext context, String name, StatelessWidget screenTo) { + return FlatButton( + onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => screenTo)), + child: Container( + child: Text( + name, + style: TextStyle(color: Colors.white, fontSize: 16.0), + textAlign: TextAlign.center, + ), + width: 270.0, + ), + color: Color(0xff3b5998), + highlightColor: Color(0xff8b9dc3), + padding: EdgeInsets.all(12.0), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flip_panel/flip_panel.dart b/FlutterHelper/flutter_helper/lib/samples/flip_panel/flip_panel.dart new file mode 100644 index 00000000..76c21bf6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flip_panel/flip_panel.dart @@ -0,0 +1,773 @@ +/// +/// * author: hunghd +/// * email: hunghd.yb@gmail.com +/// +/// * contributors: Emily Fortuna (efortuna), Sunit Gautam (gsunit) +/// +/// A package provides a [Widget] that simulates the 3D flip effect on flipclock +/// +/// + +library flip_panel; + +import 'package:flutter/material.dart'; +import 'dart:async'; +import 'dart:math' as math; + +typedef Widget DigitBuilder(BuildContext, int); + +/// +/// A [Widget] provides a simple implementation of a flipclock using [FlipPanel] +/// +@immutable +class FlipClock extends StatelessWidget { + DigitBuilder _digitBuilder; + Widget _separator; + final DateTime startTime; + final EdgeInsets spacing; + final FlipDirection flipDirection; + + /// Set countdown to true to have a countdown timer. + final bool countdownMode; + + final bool _showHours; + final bool _showDays; + + Duration timeLeft; + + /// Called when the countdown clock hits zero. + final VoidCallback onDone; + + final double height; + final double width; + + FlipClock({ + Key key, + @required DigitBuilder digitBuilder, + @required Widget separator, + @required this.startTime, + this.countdownMode = false, + this.spacing = const EdgeInsets.symmetric(horizontal: 2.0), + this.flipDirection = FlipDirection.down, + this.height = 44.0, + this.width = 60.0, + this.timeLeft, + }) : _showHours = true, + _showDays = false, + _digitBuilder = digitBuilder, + _separator = separator, + onDone = null; + + FlipClock.simple({ + Key key, + @required this.startTime, + @required Color digitColor, + @required Color backgroundColor, + @required double digitSize, + BorderRadius borderRadius = const BorderRadius.all(Radius.circular(0.0)), + this.spacing = const EdgeInsets.symmetric(horizontal: 2.0), + this.flipDirection = FlipDirection.down, + this.height = 60.0, + this.width = 44.0, + this.timeLeft, + }) : countdownMode = false, + _showHours = true, + _showDays = false, + onDone = null { + _digitBuilder = (context, digit) => Container( + alignment: Alignment.center, + width: width, + height: height, + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: borderRadius, + ), + child: Text( + '$digit', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: digitSize, + color: digitColor), + ), + ); + _separator = Container( + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: borderRadius, + ), + width: width / 2, + height: height, + alignment: Alignment.center, + child: Text( + ':', + style: TextStyle( + fontSize: digitSize, + color: digitColor, + ), + ), + ); + } + + FlipClock.countdown({ + Key key, + @required Duration duration, + @required Color digitColor, + @required Color backgroundColor, + @required double digitSize, + BorderRadius borderRadius = const BorderRadius.all(Radius.circular(0.0)), + this.spacing = const EdgeInsets.symmetric(horizontal: 2.0), + this.onDone, + this.flipDirection = FlipDirection.down, + this.height = 60.0, + this.width = 44.0, + this.startTime, + }) : countdownMode = true, + timeLeft = duration, + _showHours = duration.inHours > 0, + _showDays = false { + _digitBuilder = (context, digit) => Container( + alignment: Alignment.center, + width: width, + height: height, + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: borderRadius, + ), + child: Text( + '$digit', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: digitSize, + color: digitColor), + ), + ); + _separator = Container( + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: borderRadius, + ), + width: width / 2, + height: height, + alignment: Alignment.center, + child: Text( + ':', + style: TextStyle( + fontSize: digitSize, + color: digitColor, + ), + ), + ); + } + + FlipClock.reverseCountdown({ + Key key, + // @required DateTime now, + // @required DateTime dDay, + @required Duration duration, + @required Color digitColor, + @required Color backgroundColor, + @required double digitSize, + BorderRadius borderRadius = const BorderRadius.all(Radius.circular(0.0)), + this.spacing = const EdgeInsets.symmetric(horizontal: 2.0), + this.onDone, + this.flipDirection = FlipDirection.down, + this.height = 40.0, + this.width = 24.0, + }) : countdownMode = true, + startTime = DateTime(2018, 0, 0, 0, 0, duration.inSeconds), + _showHours = true, + _showDays = true, + timeLeft = duration { + _digitBuilder = (context, digit) => Container( + alignment: Alignment.center, + width: width, + height: height, + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: borderRadius, + ), + child: Text( + '$digit', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: digitSize, + color: digitColor), + ), + ); + _separator = Container( + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: borderRadius, + ), + width: width / 2, + height: height, + alignment: Alignment.center, + child: Text( + ':', + style: TextStyle( + fontSize: digitSize, + color: digitColor, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + var time = startTime; + final initStream = + Stream.periodic(Duration(milliseconds: 1000), (_) { + var oldTime = time; + (countdownMode) + ? timeLeft = timeLeft - Duration(seconds: 1) + : time = time.add(Duration(seconds: 1)); + + if (!countdownMode && oldTime.day != time.day) { + time = oldTime; + if (onDone != null) onDone(); + } + + return time; + }); + final timeStream = + (countdownMode ? initStream.take(timeLeft.inSeconds) : initStream) + .asBroadcastStream(); + + var digitList = []; + // double(efortuna): Instead, allow the user to specify the format of time instead. + // Add hours if appropriate. + + if (_showDays) { + digitList.addAll([ + _buildSegment( + timeStream, + (DateTime time) => + (timeLeft.inDays > 99) ? 9 : (timeLeft.inDays ~/ 10), + (DateTime time) => + (timeLeft.inDays > 99) ? 9 : (timeLeft.inDays % 10), + startTime, + "days"), + Column( + children: [ + Padding( + padding: spacing, + child: _separator, + ), + (_showDays) + ? Container(color: Colors.black) + : Container( + color: Colors.transparent, + ) + ], + ) + ]); + } + + if (_showHours) { + digitList.addAll([ + _buildSegment( + timeStream, + (DateTime time) => (countdownMode) + ? (timeLeft.inHours % 24) ~/ 10 + : (time.hour) ~/ 10, + (DateTime time) => (countdownMode) + ? (timeLeft.inHours % 24) % 10 + : (time.hour) % 10, + startTime, + "Hours"), + Column( + children: [ + Padding( + padding: spacing, + child: _separator, + ), + (_showDays) + ? Container(color: Colors.black) + : Container( + color: Colors.transparent, + ) + ], + ) + ]); + } + return Row( + mainAxisSize: MainAxisSize.min, + children: digitList + ..addAll([ + // Minutes + _buildSegment( + timeStream, + (DateTime time) => (countdownMode) + ? (timeLeft.inMinutes % 60) ~/ 10 + : (time.minute) ~/ 10, + (DateTime time) => (countdownMode) + ? (timeLeft.inMinutes % 60) % 10 + : (time.minute) % 10, + startTime, + "minutes"), + + Column( + children: [ + Padding( + padding: spacing, + child: _separator, + ), + (_showDays) + ? Container(color: Colors.black) + : Container( + color: Colors.transparent, + ) + ], + ), + + // Seconds + _buildSegment( + timeStream, + (DateTime time) => (countdownMode) + ? (timeLeft.inSeconds % 60) ~/ 10 + : (time.second) ~/ 10, + (DateTime time) => (countdownMode) + ? (timeLeft.inSeconds % 60) % 10 + : (time.second) % 10, + startTime, + "seconds") + ]), + ); + } + + _buildSegment(Stream timeStream, Function tensDigit, + Function onesDigit, DateTime startTime, String id) { + return Column( + children: [ + Row(children: [ + Padding( + padding: spacing, + child: FlipPanel.stream( + itemStream: timeStream.map(tensDigit), + itemBuilder: _digitBuilder, + duration: const Duration(milliseconds: 450), + initValue: tensDigit(startTime), + direction: flipDirection, + ), + ), + Padding( + padding: spacing, + child: FlipPanel.stream( + itemStream: timeStream.map(onesDigit), + itemBuilder: _digitBuilder, + duration: const Duration(milliseconds: 450), + initValue: onesDigit(startTime), + direction: flipDirection, + ), + ), + ]), + (_showDays) + ? Row( + children: [ + Padding( + padding: const EdgeInsets.all(1.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(3.0), + child: Container( + decoration: BoxDecoration( + color: Colors.black, + ), + child: Padding( + padding: const EdgeInsets.all(2.0), + child: Text( + id.toUpperCase(), + style: TextStyle( + color: Colors.white, + fontSize: 8.0, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + ) + ], + ) + : Row() + ], + ); + } +} + +/// +/// Signature for a function that creates a widget for a given index, e.g., in a +/// list. +/// +typedef Widget IndexedItemBuilder(BuildContext, int); + +/// +/// Signature for a function that creates a widget for a value emitted from a [Stream] +/// +typedef Widget StreamItemBuilder(BuildContext, T); + +/// +/// An enum defines all supported directions of [FlipPanel] +/// +enum FlipDirection { up, down } + +/// +/// A [Widget] provides 3D flipp animation on a panel. The content of each panel +/// is built from [IndexedItemBuilder] or [StreamItemBuilder] +/// +/// Note: The size of every panel should be the same and the panel should be +/// a static [Widget] (which is an instance of [StatelessWidget]) +/// +class FlipPanel extends StatefulWidget { + final IndexedItemBuilder indexedItemBuilder; + final StreamItemBuilder streamItemBuilder; + final Stream itemStream; + final int itemsCount; + final Duration period; + final Duration duration; + final int loop; + final int startIndex; + final T initValue; + final double spacing; + final FlipDirection direction; + + FlipPanel({ + Key key, + this.indexedItemBuilder, + this.streamItemBuilder, + this.itemStream, + this.itemsCount, + this.period, + this.duration, + this.loop, + this.startIndex, + this.initValue, + this.spacing, + this.direction, + }) : super(key: key); + + /// + /// Create a flip panel from iterable source + /// + /// * [itemBuilder] is called periodically in each time of [period] + /// * The animation is looped in [loop] times before finished. + /// Setting [loop] to -1 makes flip animation run forever. + /// * The [period] should be two times greater than [duration] of flip animation, + /// otherwise the animation becomes jerky/stuttery. + /// + FlipPanel.builder({ + Key key, + @required IndexedItemBuilder itemBuilder, + @required this.itemsCount, + @required this.period, + this.duration = const Duration(milliseconds: 500), + this.loop = 1, + this.startIndex = 0, + this.spacing = 0.5, + this.direction = FlipDirection.down, + }) : assert(itemBuilder != null), + assert(itemsCount != null), + assert(startIndex < itemsCount), + assert(period == null || + period.inMilliseconds >= 2 * duration.inMilliseconds), + indexedItemBuilder = itemBuilder, + streamItemBuilder = null, + itemStream = null, + initValue = null, + super(key: key); + + /// + /// Create a flip panel from stream source + /// + /// * [itemBuilder] is called whenever a new value is emitted from [itemStream] + /// + FlipPanel.stream({ + Key key, + @required this.itemStream, + @required StreamItemBuilder itemBuilder, + this.initValue, + this.duration = const Duration(milliseconds: 500), + this.spacing = 0.5, + this.direction = FlipDirection.down, + }) : assert(itemStream != null), + indexedItemBuilder = null, + streamItemBuilder = itemBuilder, + itemsCount = 0, + period = null, + loop = 0, + startIndex = 0, + super(key: key); + + @override + _FlipPanelState createState() => _FlipPanelState(); +} + +class _FlipPanelState extends State + with SingleTickerProviderStateMixin { + AnimationController _controller; + Animation _animation; + int _currentIndex; + bool _isReversePhase; + bool _isStreamMode; + bool _running; + final _perspective = 0.003; + final _zeroAngle = + 0.0001; // There's something wrong in the perspective transform, I use a very small value instead of zero to temporarily get it around. + int _loop; + T _currentValue, _nextValue; + Timer _timer; + StreamSubscription _subscription; + + Widget _child1, _child2; + Widget _upperChild1, _upperChild2; + Widget _lowerChild1, _lowerChild2; + + @override + void initState() { + super.initState(); + _currentIndex = widget.startIndex; + _isStreamMode = widget.itemStream != null; + _isReversePhase = false; + _running = false; + _loop = 0; + + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + _isReversePhase = true; + _controller.reverse(); + } + if (status == AnimationStatus.dismissed) { + _currentValue = _nextValue; + _running = false; + } + }) + ..addListener(() { + setState(() { + _running = true; + }); + }); + _animation = + Tween(begin: _zeroAngle, end: math.pi / 2).animate(_controller); + + if (widget.period != null) { + _timer = Timer.periodic(widget.period, (_) { + if (widget.loop < 0 || _loop < widget.loop) { + if (_currentIndex + 1 == widget.itemsCount - 2) { + _loop++; + } + _currentIndex = (_currentIndex + 1) % widget.itemsCount; + _child1 = null; + _isReversePhase = false; + _controller.forward(); + } else { + _timer.cancel(); + _currentIndex = (_currentIndex + 1) % widget.itemsCount; + setState(() { + _running = false; + }); + } + }); + } + + if (_isStreamMode) { + _currentValue = widget.initValue; + _subscription = widget.itemStream.distinct().listen((value) { + if (_currentValue == null) { + _currentValue = value; + } else if (value != _currentValue) { + _nextValue = value; + _child1 = null; + _isReversePhase = false; + _controller.forward(); + } + }); + } else if (widget.loop < 0 || _loop < widget.loop) { + _controller.forward(); + } + } + + @override + void dispose() { + _controller.dispose(); + if (_subscription != null) _subscription.cancel(); + if (_timer != null) _timer.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _buildChildWidgetsIfNeed(context); + + return _buildPanel(); + } + + void _buildChildWidgetsIfNeed(BuildContext context) { + Widget makeUpperClip(Widget widget) { + return ClipRect( + child: Align( + alignment: Alignment.topCenter, + heightFactor: 0.5, + child: widget, + ), + ); + } + + Widget makeLowerClip(Widget widget) { + return ClipRect( + child: Align( + alignment: Alignment.bottomCenter, + heightFactor: 0.5, + child: widget, + ), + ); + } + + if (_running) { + if (_child1 == null) { + _child1 = _child2 != null + ? _child2 + : _isStreamMode + ? widget.streamItemBuilder(context, _currentValue) + : widget.indexedItemBuilder( + context, _currentIndex % widget.itemsCount); + _child2 = null; + _upperChild1 = + _upperChild2 != null ? _upperChild2 : makeUpperClip(_child1); + _lowerChild1 = + _lowerChild2 != null ? _lowerChild2 : makeLowerClip(_child1); + } + if (_child2 == null) { + _child2 = _isStreamMode + ? widget.streamItemBuilder(context, _nextValue) + : widget.indexedItemBuilder( + context, (_currentIndex + 1) % widget.itemsCount); + _upperChild2 = makeUpperClip(_child2); + _lowerChild2 = makeLowerClip(_child2); + } + } else { + _child1 = _child2 != null + ? _child2 + : _isStreamMode + ? widget.streamItemBuilder(context, _currentValue) + : widget.indexedItemBuilder( + context, _currentIndex % widget.itemsCount); + _upperChild1 = + _upperChild2 != null ? _upperChild2 : makeUpperClip(_child1); + _lowerChild1 = + _lowerChild2 != null ? _lowerChild2 : makeLowerClip(_child1); + } + } + + Widget _buildUpperFlipPanel() => widget.direction == FlipDirection.up + ? Stack( + children: [ + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _upperChild1), + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_isReversePhase ? _animation.value : math.pi / 2), + child: _upperChild2, + ), + ], + ) + : Stack( + children: [ + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _upperChild2), + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_isReversePhase ? math.pi / 2 : _animation.value), + child: _upperChild1, + ), + ], + ); + + Widget _buildLowerFlipPanel() => widget.direction == FlipDirection.up + ? Stack( + children: [ + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _lowerChild2), + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_isReversePhase ? math.pi / 2 : -_animation.value), + child: _lowerChild1, + ) + ], + ) + : Stack( + children: [ + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _lowerChild1), + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_isReversePhase ? -_animation.value : math.pi / 2), + child: _lowerChild2, + ) + ], + ); + + Widget _buildPanel() { + return _running + ? Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildUpperFlipPanel(), + Padding( + padding: EdgeInsets.only(top: widget.spacing), + ), + _buildLowerFlipPanel(), + ], + ) + : _isStreamMode && _currentValue == null + ? Container() + : Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _upperChild1), + Padding( + padding: EdgeInsets.only(top: widget.spacing), + ), + Transform( + alignment: Alignment.topCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, _perspective) + ..rotateX(_zeroAngle), + child: _lowerChild1) + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flip_panel/main.dart b/FlutterHelper/flutter_helper/lib/samples/flip_panel/main.dart new file mode 100644 index 00000000..99d77d73 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flip_panel/main.dart @@ -0,0 +1,252 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter_helper/samples/flip_panel/flip_panel.dart'; + +void main() => runApp(new FlipPanelApp()); + +class FlipPanelApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData.light().copyWith( + scaffoldBackgroundColor: Colors.white, + ), + title: 'FlipPanel', + routes: { + 'flip_image': (_) => AnimatedImagePage(), + 'flip_clock': (_) => FlipClockPage(), + 'countdown_clock': (_) => CountdownClockPage(), + 'reverse_countdown': (_) => ReverseCountdown(), + }, + home: HomePage(), + ); + } +} + +class HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('FlipPanel'), + ), + body: Column( + children: [ + ListTile( + title: Text('FlipImage'), + onTap: () => Navigator.of(context).pushNamed('flip_image'), + ), + ListTile( + title: Text('FlipClock'), + onTap: () => Navigator.of(context).pushNamed('flip_clock'), + ), + ListTile( + title: Text('CountdownClock'), + onTap: () => Navigator.of(context).pushNamed('countdown_clock'), + ), + ListTile( + title: Text('DaysToGo'), + onTap: () => Navigator.of(context).pushNamed('reverse_countdown'), + ), + ], + ), + ); + } +} + +class AnimatedImagePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final imageWidth = 320.0; + final imageHeight = 171.0; + final toleranceFactor = 0.033; + final widthFactor = 0.125; + final heightFactor = 0.5; + + final random = Random(); + + return Scaffold( + appBar: AppBar( + title: Text('FlipImage'), + ), + body: Container( + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + ] + .map((count) => FlipPanel.stream( + itemStream: Stream.fromFuture(Future.delayed( + Duration(milliseconds: random.nextInt(20) * 100), + () => 1)), + itemBuilder: (_, value) => value <= 0 + ? Container( + color: Colors.white, + width: widthFactor * imageWidth, + height: heightFactor * imageHeight, + ) + : ClipRect( + child: Align( + alignment: Alignment( + -1.0 + + count * 2 * 0.125 + + count * toleranceFactor, + -1.0), + widthFactor: widthFactor, + heightFactor: heightFactor, + child: Image.asset( + 'assets/flutter_cover.png', + width: imageWidth, + height: imageHeight, + ))), + initValue: 0, + spacing: 0.0, + direction: FlipDirection.up, + )) + .toList(), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + ] + .map((count) => FlipPanel.stream( + itemStream: Stream.fromFuture(Future.delayed( + Duration(milliseconds: random.nextInt(20) * 100), + () => 1)), + itemBuilder: (_, value) => value <= 0 + ? Container( + color: Colors.white, + width: widthFactor * imageWidth, + height: heightFactor * imageHeight, + ) + : ClipRect( + child: Align( + alignment: Alignment( + -1.0 + + count * 2 * 0.125 + + count * toleranceFactor, + 1.0), + widthFactor: widthFactor, + heightFactor: heightFactor, + child: Image.asset( + 'assets/flutter_cover.png', + width: imageWidth, + height: imageHeight, + ))), + initValue: 0, + spacing: 0.0, + direction: FlipDirection.down, + )) + .toList(), + ) + ], + ), + ), + ), + ); + } +} + +class FlipClockPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('FlipClock'), + ), + body: Center( + child: SizedBox( + height: 64.0, + child: FlipClock.simple( + startTime: DateTime.now(), + digitColor: Colors.white, + backgroundColor: Colors.black, + digitSize: 48.0, + borderRadius: const BorderRadius.all(Radius.circular(3.0)), + ), + ), + ), + ); + } +} + +class CountdownClockPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('FlipClock'), + ), + body: Center( + child: SizedBox( + height: 64.0, + child: FlipClock.countdown( + duration: Duration(minutes: 1), + digitColor: Colors.white, + backgroundColor: Colors.black, + digitSize: 48.0, + borderRadius: const BorderRadius.all(Radius.circular(3.0)), + onDone: () => print('ih'), + ), + ), + ), + ); + } +} + +class ReverseCountdown extends StatelessWidget { + //when using reverse countdown in your own app, change debugMode to false and provide the requied dDay values. + final bool debugMode = true; + DateTime now = DateTime.now(); + DateTime dDay = DateTime(2018, 11, 26, 0, 0, 0); + + @override + Widget build(BuildContext context) { + dDay = (debugMode) + ? DateTime(now.year, now.month + 2, now.day, now.hour, now.minute, + now.second + 10) + : dDay; + + Duration _duration = dDay.difference(now); + + return Scaffold( + appBar: AppBar( + title: Text('ReverseCountdown'), + ), + body: Center( + child: SizedBox( + height: 64.0, + child: FlipClock.reverseCountdown( + duration: _duration, + digitColor: Colors.white, + backgroundColor: Colors.black, + digitSize: 30.0, + borderRadius: const BorderRadius.all(Radius.circular(3.0)), + //onDone: () => print('ih'), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar.dart b/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar.dart new file mode 100644 index 00000000..dc1da81d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar.dart @@ -0,0 +1,758 @@ +import 'dart:async'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +import 'flushbar_route.dart' as route; + +const String FLUSHBAR_ROUTE_NAME = "/flushbarRoute"; + +typedef void FlushbarStatusCallback(FlushbarStatus status); +typedef void OnTap(Flushbar flushbar); + +/// A highly customizable widget so you can notify your user when you fell like he needs a beautiful explanation. +class Flushbar extends StatefulWidget { + Flushbar( + {Key key, + String title, + String message, + Widget titleText, + Widget messageText, + Widget icon, + bool shouldIconPulse = true, + double maxWidth, + EdgeInsets margin = const EdgeInsets.all(0.0), + EdgeInsets padding = const EdgeInsets.all(16), + double borderRadius = 0.0, + Color borderColor, + double borderWidth = 1.0, + Color backgroundColor = const Color(0xFF303030), + Color leftBarIndicatorColor, + List boxShadows, + Gradient backgroundGradient, + Widget mainButton, + OnTap onTap, + Duration duration, + bool isDismissible = true, + FlushbarDismissDirection dismissDirection = + FlushbarDismissDirection.VERTICAL, + bool showProgressIndicator = false, + AnimationController progressIndicatorController, + Color progressIndicatorBackgroundColor, + Animation progressIndicatorValueColor, + FlushbarPosition flushbarPosition = FlushbarPosition.BOTTOM, + FlushbarStyle flushbarStyle = FlushbarStyle.FLOATING, + Curve forwardAnimationCurve = Curves.easeOutCirc, + Curve reverseAnimationCurve = Curves.easeOutCirc, + Duration animationDuration = const Duration(seconds: 1), + FlushbarStatusCallback onStatusChanged, + double barBlur = 0.0, + bool blockBackgroundInteraction = false, + double routeBlur, + Color routeColor, + Form userInputForm}) + : this.title = title, + this.message = message, + this.titleText = titleText, + this.messageText = messageText, + this.icon = icon, + this.shouldIconPulse = shouldIconPulse, + this.maxWidth = maxWidth, + this.margin = margin, + this.padding = padding, + this.borderRadius = borderRadius, + this.borderColor = borderColor, + this.borderWidth = borderWidth, + this.backgroundColor = backgroundColor, + this.leftBarIndicatorColor = leftBarIndicatorColor, + this.boxShadows = boxShadows, + this.backgroundGradient = backgroundGradient, + this.mainButton = mainButton, + this.onTap = onTap, + this.duration = duration, + this.isDismissible = isDismissible, + this.dismissDirection = dismissDirection, + this.showProgressIndicator = showProgressIndicator, + this.progressIndicatorController = progressIndicatorController, + this.progressIndicatorBackgroundColor = + progressIndicatorBackgroundColor, + this.progressIndicatorValueColor = progressIndicatorValueColor, + this.flushbarPosition = flushbarPosition, + this.flushbarStyle = flushbarStyle, + this.forwardAnimationCurve = forwardAnimationCurve, + this.reverseAnimationCurve = reverseAnimationCurve, + this.animationDuration = animationDuration, + this.barBlur = barBlur, + this.blockBackgroundInteraction = blockBackgroundInteraction, + this.routeBlur = routeBlur, + this.routeColor = routeColor, + this.userInputForm = userInputForm, + super(key: key) { + this.onStatusChanged = onStatusChanged ?? (status) {}; + } + + /// A callback for you to listen to the different Flushbar status + FlushbarStatusCallback onStatusChanged; + + /// The title displayed to the user + final String title; + + /// The message displayed to the user. + final String message; + + /// Replaces [title]. Although this accepts a [Widget], it is meant to receive [Text] or [RichText] + final Widget titleText; + + /// Replaces [message]. Although this accepts a [Widget], it is meant to receive [Text] or [RichText] + final Widget messageText; + + /// Will be ignored if [backgroundGradient] is not null + final Color backgroundColor; + + /// If not null, shows a left vertical bar to better indicate the humor of the notification. + /// It is not possible to use it with a [Form] and I do not recommend using it with [LinearProgressIndicator] + final Color leftBarIndicatorColor; + + /// [boxShadows] The shadows generated by Flushbar. Leave it null if you don't want a shadow. + /// You can use more than one if you feel the need. + /// Check (this example)[https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/shadows.dart] + final List boxShadows; + + /// Makes [backgroundColor] be ignored. + final Gradient backgroundGradient; + + /// You can use any widget here, but I recommend [Icon] or [Image] as indication of what kind + /// of message you are displaying. Other widgets may break the layout + final Widget icon; + + /// An option to animate the icon (if present). Defaults to true. + final bool shouldIconPulse; + + /// Use if you need an action from the user. [FlatButton] is recommended here + final Widget mainButton; + + /// A callback that registers the user's click anywhere. An alternative to [mainButton] + final OnTap onTap; + + /// How long until Flushbar will hide itself (be dismissed). To make it indefinite, leave it null. + final Duration duration; + + /// True if you want to show a [LinearProgressIndicator]. + /// If [progressIndicatorController] is null, an infinite progress indicator will be shown + final bool showProgressIndicator; + + /// An optional [AnimationController] when you want to control the progress of your [LinearProgressIndicator]. + /// You are responsible for controlling the progress + final AnimationController progressIndicatorController; + + /// A [LinearProgressIndicator] configuration parameter. + final Color progressIndicatorBackgroundColor; + + /// A [LinearProgressIndicator] configuration parameter. + final Animation progressIndicatorValueColor; + + /// Determines if the user can swipe or click the overlay (if [routeBlur] > 0) to dismiss. + /// It is recommended that you set [duration] != null if this is false. + /// If the user swipes to dismiss or clicks the overlay, no value will be returned. + final bool isDismissible; + + /// Used to limit Flushbar width (usually on large screens) + final double maxWidth; + + /// Adds a custom margin to Flushbar + final EdgeInsets margin; + + /// Adds a custom padding to Flushbar + /// The default follows material design guide line + final EdgeInsets padding; + + /// Adds a radius to all corners of Flushbar. Best combined with [margin]. + /// I do not recommend using it with [showProgressIndicator] or [leftBarIndicatorColor]. + final double borderRadius; + + /// Adds a border to every side of Flushbar + /// I do not recommend using it with [showProgressIndicator] or [leftBarIndicatorColor]. + final Color borderColor; + + /// Changes the width of the border if [borderColor] is specified + final double borderWidth; + + /// Flushbar can be based on [FlushbarPosition.TOP] or on [FlushbarPosition.BOTTOM] of your screen. + /// [FlushbarPosition.BOTTOM] is the default. + final FlushbarPosition flushbarPosition; + + /// [FlushbarDismissDirection.VERTICAL] by default. + /// Can also be [FlushbarDismissDirection.HORIZONTAL] in which case both left and right dismiss are allowed. + final FlushbarDismissDirection dismissDirection; + + /// Flushbar can be floating or be grounded to the edge of the screen. + /// If grounded, I do not recommend using [margin] or [borderRadius]. [FlushbarStyle.FLOATING] is the default + /// If grounded, I do not recommend using a [backgroundColor] with transparency or [barBlur] + final FlushbarStyle flushbarStyle; + + /// The [Curve] animation used when show() is called. [Curves.easeOut] is default + final Curve forwardAnimationCurve; + + /// The [Curve] animation used when dismiss() is called. [Curves.fastOutSlowIn] is default + final Curve reverseAnimationCurve; + + /// Use it to speed up or slow down the animation duration + final Duration animationDuration; + + /// Default is 0.0. If different than 0.0, blurs only Flushbar's background. + /// To take effect, make sure your [backgroundColor] has some opacity. + /// The greater the value, the greater the blur. + final double barBlur; + + /// Determines if user can interact with the screen behind it + /// If this is false, [routeBlur] and [routeColor] will be ignored + final bool blockBackgroundInteraction; + + /// Default is 0.0. If different than 0.0, creates a blurred + /// overlay that prevents the user from interacting with the screen. + /// The greater the value, the greater the blur. + /// It does not take effect if [blockBackgroundInteraction] is false + final double routeBlur; + + /// Default is [Colors.transparent]. Only takes effect if [routeBlur] > 0.0. + /// Make sure you use a color with transparency here e.g. Colors.grey[600].withOpacity(0.2). + /// It does not take effect if [blockBackgroundInteraction] is false + final Color routeColor; + + /// A [TextFormField] in case you want a simple user input. Every other widget is ignored if this is not null. + final Form userInputForm; + + route.FlushbarRoute _flushbarRoute; + + /// Show the flushbar. Kicks in [FlushbarStatus.IS_APPEARING] state followed by [FlushbarStatus.SHOWING] + Future show(BuildContext context) async { + _flushbarRoute = route.showFlushbar( + context: context, + flushbar: this, + ); + + return await Navigator.of(context, rootNavigator: false) + .push(_flushbarRoute); + } + + /// Dismisses the flushbar causing is to return a future containing [result]. + /// When this future finishes, it is guaranteed that Flushbar was dismissed. + Future dismiss([T result]) async { + // If route was never initialized, do nothing + if (_flushbarRoute == null) { + return null; + } + + if (_flushbarRoute.isCurrent) { + _flushbarRoute.navigator.pop(result); + return _flushbarRoute.completed; + } else if (_flushbarRoute.isActive) { + // removeRoute is called every time you dismiss a Flushbar that is not the top route. + // It will not animate back and listeners will not detect FlushbarStatus.IS_HIDING or FlushbarStatus.DISMISSED + // To avoid this, always make sure that Flushbar is the top route when it is being dismissed + _flushbarRoute.navigator.removeRoute(_flushbarRoute); + } + + return null; + } + + /// Checks if the flushbar is visible + bool isShowing() { + return _flushbarRoute?.currentStatus == FlushbarStatus.SHOWING; + } + + /// Checks if the flushbar is dismissed + bool isDismissed() { + return _flushbarRoute?.currentStatus == FlushbarStatus.DISMISSED; + } + + @override + State createState() { + return _FlushbarState(); + } +} + +class _FlushbarState extends State + with TickerProviderStateMixin { + final Duration _pulseAnimationDuration = const Duration(seconds: 1); + final Widget _emptyWidget = const SizedBox(); + final double _initialOpacity = 1.0; + final double _finalOpacity = 0.4; + + GlobalKey _backgroundBoxKey; + FlushbarStatus currentStatus; + AnimationController _fadeController; + Animation _fadeAnimation; + bool _isTitlePresent; + double _messageTopMargin; + FocusScopeNode _focusNode; + FocusAttachment _focusAttachment; + Completer _boxHeightCompleter; + Function _progressListener; + CurvedAnimation _progressAnimation; + + @override + void initState() { + super.initState(); + + _backgroundBoxKey = GlobalKey(); + _boxHeightCompleter = Completer(); + + assert( + ((widget.userInputForm != null || + ((widget.message != null && widget.message.isNotEmpty) || + widget.messageText != null))), + "A message is mandatory if you are not using userInputForm. Set either a message or messageText"); + + _isTitlePresent = (widget.title != null || widget.titleText != null); + _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top; + + _configureLeftBarFuture(); + _configureProgressIndicatorAnimation(); + + if (widget.icon != null && widget.shouldIconPulse) { + _configurePulseAnimation(); + _fadeController?.forward(); + } + + _focusNode = FocusScopeNode(); + _focusAttachment = _focusNode.attach(context); + } + + @override + void dispose() { + _fadeController?.dispose(); + + widget.progressIndicatorController?.removeListener(_progressListener); + widget.progressIndicatorController?.dispose(); + + _focusAttachment.detach(); + _focusNode.dispose(); + super.dispose(); + } + + void _configureLeftBarFuture() { + SchedulerBinding.instance.addPostFrameCallback( + (_) { + final keyContext = _backgroundBoxKey.currentContext; + + if (keyContext != null) { + final RenderBox box = keyContext.findRenderObject(); + _boxHeightCompleter.complete(box.size); + } + }, + ); + } + + void _configureProgressIndicatorAnimation() { + if (widget.showProgressIndicator && + widget.progressIndicatorController != null) { + _progressAnimation = CurvedAnimation( + curve: Curves.linear, parent: widget.progressIndicatorController); + } + } + + void _configurePulseAnimation() { + _fadeController = + AnimationController(vsync: this, duration: _pulseAnimationDuration); + _fadeAnimation = Tween(begin: _initialOpacity, end: _finalOpacity).animate( + CurvedAnimation( + parent: _fadeController, + curve: Curves.linear, + ), + ); + + _fadeController.addStatusListener((status) { + if (status == AnimationStatus.completed) { + _fadeController.reverse(); + } + if (status == AnimationStatus.dismissed) { + _fadeController.forward(); + } + }); + + _fadeController.forward(); + } + + @override + Widget build(BuildContext context) { + return Align( + heightFactor: 1.0, + child: Material( + color: widget.flushbarStyle == FlushbarStyle.FLOATING + ? Colors.transparent + : widget.backgroundColor, + child: SafeArea( + minimum: widget.flushbarPosition == FlushbarPosition.BOTTOM + ? EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom) + : EdgeInsets.only(top: MediaQuery.of(context).viewInsets.top), + bottom: widget.flushbarPosition == FlushbarPosition.BOTTOM, + top: widget.flushbarPosition == FlushbarPosition.TOP, + left: false, + right: false, + child: _getFlushbar(), + ), + ), + ); + } + + Widget _getFlushbar() { + Widget flushbar; + + if (widget.userInputForm != null) { + flushbar = _generateInputFlushbar(); + } else { + flushbar = _generateFlushbar(); + } + + return Stack( + children: [ + FutureBuilder( + future: _boxHeightCompleter.future, + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return ClipRRect( + borderRadius: BorderRadius.circular(widget.borderRadius), + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: widget.barBlur, sigmaY: widget.barBlur), + child: Container( + height: snapshot.data.height, + width: snapshot.data.width, + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(widget.borderRadius), + ), + ), + ), + ); + } else { + return _emptyWidget; + } + }, + ), + flushbar, + ], + ); + } + + Widget _generateInputFlushbar() { + return Container( + key: _backgroundBoxKey, + constraints: widget.maxWidth != null + ? BoxConstraints(maxWidth: widget.maxWidth) + : null, + decoration: BoxDecoration( + color: widget.backgroundColor, + gradient: widget.backgroundGradient, + boxShadow: widget.boxShadows, + borderRadius: BorderRadius.circular(widget.borderRadius), + border: widget.borderColor != null + ? Border.all(color: widget.borderColor, width: widget.borderWidth) + : null, + ), + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, right: 8.0, bottom: 8.0, top: 16.0), + child: FocusScope( + child: widget.userInputForm, + node: _focusNode, + autofocus: true, + ), + ), + ); + } + + Widget _generateFlushbar() { + return Container( + key: _backgroundBoxKey, + constraints: widget.maxWidth != null + ? BoxConstraints(maxWidth: widget.maxWidth) + : null, + decoration: BoxDecoration( + color: widget.backgroundColor, + gradient: widget.backgroundGradient, + boxShadow: widget.boxShadows, + borderRadius: BorderRadius.circular(widget.borderRadius), + border: widget.borderColor != null + ? Border.all(color: widget.borderColor, width: widget.borderWidth) + : null, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildProgressIndicator(), + Row( + mainAxisSize: MainAxisSize.max, + children: _getAppropriateRowLayout(), + ), + ], + ), + ); + } + + Widget _buildProgressIndicator() { + if (widget.showProgressIndicator && _progressAnimation != null) { + return AnimatedBuilder( + animation: _progressAnimation, + builder: (_, __) { + return LinearProgressIndicator( + value: _progressAnimation.value, + backgroundColor: widget.progressIndicatorBackgroundColor, + valueColor: widget.progressIndicatorValueColor, + ); + }); + } + + if (widget.showProgressIndicator) { + return LinearProgressIndicator( + backgroundColor: widget.progressIndicatorBackgroundColor, + valueColor: widget.progressIndicatorValueColor, + ); + } + + return _emptyWidget; + } + + List _getAppropriateRowLayout() { + double buttonRightPadding; + double iconPadding = 0; + if (widget.padding.right - 12 < 0) { + buttonRightPadding = 4; + } else { + buttonRightPadding = widget.padding.right - 12; + } + + if (widget.padding.left > 16.0) { + iconPadding = widget.padding.left; + } + + if (widget.icon == null && widget.mainButton == null) { + return [ + _buildLeftBarIndicator(), + Expanded( + flex: 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + (_isTitlePresent) + ? Padding( + padding: EdgeInsets.only( + top: widget.padding.top, + left: widget.padding.left, + right: widget.padding.right, + ), + child: _getTitleText(), + ) + : _emptyWidget, + Padding( + padding: EdgeInsets.only( + top: _messageTopMargin, + left: widget.padding.left, + right: widget.padding.right, + bottom: widget.padding.bottom, + ), + child: widget.messageText ?? _getDefaultNotificationText(), + ), + ], + ), + ), + ]; + } else if (widget.icon != null && widget.mainButton == null) { + return [ + _buildLeftBarIndicator(), + ConstrainedBox( + constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding), + child: _getIcon(), + ), + Expanded( + flex: 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + (_isTitlePresent) + ? Padding( + padding: EdgeInsets.only( + top: widget.padding.top, + left: 4.0, + right: widget.padding.left, + ), + child: _getTitleText(), + ) + : _emptyWidget, + Padding( + padding: EdgeInsets.only( + top: _messageTopMargin, + left: 4.0, + right: widget.padding.right, + bottom: widget.padding.bottom, + ), + child: widget.messageText ?? _getDefaultNotificationText(), + ), + ], + ), + ), + ]; + } else if (widget.icon == null && widget.mainButton != null) { + return [ + _buildLeftBarIndicator(), + Expanded( + flex: 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + (_isTitlePresent) + ? Padding( + padding: EdgeInsets.only( + top: widget.padding.top, + left: widget.padding.left, + right: widget.padding.right, + ), + child: _getTitleText(), + ) + : _emptyWidget, + Padding( + padding: EdgeInsets.only( + top: _messageTopMargin, + left: widget.padding.left, + right: 8.0, + bottom: widget.padding.bottom, + ), + child: widget.messageText ?? _getDefaultNotificationText(), + ), + ], + ), + ), + Padding( + padding: EdgeInsets.only(right: buttonRightPadding), + child: _getMainActionButton(), + ), + ]; + } else { + return [ + _buildLeftBarIndicator(), + ConstrainedBox( + constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding), + child: _getIcon(), + ), + Expanded( + flex: 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + (_isTitlePresent) + ? Padding( + padding: EdgeInsets.only( + top: widget.padding.top, + left: 4.0, + right: 8.0, + ), + child: _getTitleText(), + ) + : _emptyWidget, + Padding( + padding: EdgeInsets.only( + top: _messageTopMargin, + left: 4.0, + right: 8.0, + bottom: widget.padding.bottom, + ), + child: widget.messageText ?? _getDefaultNotificationText(), + ), + ], + ), + ), + Padding( + padding: EdgeInsets.only(right: buttonRightPadding), + child: _getMainActionButton(), + ) ?? + _emptyWidget, + ]; + } + } + + Widget _buildLeftBarIndicator() { + if (widget.leftBarIndicatorColor != null) { + return FutureBuilder( + future: _boxHeightCompleter.future, + builder: (BuildContext buildContext, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Container( + color: widget.leftBarIndicatorColor, + width: 5.0, + height: snapshot.data.height, + ); + } else { + return _emptyWidget; + } + }, + ); + } else { + return _emptyWidget; + } + } + + Widget _getIcon() { + if (widget.icon != null && widget.icon is Icon && widget.shouldIconPulse) { + return FadeTransition( + opacity: _fadeAnimation, + child: widget.icon, + ); + } else if (widget.icon != null) { + return widget.icon; + } else { + return _emptyWidget; + } + } + + Widget _getTitleText() { + return widget.titleText != null + ? widget.titleText + : Text( + widget.title ?? "", + style: TextStyle( + fontSize: 16.0, + color: Colors.white, + fontWeight: FontWeight.bold), + ); + } + + Text _getDefaultNotificationText() { + return Text( + widget.message ?? "", + style: TextStyle(fontSize: 14.0, color: Colors.white), + ); + } + + Widget _getMainActionButton() { + if (widget.mainButton != null) { + return widget.mainButton; + } else { + return null; + } + } +} + +/// Indicates if flushbar is going to start at the [TOP] or at the [BOTTOM] +enum FlushbarPosition { TOP, BOTTOM } + +/// Indicates if flushbar will be attached to the edge of the screen or not +enum FlushbarStyle { FLOATING, GROUNDED } + +/// Indicates the direction in which it is possible to dismiss +/// If vertical, dismiss up will be allowed if [FlushbarPosition.TOP] +/// If vertical, dismiss down will be allowed if [FlushbarPosition.BOTTOM] +enum FlushbarDismissDirection { HORIZONTAL, VERTICAL } + +/// Indicates the animation status +/// [FlushbarStatus.SHOWING] Flushbar has stopped and the user can see it +/// [FlushbarStatus.DISMISSED] Flushbar has finished its mission and returned any pending values +/// [FlushbarStatus.IS_APPEARING] Flushbar is moving towards [FlushbarStatus.SHOWING] +/// [FlushbarStatus.IS_HIDING] Flushbar is moving towards [] [FlushbarStatus.DISMISSED] +enum FlushbarStatus { SHOWING, DISMISSED, IS_APPEARING, IS_HIDING } diff --git a/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar_helper.dart b/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar_helper.dart new file mode 100644 index 00000000..4218eae7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar_helper.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; + +import 'flushbar.dart'; + +class FlushbarHelper { + /// Get a success notification flushbar. + static Flushbar createSuccess( + {@required String message, + String title, + Duration duration = const Duration(seconds: 3)}) { + return Flushbar( + title: title, + message: message, + icon: Icon( + Icons.check_circle, + color: Colors.green[300], + ), + leftBarIndicatorColor: Colors.green[300], + duration: duration, + ); + } + + /// Get an information notification flushbar + static Flushbar createInformation( + {@required String message, + String title, + Duration duration = const Duration(seconds: 3)}) { + return Flushbar( + title: title, + message: message, + icon: Icon( + Icons.info_outline, + size: 28.0, + color: Colors.blue[300], + ), + leftBarIndicatorColor: Colors.blue[300], + duration: duration, + ); + } + + /// Get a error notification flushbar + static Flushbar createError( + {@required String message, + String title, + Duration duration = const Duration(seconds: 3)}) { + return Flushbar( + title: title, + message: message, + icon: Icon( + Icons.warning, + size: 28.0, + color: Colors.red[300], + ), + leftBarIndicatorColor: Colors.red[300], + duration: duration, + ); + } + + /// Get a flushbar that can receive a user action through a button. + static Flushbar createAction( + {@required String message, + @required FlatButton button, + String title, + Duration duration = const Duration(seconds: 3)}) { + return Flushbar( + title: title, + message: message, + duration: duration, + mainButton: button, + ); + } + + // Get a flushbar that shows the progress of a async computation. + static Flushbar createLoading( + {@required String message, + @required LinearProgressIndicator linearProgressIndicator, + String title, + Duration duration = const Duration(seconds: 3), + AnimationController progressIndicatorController, + Color progressIndicatorBackgroundColor}) { + return Flushbar( + title: title, + message: message, + icon: Icon( + Icons.cloud_upload, + color: Colors.blue[300], + ), + duration: duration, + showProgressIndicator: true, + progressIndicatorController: progressIndicatorController, + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, + ); + } + + /// Get a flushbar that shows an user input form. + static Flushbar createInputFlushbar({@required Form textForm}) { + return Flushbar( + duration: null, + userInputForm: textForm, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar_route.dart b/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar_route.dart new file mode 100644 index 00000000..90f20e97 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flushbar/flushbar_route.dart @@ -0,0 +1,438 @@ +import 'dart:async'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +import 'flushbar.dart'; + +class FlushbarRoute extends OverlayRoute { + final Flushbar flushbar; + final Builder _builder; + final Completer _transitionCompleter = Completer(); + final FlushbarStatusCallback _onStatusChanged; + + Animation _filterBlurAnimation; + Animation _filterColorAnimation; + Alignment _initialAlignment; + Alignment _endAlignment; + bool _wasDismissedBySwipe = false; + Timer _timer; + T _result; + FlushbarStatus currentStatus; + + FlushbarRoute({ + @required this.flushbar, + RouteSettings settings, + }) : _builder = Builder(builder: (BuildContext innerContext) { + return GestureDetector( + child: flushbar, + onTap: + flushbar.onTap != null ? () => flushbar.onTap(flushbar) : null, + ); + }), + _onStatusChanged = flushbar.onStatusChanged, + super(settings: settings) { + _configureAlignment(this.flushbar.flushbarPosition); + } + + void _configureAlignment(FlushbarPosition flushbarPosition) { + switch (flushbar.flushbarPosition) { + case FlushbarPosition.TOP: + { + _initialAlignment = Alignment(-1.0, -2.0); + _endAlignment = Alignment(-1.0, -1.0); + break; + } + case FlushbarPosition.BOTTOM: + { + _initialAlignment = Alignment(-1.0, 2.0); + _endAlignment = Alignment(-1.0, 1.0); + break; + } + } + } + + Future get completed => _transitionCompleter.future; + bool get opaque => false; + + @override + Iterable createOverlayEntries() { + final List overlays = []; + + if (flushbar.blockBackgroundInteraction) { + overlays.add( + OverlayEntry( + builder: (BuildContext context) { + return GestureDetector( + onTap: flushbar.isDismissible ? () => flushbar.dismiss() : null, + child: _createBackgroundOverlay(), + ); + }, + maintainState: false, + opaque: opaque), + ); + } + + overlays.add( + OverlayEntry( + builder: (BuildContext context) { + final Widget annotatedChild = Semantics( + child: AlignTransition( + alignment: _animation, + child: flushbar.isDismissible + ? _getDismissibleFlushbar(_builder) + : _getFlushbar(), + ), + focused: false, + container: true, + explicitChildNodes: true, + ); + return annotatedChild; + }, + maintainState: false, + opaque: opaque), + ); + + return overlays; + } + + Widget _createBackgroundOverlay() { + if (_filterBlurAnimation != null && _filterColorAnimation != null) { + return AnimatedBuilder( + animation: _filterBlurAnimation, + builder: (context, child) { + return BackdropFilter( + filter: ImageFilter.blur( + sigmaX: _filterBlurAnimation.value, + sigmaY: _filterBlurAnimation.value), + child: Container( + constraints: BoxConstraints.expand(), + color: _filterColorAnimation.value, + ), + ); + }, + ); + } + + if (_filterBlurAnimation != null) { + return AnimatedBuilder( + animation: _filterBlurAnimation, + builder: (context, child) { + return BackdropFilter( + filter: ImageFilter.blur( + sigmaX: _filterBlurAnimation.value, + sigmaY: _filterBlurAnimation.value), + child: Container( + constraints: BoxConstraints.expand(), + color: Colors.transparent, + ), + ); + }, + ); + } + + if (_filterColorAnimation != null) { + AnimatedBuilder( + animation: _filterColorAnimation, + builder: (context, child) { + return Container( + constraints: BoxConstraints.expand(), + color: _filterColorAnimation.value, + ); + }, + ); + } + + return Container( + constraints: BoxConstraints.expand(), + color: Colors.transparent, + ); + } + + /// This string is a workaround until Dismissible supports a returning item + String dismissibleKeyGen = ""; + + Widget _getDismissibleFlushbar(Widget child) { + return Dismissible( + direction: _getDismissDirection(), + resizeDuration: null, + confirmDismiss: (_) { + if (currentStatus == FlushbarStatus.IS_APPEARING || + currentStatus == FlushbarStatus.IS_HIDING) { + return Future.value(false); + } + return Future.value(true); + }, + key: Key(dismissibleKeyGen), + onDismissed: (_) { + dismissibleKeyGen += "1"; + _cancelTimer(); + _wasDismissedBySwipe = true; + + if (isCurrent) { + navigator.pop(); + } else { + navigator.removeRoute(this); + } + }, + child: _getFlushbar(), + ); + } + + DismissDirection _getDismissDirection() { + if (flushbar.dismissDirection == FlushbarDismissDirection.HORIZONTAL) { + return DismissDirection.horizontal; + } else { + if (flushbar.flushbarPosition == FlushbarPosition.TOP) { + return DismissDirection.up; + } else { + return DismissDirection.down; + } + } + } + + Widget _getFlushbar() { + return Container( + margin: flushbar.margin, + child: _builder, + ); + } + + @override + bool get finishedWhenPopped => + _controller.status == AnimationStatus.dismissed; + + /// The animation that drives the route's transition and the previous route's + /// forward transition. + Animation get animation => _animation; + Animation _animation; + + /// The animation controller that the route uses to drive the transitions. + /// + /// The animation itself is exposed by the [animation] property. + @protected + AnimationController get controller => _controller; + AnimationController _controller; + + /// Called to create the animation controller that will drive the transitions to + /// this route from the previous one, and back to the previous route from this + /// one. + AnimationController createAnimationController() { + assert(!_transitionCompleter.isCompleted, + 'Cannot reuse a $runtimeType after disposing it.'); + assert(flushbar.animationDuration != null && + flushbar.animationDuration >= Duration.zero); + return AnimationController( + duration: flushbar.animationDuration, + debugLabel: debugLabel, + vsync: navigator, + ); + } + + /// Called to create the animation that exposes the current progress of + /// the transition controlled by the animation controller created by + /// [createAnimationController()]. + Animation createAnimation() { + assert(!_transitionCompleter.isCompleted, + 'Cannot reuse a $runtimeType after disposing it.'); + assert(_controller != null); + return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate( + CurvedAnimation( + parent: _controller, + curve: flushbar.forwardAnimationCurve, + reverseCurve: flushbar.reverseAnimationCurve, + ), + ); + } + + Animation createBlurFilterAnimation() { + if (flushbar.routeBlur == null) return null; + + return Tween(begin: 0.0, end: flushbar.routeBlur).animate( + CurvedAnimation( + parent: _controller, + curve: Interval( + 0.0, + 0.35, + curve: Curves.easeInOutCirc, + ), + ), + ); + } + + Animation createColorFilterAnimation() { + if (flushbar.routeColor == null) return null; + + return ColorTween(begin: Colors.transparent, end: flushbar.routeColor) + .animate( + CurvedAnimation( + parent: _controller, + curve: Interval( + 0.0, + 0.35, + curve: Curves.easeInOutCirc, + ), + ), + ); + } + + //copy of `routes.dart` + void _handleStatusChanged(AnimationStatus status) { + switch (status) { + case AnimationStatus.completed: + currentStatus = FlushbarStatus.SHOWING; + _onStatusChanged(currentStatus); + if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = opaque; + + break; + case AnimationStatus.forward: + currentStatus = FlushbarStatus.IS_APPEARING; + _onStatusChanged(currentStatus); + break; + case AnimationStatus.reverse: + currentStatus = FlushbarStatus.IS_HIDING; + _onStatusChanged(currentStatus); + if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = false; + break; + case AnimationStatus.dismissed: + assert(!overlayEntries.first.opaque); + // We might still be the current route if a subclass is controlling the + // the transition and hits the dismissed status. For example, the iOS + // back gesture drives this animation to the dismissed status before + // popping the navigator. + currentStatus = FlushbarStatus.DISMISSED; + _onStatusChanged(currentStatus); + + if (!isCurrent) { + navigator.finalizeRoute(this); + assert(overlayEntries.isEmpty); + } + break; + } + changedInternalState(); + } + + @override + void install() { + assert(!_transitionCompleter.isCompleted, + 'Cannot install a $runtimeType after disposing it.'); + _controller = createAnimationController(); + assert(_controller != null, + '$runtimeType.createAnimationController() returned null.'); + _filterBlurAnimation = createBlurFilterAnimation(); + _filterColorAnimation = createColorFilterAnimation(); + _animation = createAnimation(); + assert(_animation != null, '$runtimeType.createAnimation() returned null.'); + super.install(); + } + + @override + TickerFuture didPush() { + assert(_controller != null, + '$runtimeType.didPush called before calling install() or after calling dispose().'); + assert(!_transitionCompleter.isCompleted, + 'Cannot reuse a $runtimeType after disposing it.'); + _animation.addStatusListener(_handleStatusChanged); + _configureTimer(); + super.didPush(); + return _controller.forward(); + } + + @override + void didReplace(Route oldRoute) { + assert(_controller != null, + '$runtimeType.didReplace called before calling install() or after calling dispose().'); + assert(!_transitionCompleter.isCompleted, + 'Cannot reuse a $runtimeType after disposing it.'); + if (oldRoute is FlushbarRoute) + _controller.value = oldRoute._controller.value; + _animation.addStatusListener(_handleStatusChanged); + super.didReplace(oldRoute); + } + + @override + bool didPop(T result) { + assert(_controller != null, + '$runtimeType.didPop called before calling install() or after calling dispose().'); + assert(!_transitionCompleter.isCompleted, + 'Cannot reuse a $runtimeType after disposing it.'); + + _result = result; + _cancelTimer(); + + if (_wasDismissedBySwipe) { + Timer(Duration(milliseconds: 200), () { + _controller.reset(); + }); + + _wasDismissedBySwipe = false; + } else { + _controller.reverse(); + } + + return super.didPop(result); + } + + void _configureTimer() { + if (flushbar.duration != null) { + if (_timer != null && _timer.isActive) { + _timer.cancel(); + } + _timer = Timer(flushbar.duration, () { + if (this.isCurrent) { + navigator.pop(); + } else if (this.isActive) { + navigator.removeRoute(this); + } + }); + } else { + if (_timer != null) { + _timer.cancel(); + } + } + } + + void _cancelTimer() { + if (_timer != null && _timer.isActive) { + _timer.cancel(); + } + } + + /// Whether this route can perform a transition to the given route. + /// + /// Subclasses can override this method to restrict the set of routes they + /// need to coordinate transitions with. + bool canTransitionTo(FlushbarRoute nextRoute) => true; + + /// Whether this route can perform a transition from the given route. + /// + /// Subclasses can override this method to restrict the set of routes they + /// need to coordinate transitions with. + bool canTransitionFrom(FlushbarRoute previousRoute) => true; + + @override + void dispose() { + assert(!_transitionCompleter.isCompleted, + 'Cannot dispose a $runtimeType twice.'); + _controller?.dispose(); + _transitionCompleter.complete(_result); + super.dispose(); + } + + /// A short description of this route useful for debugging. + String get debugLabel => '$runtimeType'; + + @override + String toString() => '$runtimeType(animation: $_controller)'; +} + +FlushbarRoute showFlushbar( + {@required BuildContext context, @required Flushbar flushbar}) { + assert(flushbar != null); + + return FlushbarRoute( + flushbar: flushbar, + settings: RouteSettings(name: FLUSHBAR_ROUTE_NAME), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flushbar/main.dart b/FlutterHelper/flutter_helper/lib/samples/flushbar/main.dart new file mode 100644 index 00000000..9f78ec0e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flushbar/main.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +import 'flushbar.dart'; + +class YourAwesomeApp extends StatelessWidget with HighMixin { + @override + Widget build(BuildContext context) { + return Scaffold( + body: ListView( + children: [ + Image.asset('readme_resources/flushbar_logo.png'), + Image.asset('readme_resources/floating_style.png'), + Image.asset('readme_resources/grounded_style.png'), + Image.asset('readme_resources/flushbar_animated.gif'), + Image.asset('readme_resources/input_bar.png'), + Image.asset('readme_resources/complete_bar.png'), + Image.asset('readme_resources/gradient_bar.png'), + Image.asset('readme_resources/position_bar.png'), + Image.asset('readme_resources/left_bar_indicator.png'), + Image.asset('readme_resources/padding_and_radius.png'), + Image.asset('readme_resources/icon_and_button_bar.png'), + Image.asset('readme_resources/background_color_bar.png'), + Image.asset('readme_resources/text_bar.png'), + Image.asset('readme_resources/basic_bar.png'), + ], + ), + ); + } + + // Flushbar flush; + // @override + // Widget build(BuildContext context) { + // return Container( + // child: Center( + // child: MaterialButton( + // onPressed: () { + // flush = Flushbar( + // title: "Hey Ninja", + // message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", + // icon: Icon( + // Icons.info_outline, + // color: Colors.blue,), + // mainButton: FlatButton( + // onPressed: () { + // flush.dismiss(true); // result = true + // }, + // child: Text( + // "ADD", + // style: TextStyle(color: Colors.amber), + // ), + // ),) // is the type of the result passed to dismiss() and collected by show().then((result){}) + // ..show(context).then((result) { + // setState(() { // setState() is optional here + // _wasButtonClicked = result; + // }); + // }); + // }, + // ), + // ), + // ); + // } + + // @override + // Widget build(BuildContext context) { + // return MaterialApp( + // title: 'YourAwesomeApp', + // home: Scaffold( + // appBar: AppBar(title: Text('flushbar'),), + // body: Container( + // child: Center( + // child: MaterialButton( + // onPressed: () { + // Flushbar( + // title: "Hey Ninja", + // message: + // "Lorem Ipsum is simply dummy text of the printing and typesetting industry", + // duration: Duration(seconds: 3), + // )..show(context); + // }, + // ), + // ), + // ), + // ), + // ); + // } + + @override + High getHigh() => High(toStringShort(), ''); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/sliver_calendar.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/sliver_calendar.dart new file mode 100644 index 00000000..82655ecf --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/sliver_calendar.dart @@ -0,0 +1,2 @@ +export 'src/calendar.dart'; +export 'src/calendarevent.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendar.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendar.dart new file mode 100644 index 00000000..4ee3ac21 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendar.dart @@ -0,0 +1,329 @@ +import 'dart:async'; + +import 'package:clock/clock.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:timezone/timezone.dart'; + +import 'calendarevent.dart'; +import 'calendarheader.dart'; +import 'sliverlistcalendar.dart'; +import 'sliverscrollviewcalendar.dart'; + +export 'calendarevent.dart'; + +/// +/// Create a calendar event list between the two bounding dates. +/// +typedef List CalendarEventBuilder(DateTime start, DateTime end); + +/// +/// The widget for the specific calendar event, this is what to render +/// when showing the calendar event. +/// +typedef Widget CalendarWidgetBuilder(BuildContext context, CalendarEvent index); + +/// +/// The widget to show the calendar with a header that displays the +/// current month, drop down and then the events in a sliverlist. +/// +class CalendarWidget extends StatefulWidget { + /// + /// Creates a calendar widget in place. The [initialDate] is the date + /// which will be used to show the first calendar in the list. The + /// [source] is used to get the events from. + /// + /// The [header] object can be used to completely customise the header used + /// in the calendar. It defaults to making one based on the [CalendarHeader] + /// class. + /// + /// The [location] will set itself to the local location if it not set. The + /// calendarKey is used to co-ordinate all the pieces of the calendar across + /// the widget. THis will default to a useful value if not set, this is only + /// really needed if you want to display more than one. + /// + /// The [initialScrollOffset] is where to put the scroll bar to start with + /// if this is not set then the offset is so the microseconds since the epoc + /// based on the initial date. + /// + CalendarWidget({ + @required this.initialDate, + @required this.buildItem, + @required this.getEvents, + TZDateTime beginningRangeDate, + TZDateTime endingRangeDate, + this.bannerHeader, + this.monthHeader, + Key key, + this.view = CalendarViewType.Schedule, + this.weekBeginsWithDay = 0, + Location location, + String calendarKey, + double initialScrollOffset, + this.headerColor, + this.headerMonthStyle, + this.headerExpandIconColor, + this.tapToCloseHeader = true, + this.header, + }) : beginningRangeDate = + beginningRangeDate ?? TZDateTime(location ?? local, 2010), + endingRangeDate = endingRangeDate ?? + TZDateTime(location ?? local, clock.now().year + 2), + assert(beginningRangeDate == null || + (beginningRangeDate.compareTo(initialDate) <= 0) && + (endingRangeDate == null || + initialDate.compareTo(endingRangeDate) <= 0)), + location = location ?? local, + initialScrollOffset = initialScrollOffset ?? + initialDate.microsecondsSinceEpoch.toDouble(), + super(key: key); + + /// The initial date to show the calendar for. + final TZDateTime initialDate; + + /// + /// The edge of the range to display in the calendar, cannot scroll + /// back past this point + /// + final TZDateTime beginningRangeDate; + + /// + /// The end of the range to display yin the calendar, cannot scroll forward + /// past this point. + /// + final TZDateTime endingRangeDate; + + /// The type of the calendar to displau. + final CalendarViewType view; + + /// which day to begin the week for when displaying a week + final int + weekBeginsWithDay; // Sunday = 0, Monday = 1, Tuesday = 2, ..., Saturday = 6 + /// the timezone locatrion to use fdor the days. + final Location location; + + /// Where to start the scroll at. + final double initialScrollOffset; + + /// Returns the events to use to display on the screen. + final CalendarEventBuilder getEvents; + + /// building the widget to display for each of the events in the calendar. + final CalendarWidgetBuilder buildItem; + + /// the header to use at the top of each momth. + final ImageProvider monthHeader; + + /// the header to use at the top of the banner. + final ImageProvider bannerHeader; + + /// The color of the header. + final Color headerColor; + + /// The style to use for displaying the header for the month. + final TextStyle headerMonthStyle; + + /// The color of the expand icon for the header. + final Color headerExpandIconColor; + + /// If you can close the header with a tap. + final bool tapToCloseHeader; + + /// The header to display. + final Widget header; + + @override + State createState() { + return CalendarWidgetState(); + } +} + +/// +/// The state for the calendar widget. +/// +class CalendarWidgetState extends State { + CalendarWidgetState() { + _headerBroadcastStream = _headerExpandController.stream.asBroadcastStream(); + _indexBroadcastStream = _updateController.stream.asBroadcastStream(); + } + + int _currentTopDisplayIndex; + Map> events = >{}; + StreamController _updateController = StreamController(); + StreamController _headerExpandController = StreamController(); + Stream _headerBroadcastStream; + Stream _indexBroadcastStream; + RenderSliverCenterList renderSliverList; + bool _headerExpanded = false; + SliverScrollViewCalendarElement element; + ScrollController controller; + + @override + void initState() { + _currentTopDisplayIndex = widget.initialDate.millisecondsSinceEpoch ~/ + Duration.millisecondsPerDay; + super.initState(); + } + + /// Sets the current top index and tells people about the change. + set currentTopDisplayIndex(int index) { + _currentTopDisplayIndex = index; + + _updateController.add(index); + } + + /// Update if the header is expanded and tell people about the change. + set headerExpanded(bool expanded) { + if (expanded != _headerExpanded) { + _headerExpanded = expanded; + _headerExpandController.add(expanded); + } + } + + /// If the header is currently expanded or not. + bool get headerExpanded => _headerExpanded; + + /// The index of the current display, this is the display index and not + /// the index into the events. + int get currentTopDisplayIndex => _currentTopDisplayIndex; + + /// + /// Broadcast stream to let the various elements know about the current + /// top of the display. + /// + Stream get indexChangeStream { + return _indexBroadcastStream; + } + + /// Broadcast stream that is updated with the current state of the header + /// when it changes. + Stream get headerExpandedChangeStream { + return _headerBroadcastStream; + } + + @override + void dispose() { + // stop it being disposed twice, althougn not sure why it is being disposed + // twice. + super.dispose(); + _updateController.close(); + _headerExpandController.close(); + } + + /// + /// Updates the events in the given time range by pulling from the + /// source and updating the indexes in the events mapping. + /// + void updateInternalEvents(TZDateTime startWindow, TZDateTime endWindow) { + List rawEvents = widget.getEvents(startWindow, endWindow); + rawEvents.sort( + (CalendarEvent e, CalendarEvent e2) => e.instant.compareTo(e2.instant)); + // Make sure we clean up the old indexes when we update. + events.clear(); + if (rawEvents.isNotEmpty) { + int curIndex = CalendarEvent.indexFromMilliseconds( + rawEvents[0].instant, widget.location); + int sliceIndex = 0; + // Get the offsets into the array. + for (int i = 1; i < rawEvents.length; i++) { + int index = CalendarEvent.indexFromMilliseconds( + rawEvents[i].instant, widget.location); + if (index != curIndex) { + if (sliceIndex != i) { + events[curIndex] = rawEvents.sublist(sliceIndex, i); + } else { + events[curIndex] = [rawEvents[sliceIndex]]; + } + curIndex = index; + sliceIndex = i; + } + } + if (sliceIndex != rawEvents.length) { + events[curIndex] = rawEvents.sublist(sliceIndex); + } + } + } + + //static Map _data = + //{}; + + /// + /// Creates the calendar state for the specific co-ordination key. + /// + /* + static SharedCalendarState createState(String coordinationKey, + CalendarSource source, TZDateTime currentTop, Location location) { + if (_data.containsKey(coordinationKey)) { + // Update the source into the new shared state and fix the elemet. + CalendarSource old = _data[coordinationKey].source; + _data[coordinationKey].source = source; + source.init(old.element); + source.didUpdateSource(old); + return _data[coordinationKey]; + } + return _data[coordinationKey]; + } + */ + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + widget.header ?? + CalendarHeader( + this, + widget.bannerHeader, + widget.location, + widget.headerColor, + widget.headerMonthStyle, + widget.headerExpandIconColor, + widget.weekBeginsWithDay, + null, + null, + widget.beginningRangeDate, + widget.endingRangeDate), + Expanded( + child: Padding( + padding: EdgeInsets.only(top: 5.0), + child: WrappedScrollViewCalendar( + state: this, + initialDate: widget.initialDate, + beginningRangeDate: widget.beginningRangeDate, + endingRangeDate: widget.endingRangeDate, + initialScrollOffset: widget.initialScrollOffset, + view: widget.view, + location: widget.location, + monthHeader: widget.monthHeader, + tapToCloseHeader: widget.tapToCloseHeader, + ), + ), + ), + ], + ); + } + + /// + /// Scrolls the calendar to the specific datetime set here. Note + /// we only use the month/day/year for this. The milliseconds is + /// *not* correct and not in local time. + /// + void scrollToDay(DateTime time) { + if (element != null) { + element.scrollToDate(time); + } + } + + /// + /// Update the events on the screen when things change. + /// This causes the system to re-ask for the events. + /// + void updateEvents() { + if (element != null) { + element.updateEvents(); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendardaymarker.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendardaymarker.dart new file mode 100644 index 00000000..4dbda594 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendardaymarker.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +/// A one device pixel thick horizontal line, with a circle at the start +/// designed to look like the time of day lines in calendar. +/// +class CalendarDayMarker extends StatelessWidget { + /// The height must be positive. + const CalendarDayMarker( + {Key key, + this.height = 16.0, + this.radius = 5.0, + this.indent = 0.0, + this.color}) + : assert(height >= 0.0), + super(key: key); + + /// The vertical extent. + final double height; + + /// The amount of empty space to the left of the divider. + final double indent; + + /// Radius of the dot at the start of the line. + final double radius; + + /// The color to use when painting the line. + /// + /// Defaults to the current theme's divider color, given by + /// [ThemeData.dividerColor]. + /// + /// ## Sample code + /// + /// ```dart + /// new Divider( + /// color: Colors.deepOrange, + /// ) + /// ``` + final Color color; + + /// Create a side for the border. + static BorderSide createBorderSide(BuildContext context, + {Color color, double width: 0.0}) { + return BorderSide( + color: color ?? Theme.of(context).dividerColor, + width: width, + ); + } + + @override + Widget build(BuildContext context) { + return CustomPaint( + painter: _CalendarDayMarkerPainter( + radius, Offset(indent + radius / 2, height / 2), color), + child: SizedBox( + height: height, + child: Center( + child: Container( + height: 0.0, + margin: EdgeInsetsDirectional.only(start: indent), + decoration: ShapeDecoration( + shape: Border( + bottom: BorderSide( + color: color ?? Theme.of(context).dividerColor, + width: 0.0, + ), + ), + ), + ), + ), + ), + ); + } +} + +class _CalendarDayMarkerPainter extends CustomPainter { + _CalendarDayMarkerPainter(this._radius, this._offset, this._color); + + final double _radius; + final Offset _offset; + final Color _color; + + @override + void paint(Canvas canvas, Size size) { + canvas.drawCircle(_offset, _radius, Paint()..color = _color); + } + + @override + bool shouldRepaint(_CalendarDayMarkerPainter other) => + other._radius != _radius || + other._offset != _offset || + other._color != _color; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendarevent.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendarevent.dart new file mode 100644 index 00000000..f5bddec6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendarevent.dart @@ -0,0 +1,56 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; +import 'package:timezone/timezone.dart'; + +/// One day duration to use in the rest of the system. +final Duration oneDay = Duration(days: 1); + +/// +/// The source for the calendar, this is where to get all the events from. +/// +abstract class CalendarEventElement { + void updateEvents(); + + void scrollToDate(TZDateTime time); +} + +/// The type of the calendar view to show. Right now only schedule is +/// implemented. +enum CalendarViewType { Schedule, Week, Month } + +/// +/// The calendar event to display in the calendar. This contains details +/// about how to render it and display it. +/// +class CalendarEvent { + CalendarEvent({ + @required this.index, + @required this.instant, + @required TZDateTime instantEnd, + }) : _instantEnd = instantEnd; + + /// The instant to display the event at. + TZDateTime instant; + TZDateTime _instantEnd; + + /// The index to use for the event. + int index; + + /// when the event ends. + TZDateTime get instantEnd => _instantEnd; + + static const int _yearOffset = 12 * 31; + static const int _monthOffset = 31; + + /// get the index from the milliseconds that are passed in. + static int indexFromMilliseconds(DateTime time, Location loc) { + return time.year * _yearOffset + + (time.month - 1) * _monthOffset + + time.day - + 1; + } + + @override + String toString() { + return 'CalendarEvent{instant: $instant, index: $index}'; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendarheader.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendarheader.dart new file mode 100644 index 00000000..5c61c75b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/calendarheader.dart @@ -0,0 +1,517 @@ +import 'dart:async'; + +import 'package:clock/clock.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:timezone/timezone.dart'; + +import 'calendar.dart'; +import 'calendarevent.dart'; + +final Duration _kExpand = Duration(milliseconds: 200); + +/// +/// This function will be called to generate a day in the header. By +/// default it does this. Which is overlaid by the event indicators. +/// button = new Center( +/// child: new FlatButton( +/// color: day.isAtSameMomentAs(nowTime) +/// ? theme.accentColor +/// : day.isAtSameMomentAs(displayDate) +/// ? Colors.grey.shade200 +/// : Colors.white, +/// shape: new CircleBorder(), +/// child: new Text(day.day.toString()), +/// onPressed: () => sharedState.source.scrollToDay(day), +/// padding: EdgeInsets.zero, +/// ), +/// ); +/// +typedef HeaderDayIndicator = Widget Function( + ThemeData theme, DateTime day, DateTime nowTime); + +/// +/// Generates the small boxes on the calendar to indicate that there are events +/// on this specific day. It creates a stack and then puts in the main day +/// button inside the stack with the event indicators overlaid on top of it. +/// The calendar events are the events on this day. It can be an empty array. +/// +typedef EventIndicator = Widget Function( + Widget button, List events); + +/// +/// Displays the header for the calendar. This handles the title with the +/// month/year and a drop down item as well as opening to show the whole month. +/// +class CalendarHeader extends StatefulWidget { + /// + /// Creates the calendar header. [calendarKey] is the key to find the shared + /// state from. [location] to use for the calendar. + /// + /// See [EventIndicator] and [HeaderDayIndicator] for details on how the + /// day and event indicators can be customized. + /// + CalendarHeader( + this.state, + this.bannerHeader, + Location location, + this.color, + this.headerStyle, + this.expandIconColor, + this.weekBeginsWithDay, + this.dayIndicator, + this.eventIndicator, + this.beginningRangeDate, + this.endingRangeDate) + : _location = location; + + final Location _location; + final CalendarWidgetState state; + final ImageProvider bannerHeader; + final Color color; + final TextStyle headerStyle; + final Color expandIconColor; + final int weekBeginsWithDay; + final EventIndicator eventIndicator; + final HeaderDayIndicator dayIndicator; + final TZDateTime beginningRangeDate; + final TZDateTime endingRangeDate; + + @override + State createState() { + return _CalendarHeaderState(); + } +} + +/// +/// The calendar state associated with the header. +/// +class _CalendarHeaderState extends State + with SingleTickerProviderStateMixin { + _CalendarHeaderState() { + _monthIndex = monthIndexFromTime(clock.now()); + _easeInAnimation = + CurvedAnimation(parent: _controller, curve: Curves.easeIn); + _iconTurns = Tween(begin: 0.0, end: 0.5).animate(_easeInAnimation); + } + + double get maxExtent => 55.0; + + StreamSubscription _headerExpandedSubscription; + StreamSubscription _indexChangeSubscription; + //SharedCalendarState sharedState; + AnimationController _controller; + CurvedAnimation _easeInAnimation; + Animation _iconTurns; + bool myExpandedState = false; + int _monthIndex; + int _beginningMonthIndex; + int _endingMonthIndex; + + int monthIndexFromTime(DateTime time) { + return (time.year - 1970) * 12 + (time.month - 1); + } + + DateTime monthToShow(int index) { + return DateTime(index ~/ 12 + 1970, index % 12 + 1, 1); + } + + @override + void initState() { + super.initState(); + _controller = AnimationController(duration: _kExpand, vsync: this); + _beginningMonthIndex = monthIndexFromTime(widget.beginningRangeDate); + _endingMonthIndex = monthIndexFromTime(widget.endingRangeDate); + _indexChangeSubscription = + widget.state.indexChangeStream.listen((int newTop) { + setState(() { + int ms = (widget.state.currentTopDisplayIndex + 1) * + Duration.millisecondsPerDay; + DateTime currentTopTemp = DateTime.fromMillisecondsSinceEpoch(ms); + + _monthIndex = monthIndexFromTime(currentTopTemp); + }); + }); + _headerExpandedSubscription = + widget.state.headerExpandedChangeStream.listen((bool change) { + if (myExpandedState != change) { + setState(() { + myExpandedState = change; + _doAnimation(); + }); + } + }); + } + + void _doAnimation() { + if (myExpandedState) { + _controller.forward(); + } else { + _controller.reverse().then((void value) { + setState(() { + // Rebuild without widget.children. + }); + }); + } + } + + @override + void dispose() { + super.dispose(); + _controller.dispose(); + _headerExpandedSubscription.cancel(); + _indexChangeSubscription.cancel(); + } + + void _handleOpen() { + setState(() { + // Jump the page controller to the right spot. + myExpandedState = !widget.state.headerExpanded; + widget.state.headerExpanded = myExpandedState; + _doAnimation(); + PageStorage.of(context) + ?.writeState(context, widget.state..headerExpanded); + }); + } + + Widget _buildChildren(BuildContext context, Widget child) { + DismissDirection direction = DismissDirection.horizontal; + if (_beginningMonthIndex == _monthIndex) { + direction = DismissDirection.endToStart; + } else if (_endingMonthIndex == _monthIndex) { + direction = DismissDirection.startToEnd; + } + + return Container( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildCurrentHeader(context), + ClipRect( + child: Align( + heightFactor: _easeInAnimation.value, + child: Container( + constraints: BoxConstraints(minHeight: 230.0, maxHeight: 230.0), + child: Dismissible( + key: ValueKey(_monthIndex), + resizeDuration: null, + dismissThresholds: const { + DismissDirection.horizontal: 0.2 + }, + direction: direction, + onDismissed: (DismissDirection direction) { + setState(() { + _monthIndex += + direction == DismissDirection.endToStart ? 1 : -1; + // Update the current scroll pos too. + widget.state.scrollToDay(monthToShow(_monthIndex)); + }); + }, + child: _CalendarMonthDisplay( + widget.state, + widget._location, + monthToShow(_monthIndex), + widget.weekBeginsWithDay, + widget.dayIndicator, + widget.eventIndicator, + ), + ), + ), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Material( + elevation: 4.0, + color: widget.color ?? Colors.white, + child: AnimatedBuilder( + animation: _controller, + builder: _buildChildren, + child: _buildCurrentHeader(context), + ), + ); + } + + Widget _buildCurrentHeader(BuildContext context) { + int ms = + (widget.state.currentTopDisplayIndex + 1) * Duration.millisecondsPerDay; + DateTime currentTopTemp = DateTime.fromMillisecondsSinceEpoch(ms); + DateTime currentTop = + DateTime(currentTopTemp.year, currentTopTemp.month, currentTopTemp.day); + + return Container( + padding: EdgeInsets.only(top: 10.0, left: 5.0, bottom: 10.0), + decoration: BoxDecoration( + color: widget.color ?? Colors.white, + image: widget.bannerHeader != null + ? DecorationImage( + image: widget.bannerHeader, + fit: BoxFit.fitHeight, + alignment: Alignment(1.0, 1.0), + ) + : null, + ), + child: GestureDetector( + onTap: _handleOpen, + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Text( + (myExpandedState + ? MaterialLocalizations.of(context) + .formatMonthYear(monthToShow(_monthIndex)) + : MaterialLocalizations.of(context) + .formatMonthYear(currentTop)) + + ' ', + style: widget.headerStyle ?? + Theme.of(context) + .textTheme + .headline6 + .copyWith(fontSize: 25.0), + ), + RotationTransition( + turns: _iconTurns, + child: Icon( + Icons.expand_more, + color: widget.expandIconColor ?? Colors.black, + size: 25.0, + ), + ), + ], + ), + ), + ); + } +} + +/// +/// Shows a small dot for the event to show the calendar day has a specific +/// event at it. +/// +class _CalendarEventIndicator extends CustomPainter { + _CalendarEventIndicator(this._radius, this._event); + + final double _radius; + final CalendarEvent _event; + + @override + void paint(Canvas canvas, Size size) { + canvas.drawCircle( + Offset(_radius, _radius), _radius, Paint()..color = Colors.black); + } + + @override + bool shouldRepaint(_CalendarEventIndicator other) => + other._radius != _radius || other._event != _event; +} + +/// +/// The animated container to show for the month with all the days and the +/// day headers. +/// +class _CalendarMonthDisplay extends StatelessWidget { + _CalendarMonthDisplay(this.sharedState, this.location, this.displayDate, + this.weekBeginsWithDay, this.dayIndicator, this.eventIndicator); + + final CalendarWidgetState sharedState; + final Location location; + final DateTime displayDate; + final int weekBeginsWithDay; + final HeaderDayIndicator dayIndicator; + final EventIndicator eventIndicator; + + static final Duration week = Duration(days: 7); + + Widget _eventIndicator(Widget button, int eventIndex) { + if (sharedState.events.containsKey(eventIndex)) { + if (eventIndicator != null) { + return eventIndicator(button, sharedState.events[eventIndex]); + } + List eventIndicators = []; + for (CalendarEvent event in sharedState.events[eventIndex]) { + eventIndicators.add( + SizedBox( + height: 4.0, + width: 4.0, + child: CustomPaint( + painter: _CalendarEventIndicator(2.0, event), + ), + ), + ); + eventIndicators.add( + SizedBox( + width: 2.0, + ), + ); + } + return SizedBox( + width: 40.0, + height: 40.0, + child: Stack( + children: [ + button, + Container( + alignment: Alignment(1.0, 1.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: eventIndicators, + ), + ), + ], + ), + ); + } else { + if (eventIndicator != null) { + return eventIndicator(button, []); + } + return SizedBox( + width: 40.0, + height: 40.0, + child: button, + ); + } + } + + Widget _buildButton(ThemeData theme, DateTime day, DateTime nowTime) { + Widget button; + // Only show days in the current month. + if (day.month != displayDate.month) { + button = SizedBox(width: 1.0); + } else { + if (dayIndicator != null) { + button = dayIndicator(theme, day, nowTime); + } else { + button = Center( + child: TextButton( + style: TextButton.styleFrom( + primary: day.isAtSameMomentAs(nowTime) + ? theme.accentColor + : day.isAtSameMomentAs(displayDate) + ? Colors.grey.shade200 + : Colors.white, + shape: CircleBorder(), + padding: EdgeInsets.zero, + ), + child: Text(day.day.toString()), + onPressed: () => sharedState.scrollToDay(day), + ), + ); + } + } + int eventIndex = CalendarEvent.indexFromMilliseconds(day, location); + return _eventIndicator(button, eventIndex); + } + + @override + Widget build(BuildContext context) { + DateTime nowTmp = clock.now(); + DateTime nowTime = DateTime(nowTmp.year, nowTmp.month, nowTmp.day); + DateTime topFirst = displayDate; + topFirst = + topFirst.subtract(Duration(days: topFirst.weekday - weekBeginsWithDay)); + DateTime topSecond = topFirst.add(week); + if (topSecond.day == 1) { + // Opps, out by a week. + topFirst = topSecond; + topSecond = topFirst.add(week); + } + DateTime topThird = topSecond.add(week); + DateTime topFourth = topThird.add(week); + DateTime topFifth = topFourth.add(week); + List dayHeaders = []; + List firstDays = []; + List secondDays = []; + List thirdDays = []; + List fourthDays = []; + List fifthDays = []; + ThemeData theme = Theme.of(context); + + for (int i = 0; i < 7; i++) { + dayHeaders.add( + SizedBox( + width: 40.0, + height: 20.0, + child: Center( + child: Text( + MaterialLocalizations.of(context) + .narrowWeekdays[topFirst.weekday % 7], + ), + ), + ), + ); + + // First row. + firstDays.add(_buildButton(theme, topFirst, nowTime)); + + // Second row. + secondDays.add(_buildButton(theme, topSecond, nowTime)); + + // Third row. + thirdDays.add(_buildButton(theme, topThird, nowTime)); + + // Fourth row. + fourthDays.add(_buildButton(theme, topFourth, nowTime)); + + // Fifth row. + fifthDays.add(_buildButton(theme, topFifth, nowTime)); + + topFirst = topFirst.add(oneDay); + topSecond = topSecond.add(oneDay); + topThird = topThird.add(oneDay); + topFourth = topFourth.add(oneDay); + topFifth = topFifth.add(oneDay); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: dayHeaders, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: firstDays, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: secondDays, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: thirdDays, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: fourthDays, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: fifthDays, + ), + SizedBox(height: 10.0), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/sliverlistcalendar.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/sliverlistcalendar.dart new file mode 100644 index 00000000..5d62ebc4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/sliverlistcalendar.dart @@ -0,0 +1,453 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +import 'calendar.dart'; + +/// A sliver that places multiple box children in a linear array along the main +/// axis. +/// +/// Each child is forced to have the [SliverConstraints.crossAxisExtent] in the +/// cross axis but determines its own main axis extent. +/// +/// [RenderSliverList] determines its scroll offset by "dead reckoning" because +/// children outside the visible part of the sliver are not materialized, which +/// means [RenderSliverList] cannot learn their main axis extent. Instead, newly +/// materialized children are placed adjacent to existing children. If this dead +/// reckoning results in a logical inconsistency (e.g., attempting to place the +/// zeroth child at a scroll offset other than zero), the [RenderSliverList] +/// generates a [SliverGeometry.scrollOffsetCorrection] to restore consistency. +/// +/// If the children have a fixed extent in the main axis, consider using +/// [RenderSliverFixedExtentList] rather than [RenderSliverList] because +/// [RenderSliverFixedExtentList] does not need to perform layout on its +/// children to obtain their extent in the main axis and is therefore more +/// efficient. +/// +/// See also: +/// +/// * [RenderSliverFixedExtentList], which is more efficient for children with +/// the same extent in the main axis. +/// * [RenderSliverGrid], which places its children in arbitrary positions. +class RenderSliverCenterList extends RenderSliverMultiBoxAdaptor { + /// Creates a sliver that places multiple box children in a linear array along + /// the main axis. + /// + /// The [childManager] argument must not be null. + RenderSliverCenterList({ + @required RenderSliverBoxChildManager childManager, + @required this.state, + this.startIndex = 0, + }) : super(childManager: childManager); + + final int startIndex; + final CalendarWidgetState state; + int newTopScrollIndex; + + @override + void performLayout() { + childManager.didStartLayout(); + childManager.setDidUnderflow(false); + + final double scrollOffset = constraints.scrollOffset; + assert(scrollOffset >= 0.0); + final double remainingPaintExtent = constraints.remainingPaintExtent; + assert(remainingPaintExtent >= 0.0); + double targetEndScrollOffset = scrollOffset + remainingPaintExtent; + final BoxConstraints childConstraints = constraints.asBoxConstraints(); + int leadingGarbage = 0; + int trailingGarbage = 0; + bool reachedEnd = false; + bool forceScrollUpdate = false; + + debugPrint('new top $newTopScrollIndex'); + + // This algorithm in principle is straight-forward: find the first child + // that overlaps the given scrollOffset, creating more children at the top + // of the list if necessary, then walk down the list updating and laying out + // each child and adding more at the end if necessary until we have enough + // children to cover the entire viewport. + // + // It is complicated by one minor issue, which is that any time you update + // or create a child, it's possible that the some of the children that + // haven't yet been laid out will be removed, leaving the list in an + // inconsistent state, and requiring that missing nodes be recreated. + // + // To keep this mess tractable, this algorithm starts from what is currently + // the first child, if any, and then walks up and/or down from there, so + // that the nodes that might get removed are always at the edges of what has + // already been laid out. + + //print('offset $scrollOffset'); + + // Make sure we have at least one child to start from. + if (firstChild == null) { + //print('Making first child'); + if (!addInitialChild(index: startIndex, layoutOffset: scrollOffset)) { + // There are no children. + geometry = SliverGeometry.zero; + childManager.didFinishLayout(); + return; + } + } + + // We have at least one child. + + // These variables track the range of children that we have laid out. Within + // this range, the children have consecutive indices. Outside this range, + // it's possible for a child to get removed without notice. + RenderBox leadingChildWithLayout, trailingChildWithLayout; + + // Find the last child that is at or before the scrollOffset. + RenderBox earliestUsefulChild = firstChild; + if (newTopScrollIndex != null) { + final SliverMultiBoxAdaptorParentData childParentData = + firstChild.parentData as SliverMultiBoxAdaptorParentData; + if (childParentData.index == newTopScrollIndex) { + newTopScrollIndex = null; + if (childParentData.layoutOffset != scrollOffset) { + geometry = SliverGeometry( + scrollOffsetCorrection: + childParentData.layoutOffset - scrollOffset, + ); + } + debugPrint('$geometry $scrollOffset ${childParentData.layoutOffset}'); + //sharedState.controller.jumpTo(childParentData.layoutOffset); + return; + } + } + + for (double earliestScrollOffset = childScrollOffset(earliestUsefulChild); + earliestScrollOffset > scrollOffset; + earliestScrollOffset = childScrollOffset(earliestUsefulChild)) { + // We have to add children before the earliestUsefulChild. + earliestUsefulChild = + insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true); + + if (earliestUsefulChild == null) { + final SliverMultiBoxAdaptorParentData childParentData = + firstChild.parentData as SliverMultiBoxAdaptorParentData; + childParentData.layoutOffset = 0.0; + //print("earlierusefulchild ${childParentData.layoutOffset}"); + + if (scrollOffset == 0.0) { + earliestUsefulChild = firstChild; + leadingChildWithLayout = earliestUsefulChild; + trailingChildWithLayout ??= earliestUsefulChild; + break; + } else { + // We ran out of children before reaching the scroll offset. + // We must inform our parent that this sliver cannot fulfill + // its contract and that we need a scroll offset correction. + geometry = SliverGeometry( + scrollOffsetCorrection: -scrollOffset, + ); + //print("Geometry correct ${childParentData.layoutOffset}"); + return; + } + } + + final double firstChildScrollOffset = + earliestScrollOffset - paintExtentOf(firstChild); + if (firstChildScrollOffset < 0.0) { + // The first child doesn't fit within the viewport (underflow) and + // there may be additional children above it. Find the real first child + // and then correct the scroll position so that there's room for all and + // so that the trailing edge of the original firstChild appears where it + // was before the scroll offset correction. + // TODO(hansmuller): do this work incrementally, instead of all at once, + // i.e. find a way to avoid visiting ALL of the children whose offset + // is < 0 before returning for the scroll correction. + double correction = 0.0; + while (earliestUsefulChild != null) { + assert(firstChild == earliestUsefulChild); + correction += paintExtentOf(firstChild); + earliestUsefulChild = insertAndLayoutLeadingChild(childConstraints, + parentUsesSize: true); + } + geometry = SliverGeometry( + scrollOffsetCorrection: correction - earliestScrollOffset, + ); + final SliverMultiBoxAdaptorParentData childParentData = + firstChild.parentData as SliverMultiBoxAdaptorParentData; + childParentData.layoutOffset = 0.0; + //print("correcting here ${childParentData.layoutOffset} == 0.0"); + + return; + } + + final SliverMultiBoxAdaptorParentData childParentData = + earliestUsefulChild.parentData as SliverMultiBoxAdaptorParentData; + childParentData.layoutOffset = firstChildScrollOffset; + //print("layout offset update ${childParentData.layoutOffset} == 0.0"); + + assert(earliestUsefulChild == firstChild); + leadingChildWithLayout = earliestUsefulChild; + trailingChildWithLayout ??= earliestUsefulChild; + // If we hit the point for the scroll, then we use that. + //print('scroll up $newTopScrollIndex $childParentData'); + if (newTopScrollIndex != null) { + if (childParentData.index == newTopScrollIndex) { + newTopScrollIndex = null; + // Fix the geometry to match where we are. + if (childParentData.layoutOffset != scrollOffset) { + geometry = SliverGeometry( + scrollOffsetCorrection: + childParentData.layoutOffset - scrollOffset, + ); + } + debugPrint('$geometry $scrollOffset ${childParentData.layoutOffset}'); + return; + } + } + } + + // At this point, earliestUsefulChild is the first child, and is a child + // whose scrollOffset is at or before the scrollOffset, and + // leadingChildWithLayout and trailingChildWithLayout are either null or + // cover a range of render boxes that we have laid out with the first being + // the same as earliestUsefulChild and the last being either at or after the + // scroll offset. + + assert(earliestUsefulChild == firstChild); + assert(childScrollOffset(earliestUsefulChild) <= scrollOffset); + + if (earliestUsefulChild != null) { + final SliverMultiBoxAdaptorParentData parentData = + earliestUsefulChild.parentData as SliverMultiBoxAdaptorParentData; + state.currentTopDisplayIndex = parentData.index ~/ 2; + } + + // Make sure we've laid out at least one child. + if (leadingChildWithLayout == null) { + earliestUsefulChild.layout(childConstraints, parentUsesSize: true); + leadingChildWithLayout = earliestUsefulChild; + trailingChildWithLayout = earliestUsefulChild; + } + + // Here, earliestUsefulChild is still the first child, it's got a + // scrollOffset that is at or before our actual scrollOffset, and it has + // been laid out, and is in fact our leadingChildWithLayout. It's possible + // that some children beyond that one have also been laid out. + + bool inLayoutRange = true; + RenderBox child = earliestUsefulChild; + int index = indexOf(child); + double endScrollOffset = childScrollOffset(child) + paintExtentOf(child); + bool advance() { + // returns true if we advanced, false if we have no more children + // This function is used in two different places below, to avoid code duplication. + assert(child != null); + if (child == trailingChildWithLayout) { + inLayoutRange = false; + } + child = childAfter(child); + if (child == null) { + inLayoutRange = false; + } + index += 1; + if (!inLayoutRange) { + if (child == null || indexOf(child) != index) { + // We are missing a child. Insert it (and lay it out) if possible. + child = insertAndLayoutChild( + childConstraints, + after: trailingChildWithLayout, + parentUsesSize: true, + ); + if (child == null) { + // We have run out of children. + debugPrint('No children $geometry'); + return false; + } + } else { + // Lay out the child. + child.layout(childConstraints, parentUsesSize: true); + } + trailingChildWithLayout = child; + } + assert(child != null); + final SliverMultiBoxAdaptorParentData childParentData = + child.parentData as SliverMultiBoxAdaptorParentData; + childParentData.layoutOffset = endScrollOffset; + assert(childParentData.index == index); + endScrollOffset = childScrollOffset(child) + paintExtentOf(child); + //print('froggy frogg ${childParentData.layoutOffset}'); + return true; + } + + // Find the first child that ends after the scroll offset. + while (endScrollOffset < scrollOffset) { + leadingGarbage += 1; + if (!advance()) { + assert(leadingGarbage == childCount); + assert(child == null); + // we want to make sure we keep the last child around so we know the end scroll offset + collectGarbage(leadingGarbage - 1, 0); + assert(firstChild == lastChild); + final double extent = + childScrollOffset(lastChild) + paintExtentOf(lastChild); + geometry = SliverGeometry( + scrollExtent: extent, + paintExtent: 0.0, + maxPaintExtent: extent, + ); + //print("Stuff here"); + return; + } + + // Check here to see if we should drop out because we hit the endpoint. + if (newTopScrollIndex != null) { + SliverMultiBoxAdaptorParentData childParentData = + lastChild.parentData as SliverMultiBoxAdaptorParentData; + debugPrint( + 'top scroll offset! 2 $newTopScrollIndex ${childParentData.index}'); + if (childParentData.index == newTopScrollIndex) { + newTopScrollIndex = null; + + // Fix the geometry to match where we are. + if (childParentData.layoutOffset != scrollOffset) { + geometry = SliverGeometry( + scrollOffsetCorrection: + childParentData.layoutOffset - scrollOffset, + ); + } + // Force it to layout down to the bottom of this page. + targetEndScrollOffset = endScrollOffset + remainingPaintExtent; + debugPrint('$geometry $scrollOffset ${childParentData.layoutOffset}'); + forceScrollUpdate = true; + break; + } + } + } + + // Now find the first child that ends after our end. + while (endScrollOffset < targetEndScrollOffset) { + if (!advance()) { + reachedEnd = true; + break; + } + } + + // Finally count up all the remaining children and label them as garbage. + if (child != null) { + child = childAfter(child); + while (child != null) { + trailingGarbage += 1; + child = childAfter(child); + } + } + + // At this point everything should be good to go, we just have to clean up + // the garbage and report the geometry. + + collectGarbage(leadingGarbage, trailingGarbage); + + assert(debugAssertChildListIsNonEmptyAndContiguous()); + double estimatedMaxScrollOffset; + if (reachedEnd) { + estimatedMaxScrollOffset = endScrollOffset; + } else { + estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset( + constraints, + firstIndex: indexOf(firstChild), + lastIndex: indexOf(lastChild), + leadingScrollOffset: childScrollOffset(firstChild), + trailingScrollOffset: endScrollOffset, + ); + assert(estimatedMaxScrollOffset >= + endScrollOffset - childScrollOffset(firstChild)); + } + final double paintExtent = calculatePaintOffset( + constraints, + from: childScrollOffset(firstChild), + to: endScrollOffset, + ); + + SliverMultiBoxAdaptorParentData childParentData = + firstChild.parentData as SliverMultiBoxAdaptorParentData; + geometry = SliverGeometry( + scrollOffsetCorrection: forceScrollUpdate + ? childParentData.layoutOffset - scrollOffset + : null, + scrollExtent: estimatedMaxScrollOffset, + paintExtent: paintExtent, + maxPaintExtent: estimatedMaxScrollOffset, + // Conservative to avoid flickering away the clip during scroll. + hasVisualOverflow: endScrollOffset > targetEndScrollOffset || + constraints.scrollOffset > 0.0, + ); + //print('fluffy rabbits $geometry'); + + // We may have started the layout while scrolled to the end, which would not + // expose a new child. + if (estimatedMaxScrollOffset == endScrollOffset) { + childManager.setDidUnderflow(true); + } + childManager.didFinishLayout(); + } + + @override + double childCrossAxisPosition(RenderBox child) { + //print('render $child ${super.childCrossAxisPosition(child)}'); + return super.childCrossAxisPosition(child); + } +} + +class SliverListCenter extends SliverMultiBoxAdaptorWidget { + /// Creates a sliver that places box children in a linear array. + const SliverListCenter({ + @required SliverChildDelegate delegate, + @required this.controller, + @required this.state, + Key key, + this.startIndex = 0, + }) : super(key: key, delegate: delegate); + + @override + RenderSliverCenterList createRenderObject(BuildContext context) { + final SliverMultiBoxAdaptorElement element = + context as SliverMultiBoxAdaptorElement; + RenderSliverCenterList ret = RenderSliverCenterList( + childManager: element, startIndex: startIndex, state: state); + state.renderSliverList = ret; + return ret; + } + + final int startIndex; + final ScrollController controller; + final CalendarWidgetState state; + + /// Returns an estimate of the max scroll extent for all the children. + /// + /// Subclasses should override this function if they have additional + /// information about their max scroll extent. + /// + /// This is used by [SliverMultiBoxAdaptorElement] to implement part of the + /// [RenderSliverBoxChildManager] API. + /// + /// The default implementation defers to [delegate] via its + /// [SliverChildDelegate.estimateMaxScrollOffset] method. + @override + double estimateMaxScrollOffset( + SliverConstraints constraints, + int firstIndex, + int lastIndex, + double leadingScrollOffset, + double trailingScrollOffset, + ) { + assert(lastIndex >= firstIndex); + return delegate.estimateMaxScrollOffset( + firstIndex, + lastIndex, + leadingScrollOffset, + trailingScrollOffset, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + .add(DiagnosticsProperty('delegate', delegate)); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/sliverscrollviewcalendar.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/sliverscrollviewcalendar.dart new file mode 100644 index 00000000..879c77f9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/lib/src/sliverscrollviewcalendar.dart @@ -0,0 +1,610 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:intl/intl.dart'; +import 'package:timezone/timezone.dart'; + +import 'calendar.dart'; +import 'calendardaymarker.dart'; +import 'calendarevent.dart'; +import 'sliverlistcalendar.dart'; + +class SliverScrollViewCalendarElement extends StatelessElement + implements CalendarEventElement { + SliverScrollViewCalendarElement(SliverScrollViewCalendar widget, this._state) + : _currentLocation = widget.location, + _nowIndex = CalendarEvent.indexFromMilliseconds( + TZDateTime.now(widget.location), widget.location), + _startDisplayIndex = widget.initialDate.millisecondsSinceEpoch ~/ + Duration.millisecondsPerDay * + 2 - + 2, + _beginningRangeIndex = + widget.beginningRangeDate.millisecondsSinceEpoch ~/ + Duration.millisecondsPerDay * + 2 - + 2, + _endingRangeIndex = widget.endingRangeDate.millisecondsSinceEpoch ~/ + Duration.millisecondsPerDay * + 2 - + 2, + _type = widget.view, + super(widget) { + _state.element = this; + + // Normalize the dates. + TZDateTime normalizedStart = TZDateTime( + _currentLocation, + widget.initialDate.year, + widget.initialDate.month, + widget.initialDate.day); + switch (_type) { + case CalendarViewType.Schedule: + // Grab 60 days ahead and 60 days behind. + _startWindow = normalizedStart.subtract(Duration(days: 60)); + _endWindow = normalizedStart.add(Duration(days: 60)); + break; + case CalendarViewType.Week: + _startWindow = TZDateTime(_currentLocation, widget.initialDate.year, + widget.initialDate.month, widget.initialDate.day); + if (_startWindow.weekday != 0) { + if (_startWindow.weekday < 0) { + _startWindow = _startWindow.subtract(Duration( + days: 0 - DateTime.daysPerWeek + _startWindow.weekday)); + } else { + _startWindow = + _startWindow.subtract(Duration(days: 0 - _startWindow.weekday)); + } + _endWindow = _startWindow.add(Duration(days: DateTime.daysPerWeek)); + } + break; + case CalendarViewType.Month: + _startWindow = TZDateTime(_currentLocation, widget.initialDate.year, + widget.initialDate.month); + _endWindow = TZDateTime(_currentLocation, widget.initialDate.year, + widget.initialDate.month + 1); + break; + } + } + + TZDateTime _startWindow; + TZDateTime _endWindow; + CalendarViewType _type; + Set _rangeVisible = Set(); + // View index is the number of days since the epoch. + int _startDisplayIndex; + int _beginningRangeIndex; + int _endingRangeIndex; + Location _currentLocation; + int _nowIndex; + CalendarWidgetState _state; + StreamSubscription _topIndexChangedSubscription; + + void initState() { + _state.currentTopDisplayIndex = _startDisplayIndex ~/ 2; + debugPrint("Display index $_startDisplayIndex $_nowIndex"); + updateEvents(); + _topIndexChangedSubscription = + _state.indexChangeStream.listen((int newIndex) { + // NB: this is the display index, so in GM + int ms = newIndex * Duration.millisecondsPerDay; + + bool changed = false; + TZDateTime top = + TZDateTime.fromMillisecondsSinceEpoch(_currentLocation, ms); + if (_startWindow.difference(top).inDays < 30 || + top.isBefore(_startWindow)) { + // Set a new start window. + debugPrint("Moving start window $newIndex $top $_startWindow"); + _startWindow = top.subtract(Duration(days: 60)); + changed = true; + } + if (_endWindow.difference(top).inDays < 30 || top.isAfter(_endWindow)) { + _endWindow = top.add(Duration(days: 60)); + changed = true; + } + if (changed) { + debugPrint("Updating between $_startWindow $_endWindow"); + updateEvents(); + } + }); + } + + @override + void updateEvents() { + // Now do stuff with our events. + _state.updateInternalEvents(_startWindow, _endWindow); + markNeedsBuild(); + } + + @override + void scrollToDate(DateTime time) { + SliverScrollViewCalendar calendarWidget = + widget as SliverScrollViewCalendar; + RenderBox firstChild = _state.renderSliverList.firstChild; + int scrollToIndex = + time.millisecondsSinceEpoch ~/ Duration.millisecondsPerDay * 2; + if (firstChild != null) { + final SliverMultiBoxAdaptorParentData firstParentData = + firstChild.parentData as SliverMultiBoxAdaptorParentData; + // Already there... + if (firstParentData.index == scrollToIndex || + firstParentData.index == scrollToIndex + 1) { + return; + } + debugPrint( + 'Looking for $scrollToIndex ${firstParentData.index} ${time.month} ${time.day}'); + if (firstParentData.index < scrollToIndex) { + // See if it is in the visible set. + RenderBox lastChild = _state.renderSliverList.lastChild; + if (lastChild != null) { + final SliverMultiBoxAdaptorParentData lastParentData = + lastChild.parentData as SliverMultiBoxAdaptorParentData; + + if (lastParentData.index > scrollToIndex) { + // In range, easier scroll. + SliverMultiBoxAdaptorParentData parentData; + RenderBox currentChild = firstChild; + do { + currentChild = _state.renderSliverList.childAfter(currentChild); + parentData = + currentChild.parentData as SliverMultiBoxAdaptorParentData; + debugPrint('finding index ${parentData.index} $currentChild'); + } while (parentData.index != scrollToIndex); + if (parentData.index == scrollToIndex) { + // Yay! Scroll there and end. + calendarWidget.controller.animateTo(parentData.layoutOffset, + curve: Curves.easeIn, duration: Duration(milliseconds: 250)); + return; + } + } + } + } + _state.renderSliverList.newTopScrollIndex = scrollToIndex + 2; + // Move the index up and down by a lot to force the refresh/move. + if (firstParentData.index < scrollToIndex) { + calendarWidget.controller.jumpTo(calendarWidget.controller.offset + + Duration.microsecondsPerDay.toDouble()); + } else { + calendarWidget.controller.jumpTo(calendarWidget.controller.offset - + Duration.microsecondsPerDay.toDouble()); + } + } + } + + @override + void mount(Element parent, dynamic newSlot) { + initState(); + super.mount(parent, newSlot); + } + + @override + void rebuild() { + _rangeVisible.clear(); + super.rebuild(); + } + + Widget _buildCalendarWidget(BuildContext context, int mainIndex) { + final DateFormat monthFormat = + DateFormat.MMM(Localizations.localeOf(context).languageCode); + final DateFormat dayOfWeekFormat = + DateFormat.E(Localizations.localeOf(context).languageCode); + final DateFormat dayOfMonthFormat = + DateFormat.MMMd(Localizations.localeOf(context).languageCode); + + SliverScrollViewCalendar calendarWidget = + widget as SliverScrollViewCalendar; + const double widthFirst = 40.0; + const double inset = 5.0; + int ms = mainIndex ~/ 2 * Duration.millisecondsPerDay; + DateTime time = DateTime.fromMillisecondsSinceEpoch(ms); + if (mainIndex % 2 == 1) { + int index = CalendarEvent.indexFromMilliseconds(time, null); + if (_state.events.containsKey(index)) { + List events = _state.events[index]; + DateTime day = events[0].instant; + final Size screenSize = MediaQuery.of(context).size; + double widthSecond = screenSize.width - widthFirst - inset; + TextStyle style = Theme.of(context).textTheme.subtitle1.copyWith( + fontWeight: FontWeight.w300, + ); + List displayEvents = []; + if (index == _nowIndex) { + TZDateTime nowTime = TZDateTime.now(_currentLocation); + style.copyWith(color: Theme.of(context).accentColor); + int lastMS = + nowTime.millisecondsSinceEpoch - Duration.millisecondsPerDay; + bool shownDivider = false; + for (CalendarEvent e in events) { + if (e.instant.millisecondsSinceEpoch > lastMS && + nowTime.isBefore(e.instantEnd)) { + // Stick in the 'now marker' right here. + displayEvents.add(CalendarDayMarker( + color: Colors.redAccent, + )); + displayEvents.add(_state.widget.buildItem(context, e)); + shownDivider = true; + } else if (e.instant.isAfter(nowTime) && + e.instantEnd.isBefore(nowTime)) { + // Show on top of this card. + displayEvents.add(Stack( + children: [ + _state.widget.buildItem(context, e), + CalendarDayMarker(color: Colors.redAccent), + ], + )); + } else { + displayEvents.add(_state.widget.buildItem(context, e)); + } + } + if (!shownDivider) { + displayEvents.add(CalendarDayMarker(color: Colors.redAccent)); + } + } else { + displayEvents = events + .map( + (CalendarEvent e) => _state.widget.buildItem(context, e), + ) + .toList(); + } + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + constraints: BoxConstraints.tightFor(width: widthFirst), + margin: EdgeInsets.only(top: 14.0, left: inset), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + dayOfWeekFormat.format(day), + style: style, + ), + Text( + dayOfMonthFormat.format(day), + style: style.copyWith(fontSize: 12.0), + ), + ], + ), + ), + Container( + constraints: BoxConstraints.tightFor(width: widthSecond), + margin: EdgeInsets.only(top: 10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: displayEvents, + ), + ), + ], + ); + } else { + int startIndex = index; + DateTime start = time; + // Show day/month headers + if (!_state.events.containsKey(CalendarEvent.indexFromMilliseconds( + time.add(oneDay), _currentLocation)) || + !_state.events.containsKey(CalendarEvent.indexFromMilliseconds( + time.subtract(oneDay), _currentLocation))) { + DateTime hardStart = DateTime(start.year, start.month, 1); + DateTime hardEnd = + DateTime(start.year, start.month + 1).subtract(oneDay); + DateTime cur = start; + DateTime last = cur; + bool foundEnd = false; + if (_rangeVisible.contains(startIndex)) { + foundEnd = true; + } + int lastIndex = startIndex; + while (hardEnd.compareTo(last) > 0 && + !_state.events.containsKey(lastIndex + 1)) { + last = last.add(oneDay); + lastIndex = + CalendarEvent.indexFromMilliseconds(last, _currentLocation); + if (_rangeVisible.contains(lastIndex)) { + foundEnd = true; + } + } + // Pull back to the start too. + cur = start; + while (hardStart.compareTo(cur) < 0 && + !_state.events.containsKey(startIndex)) { + start = cur; + cur = cur.subtract(oneDay); + if (hardStart.compareTo(cur) < 0) { + startIndex = + CalendarEvent.indexFromMilliseconds(cur, _currentLocation); + if (_rangeVisible.contains(startIndex)) { + foundEnd = true; + } + } + } + if (index % 50 == 0) { + debugPrint('loc $index $startIndex $lastIndex $foundEnd'); + } + + if (!foundEnd && + !_rangeVisible.contains(startIndex) && + !_rangeVisible.contains(lastIndex)) { + _rangeVisible.add(startIndex); + _rangeVisible.add(lastIndex); + // Range + if (_nowIndex > startIndex && _nowIndex <= lastIndex) { + debugPrint('$startIndex $lastIndex $_nowIndex $start $last'); + return Container( + margin: EdgeInsets.only(top: 15.0, left: 5.0), + child: Stack( + children: [ + Text( + monthFormat.format(start) + + " " + + start.day.toString() + + " - " + + last.day.toString(), + style: Theme.of(context).textTheme.subtitle1.copyWith( + fontSize: 12.0, + fontWeight: FontWeight.w300, + ), + ), + CalendarDayMarker( + indent: widthFirst, + color: Colors.redAccent, + ), + ], + ), + ); + } else { + return Container( + margin: EdgeInsets.only(top: 15.0, left: 5.0), + child: Text( + monthFormat.format(start) + + " " + + start.day.toString() + + " - " + + last.day.toString(), + style: Theme.of(context).textTheme.subtitle1.copyWith( + fontSize: 12.0, + fontWeight: FontWeight.w300, + ), + ), + ); + } + } + } else { + // Single day + if (_nowIndex == index) { + return Container( + margin: EdgeInsets.only(top: 10.0, left: 5.0), + child: Stack( + children: [ + Text( + MaterialLocalizations.of(context).formatMediumDate(start), + style: Theme.of(context).textTheme.subtitle1.copyWith( + fontSize: 12.0, + fontWeight: FontWeight.w300, + ), + ), + CalendarDayMarker( + indent: widthFirst, + color: Colors.redAccent, + ), + ], + ), + ); + } else { + return Container( + margin: EdgeInsets.only(top: 10.0, left: 5.0), + child: Text( + MaterialLocalizations.of(context).formatMediumDate(start), + style: Theme.of(context).textTheme.subtitle1.copyWith( + fontSize: 12.0, + fontWeight: FontWeight.w300, + ), + ), + ); + } + } + } + } else { + // Put in the month header if we are at the start of the month. + TZDateTime start = + TZDateTime(_currentLocation, time.year, time.month, time.day); + if (start.day == 1) { + return Container( + decoration: calendarWidget.monthHeader != null + ? BoxDecoration( + color: Colors.blue, + image: DecorationImage( + image: calendarWidget.monthHeader, + fit: BoxFit.cover, + ), + ) + : null, + margin: EdgeInsets.only(top: 30.0), + padding: EdgeInsets.only(left: 5.0), + constraints: calendarWidget.monthHeader != null + ? BoxConstraints(minHeight: 100.0, maxHeight: 100.0) + : null, + child: Text( + MaterialLocalizations.of(context).formatMonthYear(start), + style: Theme.of(context).textTheme.headline6.copyWith( + color: calendarWidget.monthHeader != null + ? Colors.white + : Colors.black, + fontSize: 30.0, + ), + ), + ); + } + } + return const SizedBox(height: 0.1); + } + + SliverListCenter _buildCalendarList() { + SliverScrollViewCalendar calendarWidget = + widget as SliverScrollViewCalendar; + return SliverListCenter( + startIndex: _startDisplayIndex, + state: _state, + controller: calendarWidget.controller, + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + if (index < _beginningRangeIndex || + (_endingRangeIndex != -1 && index > _endingRangeIndex)) { + return null; + } + return _buildCalendarWidget(context, index); + }, + ), + ); + } + + void didUpdateWidget(covariant SliverScrollViewCalendar oldWidget) {} + + @override + void update(StatelessWidget newWidget) { + super.update(newWidget); + assert(widget == newWidget); + // Notice that we mark ourselves as dirty before calling didUpdateWidget to + // let authors call setState from within didUpdateWidget without triggering + // asserts. + markNeedsBuild(); + rebuild(); + } + + @override + void activate() { + super.activate(); + markNeedsBuild(); + } + + @override + void unmount() { + super.unmount(); + //_state.dispose(); + _topIndexChangedSubscription.cancel(); + } +} + +class SliverScrollViewCalendar extends ScrollView { + SliverScrollViewCalendar({ + @required this.initialDate, + @required double initialScrollOffset, + @required this.state, + @required this.beginningRangeDate, + @required this.endingRangeDate, + @required this.location, + this.monthHeader, + this.view = CalendarViewType.Schedule, + }) : super( + scrollDirection: Axis.vertical, + shrinkWrap: true, + controller: + ScrollController(initialScrollOffset: initialScrollOffset)) { + state.controller = controller; + } + + final DateTime initialDate; + final DateTime beginningRangeDate; + final DateTime endingRangeDate; + final CalendarViewType view; + final Location location; + final ImageProvider monthHeader; + final CalendarWidgetState state; + + @override + SliverScrollViewCalendarElement createElement() => + SliverScrollViewCalendarElement(this, state); + + @override + List buildSlivers(BuildContext context) { + SliverScrollViewCalendarElement element = + context as SliverScrollViewCalendarElement; + return [ + element._buildCalendarList(), + ]; + } +} + +/// +/// This wraps the calendar im a scroll view. +/// +class WrappedScrollViewCalendar extends StatefulWidget { + WrappedScrollViewCalendar({ + @required this.initialDate, + @required this.initialScrollOffset, + @required this.state, + @required this.beginningRangeDate, + @required this.endingRangeDate, + this.monthHeader, + this.tapToCloseHeader = true, + this.view = CalendarViewType.Schedule, + Location location, + }) : location = location ?? local; + + final DateTime initialDate; + final DateTime beginningRangeDate; + final DateTime endingRangeDate; + final CalendarViewType view; + final Location location; + final double initialScrollOffset; + final ImageProvider monthHeader; + final bool tapToCloseHeader; + final CalendarWidgetState state; + + @override + _WrapperScrollViewCalendarState createState() { + return _WrapperScrollViewCalendarState(); + } +} + +class _WrapperScrollViewCalendarState extends State { + StreamSubscription _onHeaderExpandChange; + + @override + void initState() { + super.initState(); + _onHeaderExpandChange = + widget.state.headerExpandedChangeStream.listen((bool update) { + setState(() {}); + }); + } + + @override + void dispose() { + super.dispose(); + _onHeaderExpandChange?.cancel(); + _onHeaderExpandChange = null; + } + + void _handleTapOnHeaderExpanded() { + widget.state.headerExpanded = false; + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: widget.tapToCloseHeader && widget.state.headerExpanded + ? _handleTapOnHeaderExpanded + : null, + child: SliverScrollViewCalendar( + initialDate: widget.initialDate, + beginningRangeDate: widget.beginningRangeDate, + endingRangeDate: widget.endingRangeDate, + state: widget.state, + location: widget.location, + view: widget.view, + monthHeader: widget.monthHeader, + initialScrollOffset: widget.initialScrollOffset, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/main.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/main.dart new file mode 100644 index 00000000..040dcdbd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar/main.dart @@ -0,0 +1,130 @@ +import 'dart:async'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart' show rootBundle; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_native_timezone/flutter_native_timezone.dart'; +import 'package:timezone/timezone.dart'; + +import 'lib/sliver_calendar.dart'; + +void main() async { + // Comment this line to enable debug printing... + debugPrint = (String message, {int wrapWidth}) {}; + + ByteData loadedData; + + await Future.wait(>[ + rootBundle.load('assets/timezone/2018c.tzf').then((ByteData data) { + loadedData = data; + print('loaded data'); + }) + ]); + initializeDatabase(loadedData.buffer.asUint8List()); + runApp(new CalendarApp()); +} + +class CalendarApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Flutter Calendar', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + debugShowCheckedModeBanner: false, + localizationsDelegates: const < + LocalizationsDelegate>[ + GlobalMaterialLocalizations.delegate + ], + supportedLocales: const [ + const Locale('en', ''), + const Locale('fr', ''), + ], + home: new MyHomePage(title: 'Flutter Calendar demo'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + final String title; + + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +class _MyHomePageState extends State { + List events = []; + Location loc; + Random random = new Random(); + + Widget buildItem(BuildContext context, CalendarEvent e) { + return new Card( + child: new ListTile( + title: new Text("Event ${e.index}"), + subtitle: new Text("Yay for events"), + leading: const Icon(Icons.gamepad), + ), + ); + } + + List getEvents(DateTime start, DateTime end) { + if (loc != null && events.length == 0) { + TZDateTime nowTime = + new TZDateTime.now(loc).subtract(new Duration(days: 5)); + for (int i = 0; i < 20; i++) { + TZDateTime start = + nowTime.add(new Duration(days: i + random.nextInt(10))); + events.add(new CalendarEvent( + index: i, + instant: start, + instantEnd: start.add(new Duration(minutes: 30)))); + } + } + return events; + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + ), + body: new Column( + children: [ + new FutureBuilder( + future: FlutterNativeTimezone.getLocalTimezone(), + builder: (BuildContext context, AsyncSnapshot tz) { + if (tz.hasData) { + loc = getLocation(tz.data); + TZDateTime nowTime = new TZDateTime.now(loc); + return new Expanded( + child: new CalendarWidget( + initialDate: nowTime, + location: loc, + buildItem: buildItem, + getEvents: getEvents, + bannerHeader: + new AssetImage("assets/images/calendarheader.png"), + monthHeader: + new AssetImage("assets/images/calendarbanner.jpg"), + weekBeginsWithDay: + 1, // Sunday = 0, Monday = 1, Tuesday = 2, ..., Saturday = 6 + ), + ); + } else { + return new Center( + child: new Text("Getting the timezone..."), + ); + } + }, + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/event.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/event.dart new file mode 100644 index 00000000..c7a04262 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/event.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +class Event implements EventInterface { + final DateTime date; + final String title; + final Widget icon; + final Widget dot; + final int id; + Event({ + this.id, + @required this.date, + this.title, + this.icon, + this.dot, + }); + + @override + bool operator ==(dynamic other) { + return this.date == other.date && + this.title == other.title && + this.icon == other.icon && + this.dot == other.dot && + this.id == other.id; + } + + @override + int get hashCode => hashValues(date, title, icon, id); + + @override + DateTime getDate() { + return date; + } + + @override + int getId() { + return id; + } + + @override + Widget getDot() { + return dot; + } + + @override + Widget getIcon() { + return icon; + } + + @override + String getTitle() { + return title; + } +} + +abstract class EventInterface { + DateTime getDate(); + String getTitle(); + Widget getIcon(); + Widget getDot(); + int getId(); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/event_list.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/event_list.dart new file mode 100644 index 00000000..4298a0f3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/event_list.dart @@ -0,0 +1,42 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +class EventList { + Map> events; + + EventList({ + @required this.events, + }); + + void add(DateTime date, T event) { + final eventsOfDate = events[date]; + if (eventsOfDate == null) + events[date] = [event]; + else + eventsOfDate.add(event); + } + + void addAll(DateTime date, List events) { + final eventsOfDate = this.events[date]; + if (eventsOfDate == null) + this.events[date] = events; + else + eventsOfDate.addAll(events); + } + + bool remove(DateTime date, T event) { + final eventsOfDate = events[date]; + return eventsOfDate != null ? eventsOfDate.remove(event) : false; + } + + List removeAll(DateTime date) { + return events.remove(date) ?? []; + } + + void clear() { + events.clear(); + } + + List getEvents(DateTime date) { + return events[date] ?? []; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/marked_date.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/marked_date.dart new file mode 100644 index 00000000..9bc52c14 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/marked_date.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class MarkedDate implements MarkedDateInterface { + final Color color; + final int id; + final TextStyle textStyle; + final DateTime date; + + MarkedDate({ + @required this.color, + this.id, + this.textStyle, + @required this.date, + }); + + @override + bool operator ==(dynamic other) { + return this.date == other.date && + this.color == other.color && + this.textStyle == other.textStyle && + this.id == other.id; + } + + @override + DateTime getDate() => this.date; + + @override + int getId() => this.id; + + @override + Color getColor() => this.color; + + + @override + TextStyle getTextStyle() => this.textStyle; +} + + + + +abstract class MarkedDateInterface { + DateTime getDate(); + Color getColor(); + int getId(); + TextStyle getTextStyle(); + +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/multiple_marked_dates.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/multiple_marked_dates.dart new file mode 100644 index 00000000..4a9522b3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/classes/multiple_marked_dates.dart @@ -0,0 +1,48 @@ + +import 'marked_date.dart'; +import 'package:flutter/material.dart'; + +class MultipleMarkedDates{ + List markedDates; + + MultipleMarkedDates({@required this.markedDates}); + + void add(MarkedDate markedDate){ + markedDates.add(markedDate); + } + + void addAll(List markedDates){ + this.markedDates.addAll(markedDates); + } + + bool remove(MarkedDate markedDate){ + return markedDates.remove(markedDate); + } + + void clear() { + markedDates.clear(); + } + + bool isMarked(DateTime date){ + final results = markedDates.firstWhere((element) => element.date == date, orElse: () => MarkedDate(color: Colors.black, date: DateTime(0))); + return results.date.year == date.year; + } + + Color getColor(DateTime date){ + final results = markedDates.firstWhere((element) => element.date == date, orElse: () => MarkedDate(color: Colors.black, date: DateTime(0))); + return results.color; + } + + DateTime getDate(DateTime date){ + final results = markedDates.firstWhere((element) => element.date == date, orElse: () => MarkedDate(color: Colors.black, date: DateTime(0))); + return results.date; + } + + TextStyle getTextStyle(DateTime date){ + final results = markedDates.firstWhere((element) => element.date == date, orElse: () => MarkedDate(color: Colors.black, date: DateTime(0))); + return results.textStyle; + } + + + +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/flutter_calendar_carousel.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/flutter_calendar_carousel.dart new file mode 100644 index 00000000..263e304f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/flutter_calendar_carousel.dart @@ -0,0 +1,1217 @@ +library flutter_calendar_dooboo; + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'classes/event.dart'; +import 'classes/event_list.dart'; +import 'src/calendar_header.dart'; +import 'src/default_styles.dart'; +import 'src/weekday_row.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:intl/intl.dart' show DateFormat; + +import 'classes/multiple_marked_dates.dart'; + + +typedef MarkedDateIconBuilder = Widget Function(T event); +typedef void OnDayLongPressed(DateTime day); + +/// This builder is called for every day in the calendar. +/// If you want to build only few custom day containers, return null for the days you want to leave with default looks +/// All characteristics like circle border are also applied to the custom day container [DayBuilder] provides. +/// (if supplied function returns null, Calendar's function will be called for [day]). +/// [isSelectable] - is between [CalendarCarousel.minSelectedDate] and [CalendarCarousel.maxSelectedDate] +/// [index] - DOES NOT equal day number! Index of the day built in current visible field +/// [isSelectedDay] - if the day is selected +/// [isToday] - if the day is similar to [DateTime.now()] +/// [isPrevMonthDay] - if the day is from previous month +/// [textStyle] - text style that would have been applied by the calendar if it was to build the day. +/// Example: if the user provided [CalendarCarousel.todayTextStyle] and [isToday] is true, +/// [CalendarCarousel.todayTextStyle] would be sent into [DayBuilder]'s [textStyle]. If user didn't +/// provide it, default [CalendarCarousel]'s textStyle would be sent. Same applies to all text styles like +/// [CalendarCarousel.prevDaysTextStyle], [CalendarCarousel.daysTextStyle] etc. +/// [isNextMonthDay] - if the day is from next month +/// [isThisMonthDay] - if the day is from next month +/// [day] - day being built. +typedef Widget DayBuilder( + bool isSelectable, + int index, + bool isSelectedDay, + bool isToday, + bool isPrevMonthDay, + TextStyle textStyle, + bool isNextMonthDay, + bool isThisMonthDay, + DateTime day); + +/// This builder is called for every weekday container (7 times, from Mon to Sun). +/// [weekday] - weekday built, from 0 to 6. +/// [weekdayName] - string representation of the weekday (Mon, Tue, Wed, etc). +typedef Widget WeekdayBuilder(int weekday, String weekdayName); + +class CalendarCarousel extends StatefulWidget { + final double viewportFraction; + final TextStyle prevDaysTextStyle; + final TextStyle daysTextStyle; + final TextStyle nextDaysTextStyle; + final Color prevMonthDayBorderColor; + final Color thisMonthDayBorderColor; + final Color nextMonthDayBorderColor; + final double dayPadding; + final double height; + final double width; + final TextStyle todayTextStyle; + final Color dayButtonColor; + final Color todayBorderColor; + final Color todayButtonColor; + final DateTime selectedDateTime; + final DateTime targetDateTime; + final TextStyle selectedDayTextStyle; + final Color selectedDayButtonColor; + final Color selectedDayBorderColor; + final bool daysHaveCircularBorder; + final bool disableDayPressed; + final Function(DateTime, List) onDayPressed; + final TextStyle weekdayTextStyle; + final Color iconColor; + final TextStyle headerTextStyle; + final String headerText; + final TextStyle weekendTextStyle; + final EventList markedDatesMap; + + /// Change `makredDateWidget` when `markedDateShowIcon` is set to false. + final Widget markedDateWidget; + + /// Change `ShapeBorder` when `markedDateShowIcon` is set to false. + final ShapeBorder markedDateCustomShapeBorder; + + /// Change `TextStyle` when `markedDateShowIcon` is set to false. + final TextStyle markedDateCustomTextStyle; + + /// Icon will overlap the [Day] widget when `markedDateShowIcon` is set to true. + /// This will also make below parameters work. + final bool markedDateShowIcon; + final Color markedDateIconBorderColor; + final int markedDateIconMaxShown; + final double markedDateIconMargin; + final double markedDateIconOffset; + final MarkedDateIconBuilder markedDateIconBuilder; + + /// null - no indicator, true - show the total events, false - show the total of hidden events + final bool markedDateMoreShowTotal; + final Decoration markedDateMoreCustomDecoration; + final TextStyle markedDateMoreCustomTextStyle; + final EdgeInsets headerMargin; + final double childAspectRatio; + final EdgeInsets weekDayMargin; + final EdgeInsets weekDayPadding; + final WeekdayBuilder customWeekDayBuilder; + final DayBuilder customDayBuilder; + final Color weekDayBackgroundColor; + final bool weekFormat; + final bool showWeekDays; + final bool showHeader; + final bool showHeaderButton; + final MultipleMarkedDates multipleMarkedDates; + final Widget leftButtonIcon; + final Widget rightButtonIcon; + final ScrollPhysics customGridViewPhysics; + final Function(DateTime) onCalendarChanged; + final String locale; + final int firstDayOfWeek; + final DateTime minSelectedDate; + final DateTime maxSelectedDate; + final TextStyle inactiveDaysTextStyle; + final TextStyle inactiveWeekendTextStyle; + final bool headerTitleTouchable; + final Function onHeaderTitlePressed; + final Function onLeftArrowPressed; + final Function onRightArrowPressed; + final WeekdayFormat weekDayFormat; + final bool staticSixWeekFormat; + final bool isScrollable; + final Axis scrollDirection; + final bool showOnlyCurrentMonthDate; + final bool pageSnapping; + final OnDayLongPressed onDayLongPressed; + final CrossAxisAlignment dayCrossAxisAlignment; + final MainAxisAlignment dayMainAxisAlignment; + final bool showIconBehindDayText; + final ScrollPhysics pageScrollPhysics; + final bool shouldShowTransform; + + CalendarCarousel({ + Key key, + this.viewportFraction = 1.0, + this.prevDaysTextStyle, + this.daysTextStyle, + this.nextDaysTextStyle, + this.prevMonthDayBorderColor = Colors.transparent, + this.thisMonthDayBorderColor = Colors.transparent, + this.nextMonthDayBorderColor = Colors.transparent, + this.dayPadding = 2.0, + this.height = double.infinity, + this.width = double.infinity, + this.todayTextStyle, + this.dayButtonColor = Colors.transparent, + this.todayBorderColor = Colors.red, + this.todayButtonColor = Colors.red, + this.selectedDateTime, + this.targetDateTime, + this.selectedDayTextStyle, + this.selectedDayBorderColor = Colors.green, + this.selectedDayButtonColor = Colors.green, + this.daysHaveCircularBorder, + this.disableDayPressed = false, + this.onDayPressed, + this.weekdayTextStyle = const TextStyle(), + this.iconColor = Colors.blueAccent, + this.headerTextStyle, + this.headerText, + this.weekendTextStyle, + this.markedDatesMap, + this.markedDateShowIcon = false, + this.markedDateIconBorderColor, + this.markedDateIconMaxShown = 2, + this.markedDateIconMargin = 5.0, + this.markedDateIconOffset = 5.0, + this.markedDateIconBuilder, + this.markedDateMoreShowTotal, + this.markedDateMoreCustomDecoration, + this.markedDateCustomShapeBorder, + this.markedDateCustomTextStyle, + this.markedDateMoreCustomTextStyle, + this.markedDateWidget, + this.multipleMarkedDates, + this.headerMargin = const EdgeInsets.symmetric(vertical: 16.0), + this.childAspectRatio = 1.0, + this.weekDayMargin = const EdgeInsets.only(bottom: 4.0), + this.weekDayPadding = const EdgeInsets.all(0.0), + this.weekDayBackgroundColor = Colors.transparent, + this.customWeekDayBuilder, + this.customDayBuilder, + this.showWeekDays = true, + this.weekFormat = false, + this.showHeader = true, + this.showHeaderButton = true, + this.leftButtonIcon, + this.rightButtonIcon, + this.customGridViewPhysics, + this.onCalendarChanged, + this.locale = "en", + this.firstDayOfWeek, + this.minSelectedDate, + this.maxSelectedDate, + this.inactiveDaysTextStyle, + this.inactiveWeekendTextStyle, + this.headerTitleTouchable = false, + this.onHeaderTitlePressed, + this.onLeftArrowPressed, + this.onRightArrowPressed, + this.weekDayFormat = WeekdayFormat.short, + this.staticSixWeekFormat = false, + this.isScrollable = true, + this.scrollDirection = Axis.horizontal, + this.showOnlyCurrentMonthDate = false, + this.pageSnapping = false, + this.onDayLongPressed, + this.dayCrossAxisAlignment = CrossAxisAlignment.center, + this.dayMainAxisAlignment = MainAxisAlignment.center, + this.showIconBehindDayText = false, + this.pageScrollPhysics = const ScrollPhysics(), + this.shouldShowTransform = true, + }) : super(key: key); + + @override + _CalendarState createState() => _CalendarState(); +} + +enum WeekdayFormat { + weekdays, + standalone, + short, + standaloneShort, + narrow, + standaloneNarrow, +} + +class _CalendarState + extends State> { + PageController _controller; + List _dates; + List> _weeks; + DateTime _selectedDate = DateTime.now(); + DateTime _targetDate; + int _startWeekday = 0; + int _endWeekday = 0; + DateFormat _localeDate; + int _pageNum = 0; + DateTime minDate; + DateTime maxDate; + + /// When FIRSTDAYOFWEEK is 0 in dart-intl, it represents Monday. However it is the second day in the arrays of Weekdays. + /// Therefore we need to add 1 modulo 7 to pick the right weekday from intl. (cf. [GlobalMaterialLocalizations]) + int firstDayOfWeek; + + /// If the setState called from this class, don't reload the selectedDate, but it should reload selected date if called from external class + + @override + initState() { + super.initState(); + initializeDateFormatting(); + + minDate = widget.minSelectedDate ?? DateTime(2018); + maxDate = widget.maxSelectedDate ?? + DateTime( + DateTime.now().year + 1, DateTime.now().month, DateTime.now().day); + + final selectedDateTime = widget.selectedDateTime; + if (selectedDateTime != null) _selectedDate = selectedDateTime; + + _init(); + + /// setup pageController + _controller = PageController( + initialPage: this._pageNum, + keepPage: true, + viewportFraction: widget.viewportFraction, + + /// width percentage + ); + + _localeDate = DateFormat.yMMM(widget.locale); + firstDayOfWeek = widget.firstDayOfWeek ?? + (_localeDate.dateSymbols.FIRSTDAYOFWEEK + 1) % 7; + + _setDate(); + } + + @override + void didUpdateWidget(CalendarCarousel oldWidget) { + if (widget.targetDateTime != null && widget.targetDateTime != _targetDate) { + _init(); + _setDate(_pageNum); + } + + super.didUpdateWidget(oldWidget); + } + + @override + dispose() { + _controller.dispose(); + super.dispose(); + } + + _init() { + final targetDateTime = widget.targetDateTime; + if (targetDateTime != null) { + if (targetDateTime.difference(minDate).inDays < 0) { + _targetDate = minDate; + } else if (targetDateTime.difference(maxDate).inDays > 0) { + _targetDate = maxDate; + } else { + _targetDate = targetDateTime; + } + } else { + _targetDate = _selectedDate; + } + if (widget.weekFormat) { + _pageNum = _targetDate.difference(_firstDayOfWeek(minDate)).inDays ~/ 7; + } else { + _pageNum = (_targetDate.year - minDate.year) * 12 + + _targetDate.month - + minDate.month; + } + } + + @override + Widget build(BuildContext context) { + final headerText = widget.headerText; + return Container( + width: widget.width, + height: widget.height, + child: Column( + children: [ + CalendarHeader( + showHeader: widget.showHeader, + headerMargin: widget.headerMargin, + headerTitle: headerText != null + ? headerText + : widget.weekFormat + ? '${_localeDate.format(this._weeks[this._pageNum].first)}' + : '${_localeDate.format(this._dates[this._pageNum])}', + headerTextStyle: widget.headerTextStyle, + showHeaderButtons: widget.showHeaderButton, + headerIconColor: widget.iconColor, + leftButtonIcon: widget.leftButtonIcon, + rightButtonIcon: widget.rightButtonIcon, + onLeftButtonPressed: () { + widget.onLeftArrowPressed?.call(); + + if (this._pageNum > 0) _setDate(this._pageNum - 1); + }, + onRightButtonPressed: () { + widget.onRightArrowPressed?.call(); + + if (widget.weekFormat) { + if (this._weeks.length - 1 > this._pageNum) + _setDate(this._pageNum + 1); + } else { + if (this._dates.length - 1 > this._pageNum) + _setDate(this._pageNum + 1); + } + }, + onHeaderTitlePressed: widget.headerTitleTouchable + ? () { + final onHeaderTitlePressed = widget.onHeaderTitlePressed; + if (onHeaderTitlePressed != null) { + onHeaderTitlePressed(); + } else { + _selectDateFromPicker(); + } + } + : null, + ), + WeekdayRow( + firstDayOfWeek, + widget.customWeekDayBuilder, + showWeekdays: widget.showWeekDays, + weekdayFormat: widget.weekDayFormat, + weekdayMargin: widget.weekDayMargin, + weekdayPadding: widget.weekDayPadding, + weekdayBackgroundColor: widget.weekDayBackgroundColor, + weekdayTextStyle: widget.weekdayTextStyle, + localeDate: _localeDate, + ), + Expanded( + child: PageView.builder( + itemCount: + widget.weekFormat ? this._weeks.length : this._dates.length, + physics: widget.isScrollable + ? widget.pageScrollPhysics + : NeverScrollableScrollPhysics(), + scrollDirection: widget.scrollDirection, + onPageChanged: (index) { + this._setDate(index); + }, + controller: _controller, + itemBuilder: (context, index) { + return widget.weekFormat ? weekBuilder(index) : builder(index); + }, + pageSnapping: widget.pageSnapping, + )), + ], + ), + ); + } + + Widget getDefaultDayContainer( + bool isSelectable, + int index, + bool isSelectedDay, + bool isToday, + bool isPrevMonthDay, + TextStyle textStyle, + TextStyle defaultTextStyle, + bool isNextMonthDay, + bool isThisMonthDay, + DateTime now, + ) { + + + + return Container( + width: double.infinity, + height: double.infinity, + child: Row( + crossAxisAlignment: widget.dayCrossAxisAlignment, + mainAxisAlignment: widget.dayMainAxisAlignment, + children: [ + DefaultTextStyle( + style: getDefaultDayStyle( + isSelectable, + index, + isSelectedDay, + isToday, + isPrevMonthDay, + textStyle, + defaultTextStyle, + isNextMonthDay, + isThisMonthDay + ), + child: Text( + '${now.day}', + semanticsLabel: now.day.toString(), + style: getDayStyle( + isSelectable, + index, + isSelectedDay, + isToday, + isPrevMonthDay, + textStyle, + defaultTextStyle, + isNextMonthDay, + isThisMonthDay, + now), + maxLines: 1, + ), + ), + ], + ), + ); + } + + Widget renderDay( + bool isSelectable, + int index, + bool isSelectedDay, + bool isToday, + bool isPrevMonthDay, + TextStyle textStyle, + TextStyle defaultTextStyle, + bool isNextMonthDay, + bool isThisMonthDay, + DateTime now, + ) { + + // If day is in Multiple selection mode, get its color + bool isMultipleMarked = widget.multipleMarkedDates?.isMarked(now) ?? false; + Color multipleMarkedColor = widget.multipleMarkedDates?.getColor(now); + + + + final markedDatesMap = widget.markedDatesMap; + return Container( + margin: EdgeInsets.all(widget.dayPadding), + child: GestureDetector( + onLongPress: () => _onDayLongPressed(now), + child: FlatButton( + color: isSelectedDay && widget.selectedDayButtonColor != null + ? widget.selectedDayButtonColor + : isToday && widget.todayButtonColor != null + ? widget.todayButtonColor + + // If day is in Multiple selection mode, apply a different color + : isMultipleMarked? + multipleMarkedColor + : widget.dayButtonColor, + + onPressed: widget.disableDayPressed ? null : () => _onDayPressed(now), + padding: EdgeInsets.all(widget.dayPadding), + shape: widget.markedDateCustomShapeBorder != null && + markedDatesMap != null && + markedDatesMap.getEvents(now).length > 0 + ? widget.markedDateCustomShapeBorder + : widget.daysHaveCircularBorder == null + ? CircleBorder() + : widget.daysHaveCircularBorder ?? false + ? CircleBorder( + side: BorderSide( + color: isSelectedDay + ? widget.selectedDayBorderColor + : isToday + ? widget.todayBorderColor + : isPrevMonthDay + ? widget.prevMonthDayBorderColor + : isNextMonthDay + ? widget.nextMonthDayBorderColor + : widget.thisMonthDayBorderColor, + ), + ) + : RoundedRectangleBorder( + side: BorderSide( + color: isSelectedDay + ? widget.selectedDayBorderColor + : isToday + ? widget.todayBorderColor + : isPrevMonthDay + ? widget.prevMonthDayBorderColor + : isNextMonthDay + ? widget.nextMonthDayBorderColor + : widget.thisMonthDayBorderColor, + ), + ), + child: Stack( + children: widget.showIconBehindDayText + ? [ + widget.markedDatesMap != null + ? _renderMarkedMapContainer(now) + : Container(), + getDayContainer( + isSelectable, + index, + isSelectedDay, + isToday, + isPrevMonthDay, + textStyle, + defaultTextStyle, + isNextMonthDay, + isThisMonthDay, + now), + ] + : [ + getDayContainer( + isSelectable, + index, + isSelectedDay, + isToday, + isPrevMonthDay, + textStyle, + defaultTextStyle, + isNextMonthDay, + isThisMonthDay, + now), + widget.markedDatesMap != null + ? _renderMarkedMapContainer(now) + : Container(), + ], + ), + ), + ), + ); + } + + AnimatedBuilder builder(int slideIndex) { + _startWeekday = _dates[slideIndex].weekday - firstDayOfWeek; + if (_startWeekday == 7) { + _startWeekday = 0; + } + _endWeekday = + DateTime(_dates[slideIndex].year, _dates[slideIndex].month + 1, 1) + .weekday - + firstDayOfWeek; + double screenWidth = MediaQuery.of(context).size.width; + int totalItemCount = widget.staticSixWeekFormat + ? 42 + : DateTime( + _dates[slideIndex].year, + _dates[slideIndex].month + 1, + 0, + ).day + + _startWeekday + + (7 - _endWeekday); + int year = _dates[slideIndex].year; + int month = _dates[slideIndex].month; + + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + if (!widget.shouldShowTransform) { + return child; + } + double value = 1.0; + if (_controller.position.haveDimensions) { + value = _controller.page - slideIndex; + value = (1 - (value.abs() * .5)).clamp(0.0, 1.0); + } + + return Center( + child: SizedBox( + height: Curves.easeOut.transform(value) * widget.height, + width: Curves.easeOut.transform(value) * screenWidth, + child: child, + ), + ); + }, + child: Stack( + children: [ + Positioned( + child: Container( + width: double.infinity, + height: double.infinity, + child: GridView.count( + physics: widget.customGridViewPhysics, + crossAxisCount: 7, + childAspectRatio: widget.childAspectRatio, + padding: EdgeInsets.zero, + children: List.generate(totalItemCount, + + /// last day of month + weekday + (index) { + final selectedDateTime = widget.selectedDateTime; + bool isToday = + DateTime.now().day == index + 1 - _startWeekday && + DateTime.now().month == month && + DateTime.now().year == year; + bool isSelectedDay = selectedDateTime != null && + selectedDateTime.year == year && + selectedDateTime.month == month && + selectedDateTime.day == index + 1 - _startWeekday; + bool isPrevMonthDay = index < _startWeekday; + bool isNextMonthDay = index >= + (DateTime(year, month + 1, 0).day) + _startWeekday; + bool isThisMonthDay = !isPrevMonthDay && !isNextMonthDay; + + DateTime now = DateTime(year, month, 1); + TextStyle textStyle; + TextStyle defaultTextStyle; + if (isPrevMonthDay && !widget.showOnlyCurrentMonthDate) { + now = now.subtract(Duration(days: _startWeekday - index)); + textStyle = widget.prevDaysTextStyle; + defaultTextStyle = defaultPrevDaysTextStyle; + } else if (isThisMonthDay) { + now = DateTime(year, month, index + 1 - _startWeekday); + textStyle = isSelectedDay + ? widget.selectedDayTextStyle + : isToday + ? widget.todayTextStyle + : widget.daysTextStyle; + defaultTextStyle = isSelectedDay + ? defaultSelectedDayTextStyle + : isToday + ? defaultTodayTextStyle + : defaultDaysTextStyle; + } else if (!widget.showOnlyCurrentMonthDate) { + now = DateTime(year, month, index + 1 - _startWeekday); + textStyle = widget.nextDaysTextStyle; + defaultTextStyle = defaultNextDaysTextStyle; + } else { + return Container(); + } + final markedDatesMap = widget.markedDatesMap; + if (widget.markedDateCustomTextStyle != null && + markedDatesMap != null && + markedDatesMap.getEvents(now).length > 0) { + textStyle = widget.markedDateCustomTextStyle; + } + bool isSelectable = true; + if (now.millisecondsSinceEpoch < + minDate.millisecondsSinceEpoch) + isSelectable = false; + else if (now.millisecondsSinceEpoch > + maxDate.millisecondsSinceEpoch) isSelectable = false; + return renderDay( + isSelectable, + index, + isSelectedDay, + isToday, + isPrevMonthDay, + textStyle, + defaultTextStyle, + isNextMonthDay, + isThisMonthDay, + now); + }), + ), + ), + ), + ], + ), + ); + } + + AnimatedBuilder weekBuilder(int slideIndex) { + double screenWidth = MediaQuery.of(context).size.width; + List weekDays = _weeks[slideIndex]; + + weekDays = weekDays + .map((weekDay) => weekDay.add(Duration(days: firstDayOfWeek))) + .toList(); + + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + double value = 1.0; + if (_controller.position.haveDimensions) { + value = _controller.page - slideIndex; + value = (1 - (value.abs() * .5)).clamp(0.0, 1.0); + } + + return Center( + child: SizedBox( + height: Curves.easeOut.transform(value) * widget.height, + width: Curves.easeOut.transform(value) * screenWidth, + child: child, + ), + ); + }, + child: Stack( + children: [ + Positioned( + child: Container( + width: double.infinity, + height: double.infinity, + child: GridView.count( + physics: widget.customGridViewPhysics, + crossAxisCount: 7, + childAspectRatio: widget.childAspectRatio, + padding: EdgeInsets.zero, + children: List.generate(weekDays.length, (index) { + /// last day of month + weekday + bool isToday = weekDays[index].day == DateTime.now().day && + weekDays[index].month == DateTime.now().month && + weekDays[index].year == DateTime.now().year; + bool isSelectedDay = + this._selectedDate.year == weekDays[index].year && + this._selectedDate.month == weekDays[index].month && + this._selectedDate.day == weekDays[index].day; + bool isPrevMonthDay = + weekDays[index].month < this._targetDate.month; + bool isNextMonthDay = + weekDays[index].month > this._targetDate.month; + bool isThisMonthDay = !isPrevMonthDay && !isNextMonthDay; + + DateTime now = DateTime(weekDays[index].year, + weekDays[index].month, weekDays[index].day); + TextStyle textStyle; + TextStyle defaultTextStyle; + if (isPrevMonthDay && !widget.showOnlyCurrentMonthDate) { + textStyle = widget.prevDaysTextStyle; + defaultTextStyle = defaultPrevDaysTextStyle; + } else if (isThisMonthDay) { + textStyle = isSelectedDay + ? widget.selectedDayTextStyle + : isToday + ? widget.todayTextStyle + : widget.daysTextStyle; + defaultTextStyle = isSelectedDay + ? defaultSelectedDayTextStyle + : isToday + ? defaultTodayTextStyle + : defaultDaysTextStyle; + } else if (!widget.showOnlyCurrentMonthDate) { + textStyle = widget.nextDaysTextStyle; + defaultTextStyle = defaultNextDaysTextStyle; + } else { + return Container(); + } + bool isSelectable = true; + if (now.millisecondsSinceEpoch < + minDate.millisecondsSinceEpoch) + isSelectable = false; + else if (now.millisecondsSinceEpoch > + maxDate.millisecondsSinceEpoch) isSelectable = false; + return renderDay( + isSelectable, + index, + isSelectedDay, + isToday, + isPrevMonthDay, + textStyle, + defaultTextStyle, + isNextMonthDay, + isThisMonthDay, + now); + }), + ), + ), + ), + ], + )); + } + + List _getDaysInWeek([DateTime selectedDate]) { + if (selectedDate == null) selectedDate = new DateTime.now(); + + var firstDayOfCurrentWeek = _firstDayOfWeek(selectedDate); + var lastDayOfCurrentWeek = _lastDayOfWeek(selectedDate); + + return _daysInRange(firstDayOfCurrentWeek, lastDayOfCurrentWeek).toList(); + } + + DateTime _firstDayOfWeek(DateTime date) { + var day = _createUTCMiddayDateTime(date); + return day.subtract(new Duration(days: date.weekday % 7)); + } + + DateTime _lastDayOfWeek(DateTime date) { + var day = _createUTCMiddayDateTime(date); + return day.add(new Duration(days: 7 - day.weekday % 7)); + } + + DateTime _createUTCMiddayDateTime(DateTime date) { + // Magic const: 12 is to maintain compatibility with date_utils + return new DateTime.utc(date.year, date.month, date.day, 12, 0, 0); + } + + Iterable _daysInRange(DateTime start, DateTime end) { + var offset = start.timeZoneOffset; + + return List.generate(end.difference(start).inDays, (i) => i + 1) + .map((int i) { + var d = start.add(Duration(days: i - 1)); + + var timeZoneDiff = d.timeZoneOffset - offset; + if (timeZoneDiff.inSeconds != 0) { + offset = d.timeZoneOffset; + d = d.subtract(new Duration(seconds: timeZoneDiff.inSeconds)); + } + return d; + }); + } + + void _onDayLongPressed(DateTime picked) { + widget.onDayLongPressed?.call(picked); + } + + void _onDayPressed(DateTime picked) { + if (picked.millisecondsSinceEpoch < minDate.millisecondsSinceEpoch) return; + if (picked.millisecondsSinceEpoch > maxDate.millisecondsSinceEpoch) return; + + setState(() { + _selectedDate = picked; + }); + widget.onDayPressed + ?.call(picked, widget.markedDatesMap?.getEvents(picked) ?? const []); + } + + Future _selectDateFromPicker() async { + DateTime selected = await showDatePicker( + context: context, + initialDate: _selectedDate, + firstDate: minDate, + lastDate: maxDate, + ); + + if (selected != null) { + // updating selected date range based on selected week + setState(() { + _selectedDate = selected; + }); + widget.onDayPressed?.call( + selected, widget.markedDatesMap?.getEvents(selected) ?? const []); + } + } + + void _setDatesAndWeeks() { + /// Setup default calendar format + List date = []; + int currentDateIndex = 0; + for (int _cnt = 0; + 0 >= + DateTime(minDate.year, minDate.month + _cnt) + .difference(DateTime(maxDate.year, maxDate.month)) + .inDays; + _cnt++) { + date.add(DateTime(minDate.year, minDate.month + _cnt, 1)); + if (0 == + date.last + .difference( + DateTime(this._targetDate.year, this._targetDate.month)) + .inDays) { + currentDateIndex = _cnt; + } + } + + /// Setup week-only format + List> week = []; + for (int _cnt = 0; + 0 >= + minDate + .add(Duration(days: 7 * _cnt)) + .difference(maxDate.add(Duration(days: 7))) + .inDays; + _cnt++) { + week.add(_getDaysInWeek(minDate.add(new Duration(days: 7 * _cnt)))); + } + + _startWeekday = date[currentDateIndex].weekday - firstDayOfWeek; + /*if (widget.showOnlyCurrentMonthDate) { + _startWeekday--; + }*/ + if (/*widget.showOnlyCurrentMonthDate && */ _startWeekday == 7) { + _startWeekday = 0; + } + _endWeekday = DateTime(date[currentDateIndex].year, + date[currentDateIndex].month + 1, 1) + .weekday - + firstDayOfWeek; + this._dates = date; + this._weeks = week; +// this._selectedDate = widget.selectedDateTime != null +// ? widget.selectedDateTime +// : DateTime.now(); + } + + void _setDate([int page = -1]) { + if (page == -1) { + setState(() { + _setDatesAndWeeks(); + }); + } else { + if (widget.weekFormat) { + setState(() { + this._pageNum = page; + this._targetDate = this._weeks[page].first; + }); + + _controller.animateToPage(page, + duration: Duration(milliseconds: 1), curve: Threshold(0.0)); + } else { + setState(() { + this._pageNum = page; + this._targetDate = this._dates[page]; + _startWeekday = _dates[page].weekday - firstDayOfWeek; + _endWeekday = _lastDayOfWeek(_dates[page]).weekday - firstDayOfWeek; + }); + _controller.animateToPage(page, + duration: Duration(milliseconds: 1), curve: Threshold(0.0)); + } + + //call callback + final onCalendarChanged = widget.onCalendarChanged; + if (onCalendarChanged != null) { + WidgetsBinding.instance?.addPostFrameCallback((_) { + onCalendarChanged(!widget.weekFormat + ? this._dates[page] + : this._weeks[page][firstDayOfWeek]); + }); + } + } + } + + Widget _renderMarkedMapContainer(DateTime now) { + if (widget.markedDateShowIcon) { + return Stack( + children: _renderMarkedMap(now), + ); + } else { + return Container( + height: double.infinity, + padding: EdgeInsets.only(bottom: 4.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: _renderMarkedMap(now), + ), + ); + } + } + + List _renderMarkedMap(DateTime now) { + final markedEvents = widget.markedDatesMap?.getEvents(now) ?? []; + final markedDateIconBuilder = widget.markedDateIconBuilder; + final markedDateWidget = widget.markedDateWidget; + final markedDateMoreShowTotal = widget.markedDateMoreShowTotal; + final markedDateMoreCustomTextStyle = widget.markedDateMoreCustomTextStyle; + final markedDateIconMargin = widget.markedDateIconMargin; + final markedDateShowIcon = widget.markedDateShowIcon; + final markedDateIconMaxShown = widget.markedDateIconMaxShown; + final markedDateIconOffset = widget.markedDateIconOffset; + final markedDateMoreCustomDecoration = + widget.markedDateMoreCustomDecoration; + + if (markedEvents.length > 0) { + List tmp = []; + int count = 0; + int eventIndex = 0; + double offset = 0.0; + double padding = markedDateIconMargin; + markedEvents.forEach((T event) { + if (markedDateShowIcon) { + if (tmp.length > 0 && tmp.length < markedDateIconMaxShown) { + offset += markedDateIconOffset; + } + if (tmp.length < markedDateIconMaxShown && + markedDateIconBuilder != null) { + tmp.add(Center( + child: new Container( + padding: EdgeInsets.only( + top: padding + offset, + left: padding + offset, + right: padding - offset, + bottom: padding - offset, + ), + width: double.infinity, + height: double.infinity, + child: markedDateIconBuilder(event), + ))); + } else { + count++; + } + if (count > 0 && markedDateMoreShowTotal != null) { + tmp.add( + Positioned( + bottom: 0.0, + right: 0.0, + child: Container( + padding: EdgeInsets.all(4.0), + width: markedDateMoreShowTotal ? 18 : null, + height: markedDateMoreShowTotal ? 18 : null, + decoration: markedDateMoreCustomDecoration == null + ? new BoxDecoration( + color: Colors.red, + borderRadius: + BorderRadius.all(Radius.circular(1000.0)), + ) + : markedDateMoreCustomDecoration, + child: Center( + child: Text( + markedDateMoreShowTotal + ? (count + markedDateIconMaxShown).toString() + : (count.toString() + '+'), + semanticsLabel: markedDateMoreShowTotal + ? (count + markedDateIconMaxShown).toString() + : (count.toString() + '+'), + style: markedDateMoreCustomTextStyle == null + ? TextStyle( + fontSize: 9.0, + color: Colors.white, + fontWeight: FontWeight.normal) + : markedDateMoreCustomTextStyle, + ), + ), + ), + ), + ); + } + } else { + //max 5 dots + if (eventIndex < 5) { + Widget widget; + + if (markedDateIconBuilder != null) { + widget = markedDateIconBuilder(event); + } + + if (widget != null) { + tmp.add(widget); + } else { + final dot = event.getDot(); + if (dot != null) { + tmp.add(dot); + } else if (markedDateWidget != null) { + tmp.add(markedDateWidget); + } else { + tmp.add(defaultMarkedDateWidget); + } + } + } + } + + eventIndex++; + }); + return tmp; + } + return []; + } + + TextStyle getDefaultDayStyle( + bool isSelectable, + int index, + bool isSelectedDay, + bool isToday, + bool isPrevMonthDay, + TextStyle textStyle, + TextStyle defaultTextStyle, + bool isNextMonthDay, + bool isThisMonthDay, + ) { + return !isSelectable + ? + defaultInactiveDaysTextStyle + : (_localeDate.dateSymbols.WEEKENDRANGE + .contains((index - 1 + firstDayOfWeek) % 7)) && + !isSelectedDay && + !isToday + ? (isPrevMonthDay + ? defaultPrevDaysTextStyle + : isNextMonthDay + ? defaultNextDaysTextStyle + : isSelectable + ? defaultWeekendTextStyle + : defaultInactiveWeekendTextStyle) + : + isToday + ? defaultTodayTextStyle + : isSelectable && textStyle != null + ? textStyle + : defaultTextStyle; + } + + TextStyle getDayStyle( + bool isSelectable, + int index, + bool isSelectedDay, + bool isToday, + bool isPrevMonthDay, + TextStyle textStyle, + TextStyle defaultTextStyle, + bool isNextMonthDay, + bool isThisMonthDay, + DateTime now + ) { + + // If day is in multiple selection get its style(if available) + bool isMultipleMarked = widget.multipleMarkedDates?.isMarked(now) ?? false; + TextStyle mutipleMarkedTextStyle = widget.multipleMarkedDates?.getTextStyle(now); + + + return isSelectedDay && widget.selectedDayTextStyle != null + ? widget.selectedDayTextStyle + : isMultipleMarked? + mutipleMarkedTextStyle + : (_localeDate.dateSymbols.WEEKENDRANGE + .contains((index - 1 + firstDayOfWeek) % 7)) && + !isSelectedDay && + isThisMonthDay && + !isToday + ? (isSelectable + ? widget.weekendTextStyle + : widget.inactiveWeekendTextStyle) + : !isSelectable + ? widget.inactiveDaysTextStyle + : isPrevMonthDay + ? widget.prevDaysTextStyle + : isNextMonthDay + ? widget.nextDaysTextStyle + : isToday + ? widget.todayTextStyle + : widget.daysTextStyle; + } + + Widget getDayContainer( + bool isSelectable, + int index, + bool isSelectedDay, + bool isToday, + bool isPrevMonthDay, + TextStyle textStyle, + TextStyle defaultTextStyle, + bool isNextMonthDay, + bool isThisMonthDay, + DateTime now) { + final customDayBuilder = widget.customDayBuilder; + + + + Widget dayContainer; + if (customDayBuilder != null) { + final appTextStyle = DefaultTextStyle.of(context).style; + + final dayStyle = getDayStyle( + isSelectable, + index, + isSelectedDay, + isToday, + isPrevMonthDay, + textStyle, + defaultTextStyle, + isNextMonthDay, + isThisMonthDay, + now, + ); + + final styleForBuilder = appTextStyle.merge(dayStyle); + + dayContainer = customDayBuilder(isSelectable, index, isSelectedDay, isToday, + isPrevMonthDay, styleForBuilder, isNextMonthDay, isThisMonthDay, now); + } + + return dayContainer ?? + getDefaultDayContainer( + isSelectable, + index, + isSelectedDay, + isToday, + isPrevMonthDay, + textStyle, + defaultTextStyle, + isNextMonthDay, + isThisMonthDay, + now, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/calendar_header.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/calendar_header.dart new file mode 100644 index 00000000..b983de1e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/calendar_header.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'default_styles.dart' show defaultHeaderTextStyle; + +class CalendarHeader extends StatelessWidget { + /// Passing in values for [leftButtonIcon] or [rightButtonIcon] will override [headerIconColor] + CalendarHeader( + {@required this.headerTitle, + this.headerMargin, + @required this.showHeader, + this.headerTextStyle, + this.showHeaderButtons = true, + this.headerIconColor, + this.leftButtonIcon, + this.rightButtonIcon, + @required this.onLeftButtonPressed, + @required this.onRightButtonPressed, + this.onHeaderTitlePressed}) + : isTitleTouchable = onHeaderTitlePressed != null; + + final String headerTitle; + final EdgeInsetsGeometry headerMargin; + final bool showHeader; + final TextStyle headerTextStyle; + final bool showHeaderButtons; + final Color headerIconColor; + final Widget leftButtonIcon; + final Widget rightButtonIcon; + final VoidCallback onLeftButtonPressed; + final VoidCallback onRightButtonPressed; + final bool isTitleTouchable; + final VoidCallback onHeaderTitlePressed; + + TextStyle get getTextStyle => headerTextStyle ?? defaultHeaderTextStyle; + + Widget _leftButton() => IconButton( + onPressed: onLeftButtonPressed, + icon: + leftButtonIcon ?? Icon(Icons.chevron_left, color: headerIconColor), + ); + + Widget _rightButton() => IconButton( + onPressed: onRightButtonPressed, + icon: rightButtonIcon ?? + Icon(Icons.chevron_right, color: headerIconColor), + ); + + Widget _headerTouchable() => FlatButton( + onPressed: onHeaderTitlePressed, + child: Text( + headerTitle, + semanticsLabel: headerTitle, + style: getTextStyle, + ), + ); + + @override + Widget build(BuildContext context) => showHeader + ? Container( + margin: headerMargin, + child: DefaultTextStyle( + style: getTextStyle, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + showHeaderButtons ? _leftButton() : Container(), + isTitleTouchable + ? _headerTouchable() + : Text(headerTitle, style: getTextStyle), + showHeaderButtons ? _rightButton() : Container(), + ])), + ) + : Container(); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/default_styles.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/default_styles.dart new file mode 100644 index 00000000..cfeddc98 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/default_styles.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; + +const TextStyle defaultHeaderTextStyle = const TextStyle( + fontSize: 20.0, + color: Colors.blue, +); +const TextStyle defaultPrevDaysTextStyle = const TextStyle( + color: Colors.grey, + fontSize: 14.0, +); +const TextStyle defaultNextDaysTextStyle = const TextStyle( + color: Colors.grey, + fontSize: 14.0, +); +const TextStyle defaultDaysTextStyle = const TextStyle( + color: Colors.black, + fontSize: 14.0, +); +const TextStyle defaultTodayTextStyle = const TextStyle( + color: Colors.white, + fontSize: 14.0, +); +const TextStyle defaultSelectedDayTextStyle = const TextStyle( + color: Colors.white, + fontSize: 14.0, +); +const TextStyle defaultWeekdayTextStyle = const TextStyle( + color: Colors.deepOrange, + fontSize: 14.0, +); +const TextStyle defaultWeekendTextStyle = const TextStyle( + color: Colors.pinkAccent, + fontSize: 14.0, +); +const TextStyle defaultInactiveDaysTextStyle = const TextStyle( + color: Colors.black38, + fontSize: 14.0, +); +final TextStyle defaultInactiveWeekendTextStyle = TextStyle( + color: Colors.pinkAccent.withOpacity(0.6), + fontSize: 14.0, +); +final Widget defaultMarkedDateWidget = Container( + margin: EdgeInsets.symmetric(horizontal: 1.0), + color: Colors.blueAccent, + height: 4.0, + width: 4.0, +); diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/weekday_row.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/weekday_row.dart new file mode 100644 index 00000000..9dd43334 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/lib/src/weekday_row.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +import '../flutter_calendar_carousel.dart'; +import 'default_styles.dart'; + +class WeekdayRow extends StatelessWidget { + WeekdayRow(this.firstDayOfWeek, this.customWeekdayBuilder, + {@required this.showWeekdays, + @required this.weekdayFormat, + @required this.weekdayMargin, + @required this.weekdayPadding, + @required this.weekdayBackgroundColor, + @required this.weekdayTextStyle, + @required this.localeDate}); + + final WeekdayBuilder customWeekdayBuilder; + final bool showWeekdays; + final WeekdayFormat weekdayFormat; + final EdgeInsets weekdayMargin; + final EdgeInsets weekdayPadding; + final Color weekdayBackgroundColor; + final TextStyle weekdayTextStyle; + final DateFormat localeDate; + final int firstDayOfWeek; + + Widget _weekdayContainer(int weekday, String weekDayName) { + final customWeekdayBuilder = this.customWeekdayBuilder; + return customWeekdayBuilder != null + ? customWeekdayBuilder(weekday, weekDayName) + : Expanded( + child: Container( + decoration: BoxDecoration( + border: Border.all(color: weekdayBackgroundColor), + color: weekdayBackgroundColor, + ), + margin: weekdayMargin, + padding: weekdayPadding, + child: Center( + child: DefaultTextStyle( + style: defaultWeekdayTextStyle, + child: Text( + weekDayName, + semanticsLabel: weekDayName, + style: weekdayTextStyle, + ), + ), + ), + )); + } + +// List _generateWeekdays() { +// switch (weekdayFormat) { +// case WeekdayFormat.weekdays: +// return localeDate.dateSymbols.WEEKDAYS +// .map(_weekdayContainer) +// .toList(); +// case WeekdayFormat.standalone: +// return localeDate.dateSymbols.STANDALONEWEEKDAYS +// .map(_weekdayContainer) +// .toList(); +// case WeekdayFormat.short: +// return localeDate.dateSymbols.SHORTWEEKDAYS +// .map(_weekdayContainer) +// .toList(); +// case WeekdayFormat.standaloneShort: +// return localeDate.dateSymbols.STANDALONESHORTWEEKDAYS +// .map(_weekdayContainer) +// .toList(); +// case WeekdayFormat.narrow: +// return localeDate.dateSymbols.NARROWWEEKDAYS +// .map(_weekdayContainer) +// .toList(); +// case WeekdayFormat.standaloneNarrow: +// return localeDate.dateSymbols.STANDALONENARROWWEEKDAYS +// .map(_weekdayContainer) +// .toList(); +// default: +// return localeDate.dateSymbols.STANDALONEWEEKDAYS +// .map(_weekdayContainer) +// .toList(); +// } +// } + + // TODO - locale issues + List _renderWeekDays() { + List list = []; + + /// because of number of days in a week is 7, so it would be easier to count it til 7. + for (var i = firstDayOfWeek, count = 0; + count < 7; + i = (i + 1) % 7, count++) { + String weekDay; + + switch (weekdayFormat) { + case WeekdayFormat.weekdays: + weekDay = localeDate.dateSymbols.WEEKDAYS[i]; + break; + case WeekdayFormat.standalone: + weekDay = localeDate.dateSymbols.STANDALONEWEEKDAYS[i]; + break; + case WeekdayFormat.short: + weekDay = localeDate.dateSymbols.SHORTWEEKDAYS[i]; + break; + case WeekdayFormat.standaloneShort: + weekDay = localeDate.dateSymbols.STANDALONESHORTWEEKDAYS[i]; + break; + case WeekdayFormat.narrow: + weekDay = localeDate.dateSymbols.NARROWWEEKDAYS[i]; + break; + case WeekdayFormat.standaloneNarrow: + weekDay = localeDate.dateSymbols.STANDALONENARROWWEEKDAYS[i]; + break; + default: + weekDay = localeDate.dateSymbols.STANDALONEWEEKDAYS[i]; + break; + } + list.add(_weekdayContainer(count, weekDay)); + } + + return list; + } + + @override + Widget build(BuildContext context) => showWeekdays + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: _renderWeekDays(), + ) + : Container(); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/main.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/main.dart new file mode 100644 index 00000000..6ac4ce9e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_calendar_carousel/main.dart @@ -0,0 +1,304 @@ +import 'package:flutter/material.dart'; + +import 'package:intl/intl.dart' show DateFormat; + +import 'lib/classes/event.dart'; +import 'lib/classes/event_list.dart'; +import 'lib/flutter_calendar_carousel.dart'; + +void main() => runApp(new CalendarCarouselApp()); + +class CalendarCarouselApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'dooboolab flutter calendar', + theme: new ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or press Run > Flutter Hot Reload in IntelliJ). Notice that the + // counter didn't reset back to zero; the application is not restarted. + primarySwatch: Colors.blue, + ), + home: new MyHomePage(title: 'Flutter Calendar Carousel Example'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, @required this.title}) : super(key: key); + + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + + final String title; + + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +class _MyHomePageState extends State { + DateTime _currentDate = DateTime(2019, 2, 3); + DateTime _currentDate2 = DateTime(2019, 2, 3); + String _currentMonth = DateFormat.yMMM().format(DateTime(2019, 2, 3)); + DateTime _targetDateTime = DateTime(2019, 2, 3); +// List _markedDate = [DateTime(2018, 9, 20), DateTime(2018, 10, 11)]; + static Widget _eventIcon = new Container( + decoration: new BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(1000)), + border: Border.all(color: Colors.blue, width: 2.0)), + child: new Icon( + Icons.person, + color: Colors.amber, + ), + ); + + EventList _markedDateMap = new EventList( + events: { + new DateTime(2019, 2, 10): [ + new Event( + date: new DateTime(2019, 2, 10), + title: 'Event 1', + icon: _eventIcon, + dot: Container( + margin: EdgeInsets.symmetric(horizontal: 1.0), + color: Colors.red, + height: 5.0, + width: 5.0, + ), + ), + new Event( + date: new DateTime(2019, 2, 10), + title: 'Event 2', + icon: _eventIcon, + ), + new Event( + date: new DateTime(2019, 2, 10), + title: 'Event 3', + icon: _eventIcon, + ), + ], + }, + ); + + @override + void initState() { + /// Add more events to _markedDateMap EventList + _markedDateMap.add( + new DateTime(2019, 2, 25), + new Event( + date: new DateTime(2019, 2, 25), + title: 'Event 5', + icon: _eventIcon, + )); + + _markedDateMap.add( + new DateTime(2019, 2, 10), + new Event( + date: new DateTime(2019, 2, 10), + title: 'Event 4', + icon: _eventIcon, + )); + + _markedDateMap.addAll(new DateTime(2019, 2, 11), [ + new Event( + date: new DateTime(2019, 2, 11), + title: 'Event 1', + icon: _eventIcon, + ), + new Event( + date: new DateTime(2019, 2, 11), + title: 'Event 2', + icon: _eventIcon, + ), + new Event( + date: new DateTime(2019, 2, 11), + title: 'Event 3', + icon: _eventIcon, + ), + ]); + super.initState(); + } + + @override + Widget build(BuildContext context) { + /// Example with custom icon + final _calendarCarousel = CalendarCarousel( + onDayPressed: (date, events) { + this.setState(() => _currentDate = date); + events.forEach((event) => print(event.title)); + }, + weekendTextStyle: TextStyle( + color: Colors.red, + ), + thisMonthDayBorderColor: Colors.grey, +// weekDays: null, /// for pass null when you do not want to render weekDays + headerText: 'Custom Header', + weekFormat: true, + markedDatesMap: _markedDateMap, + height: 200.0, + selectedDateTime: _currentDate2, + showIconBehindDayText: true, +// daysHaveCircularBorder: false, /// null for not rendering any border, true for circular border, false for rectangular border + customGridViewPhysics: NeverScrollableScrollPhysics(), + markedDateShowIcon: true, + markedDateIconMaxShown: 2, + selectedDayTextStyle: TextStyle( + color: Colors.yellow, + ), + todayTextStyle: TextStyle( + color: Colors.blue, + ), + markedDateIconBuilder: (event) { + return event.icon ?? Icon(Icons.help_outline); + }, + minSelectedDate: _currentDate.subtract(Duration(days: 360)), + maxSelectedDate: _currentDate.add(Duration(days: 360)), + todayButtonColor: Colors.transparent, + todayBorderColor: Colors.green, + markedDateMoreShowTotal: + true, // null for not showing hidden events indicator +// markedDateIconMargin: 9, +// markedDateIconOffset: 3, + ); + + /// Example Calendar Carousel without header and custom prev & next button + final _calendarCarouselNoHeader = CalendarCarousel( + todayBorderColor: Colors.green, + onDayPressed: (date, events) { + this.setState(() => _currentDate2 = date); + events.forEach((event) => print(event.title)); + }, + daysHaveCircularBorder: true, + showOnlyCurrentMonthDate: false, + weekendTextStyle: TextStyle( + color: Colors.red, + ), + thisMonthDayBorderColor: Colors.grey, + weekFormat: false, +// firstDayOfWeek: 4, + markedDatesMap: _markedDateMap, + height: 420.0, + selectedDateTime: _currentDate2, + targetDateTime: _targetDateTime, + customGridViewPhysics: NeverScrollableScrollPhysics(), + markedDateCustomShapeBorder: + CircleBorder(side: BorderSide(color: Colors.yellow)), + markedDateCustomTextStyle: TextStyle( + fontSize: 18, + color: Colors.blue, + ), + showHeader: false, + todayTextStyle: TextStyle( + color: Colors.blue, + ), + // markedDateShowIcon: true, + // markedDateIconMaxShown: 2, + // markedDateIconBuilder: (event) { + // return event.icon; + // }, + // markedDateMoreShowTotal: + // true, + todayButtonColor: Colors.yellow, + selectedDayTextStyle: TextStyle( + color: Colors.yellow, + ), + minSelectedDate: _currentDate.subtract(Duration(days: 360)), + maxSelectedDate: _currentDate.add(Duration(days: 360)), + prevDaysTextStyle: TextStyle( + fontSize: 16, + color: Colors.pinkAccent, + ), + inactiveDaysTextStyle: TextStyle( + color: Colors.tealAccent, + fontSize: 16, + ), + onCalendarChanged: (DateTime date) { + this.setState(() { + _targetDateTime = date; + _currentMonth = DateFormat.yMMM().format(_targetDateTime); + }); + }, + onDayLongPressed: (DateTime date) { + print('long pressed date $date'); + }, + ); + + return new Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + ), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + //custom icon + Container( + margin: EdgeInsets.symmetric(horizontal: 16.0), + child: _calendarCarousel, + ), // This trailing comma makes auto-formatting nicer for build methods. + //custom icon without header + Container( + margin: EdgeInsets.only( + top: 30.0, + bottom: 16.0, + left: 16.0, + right: 16.0, + ), + child: new Row( + children: [ + Expanded( + child: Text( + _currentMonth, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 24.0, + ), + )), + FlatButton( + child: Text('PREV'), + onPressed: () { + setState(() { + _targetDateTime = DateTime( + _targetDateTime.year, _targetDateTime.month - 1); + _currentMonth = + DateFormat.yMMM().format(_targetDateTime); + }); + }, + ), + FlatButton( + child: Text('NEXT'), + onPressed: () { + setState(() { + _targetDateTime = DateTime( + _targetDateTime.year, _targetDateTime.month + 1); + _currentMonth = + DateFormat.yMMM().format(_targetDateTime); + }); + }, + ) + ], + ), + ), + Container( + margin: EdgeInsets.symmetric(horizontal: 16.0), + child: _calendarCarouselNoHeader, + ), // + ], + ), + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_image_sequence_animator/lib/image_sequence_animator.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_image_sequence_animator/lib/image_sequence_animator.dart new file mode 100644 index 00000000..5e128eba --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_image_sequence_animator/lib/image_sequence_animator.dart @@ -0,0 +1,463 @@ +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// © Cosmos Software | Ali Yigit Bireroglu / +// All material used in the making of this code, project, program, application, software et cetera (the "Intellectual Property") / +// belongs completely and solely to Ali Yigit Bireroglu. This includes but is not limited to the source code, the multimedia and / +// other asset files. If you were granted this Intellectual Property for personal use, you are obligated to include this copyright / +// text at all times. / +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//@formatter:off + +import 'dart:async'; + +import 'package:flutter/material.dart'; + +import 'package:cached_network_image/cached_network_image.dart'; + +typedef CacheProgressIndicatorBuilder = Widget Function(BuildContext context, double progress); +typedef ImageSequenceProcessCallback = void Function(ImageSequenceAnimatorState _imageSequenceAnimator); + +class ImageSequenceAnimator extends StatefulWidget { + ///The directory of your image sequence. + ///If [isOnline] is set to false and, for example, if you add your image sequence to + ///'assets/ImageSequences/MyImageSequence' + ///then the [folderName] should be 'assets/ImageSequences/MyImageSequence'. + ///If [isOnline] is set to true and, for example, if you add your image sequence to + ///'https://www.domain.com/ImageSequences/MyImageSequence' + ///then the [folderName] should be 'https://www.domain.com/ImageSequences/MyImageSequence'. + ///[folderName] should be the same for all the images in your image sequence. + final String folderName; + + ///The file name for each image in your image sequence excluding the suffix. For example, if the images in your image sequence are named as + ///'Frame_00000.png', 'Frame_00001.png', 'Frame_00002.png', 'Frame_00003.png' ... + ///then the [fileName] should be 'Frame_'. This should be the same for all the images in your image sequence. + final String fileName; + + ///The suffix for the first image in your image sequence. For example, if the first image in your image sequence is named as + ///'Frame_00001.png' + ///then [suffixStart] should be 1. + final int suffixStart; + + ///The suffix length for each image in your image sequence. Most software such as Adobe After Effects export image sequences with a suffix. For + ///example, if the images in your image sequence are named as + ///'Frame_00000.png', 'Frame_00001.png', 'Frame_00002.png', 'Frame_00003.png' ... + ///then the [suffixCount] should be 5. This should be the same for all the images in your image sequence. + final int suffixCount; + + ///The file format for each image in your image sequence. For example, if the images in your image sequence are named as + ///'Frame_00000.png', 'Frame_00001.png', 'Frame_00002.png', 'Frame_00003.png' ... + ///then the [fileFormat] should be 'png'. This should be the same for all the images in your image sequence. + final String fileFormat; + + ///The total number of images in your image sequence. + final double frameCount; + + ///Use this value if you would like to specify a list of endpoints for the frames in your image sequence animator. If set, values for [folderName], + ///[fileName], [suffixStart], [suffixCount], [fileFormat] and [frameCount] will be ignored. + final List fullPaths; + + ///The FPS for your image sequence. For example, if your [frameCount] is 60 and the animation is meant to run in 1 second, then your [fps] should + /// be 60. + final double fps; + + ///Use this value to determine whether your image sequence should loop or not. This will override [isBoomerang] if both are set to true. + final bool isLooping; + + ///Use this value to determine whether your image sequence should boomerang or not. + final bool isBoomerang; + + ///Use this value to determine whether your image sequence should start playing immediately or not. + final bool isAutoPlay; + + ///Use this value to determine the color for your image sequence. + final Color color; + + ///Set this value to true if your [folderName] is an online path. + final bool isOnline; + + ///Set this value to true if you want the [ImageSequenceAnimator] to wait until the entire image sequence is cached. Otherwise, the [ImageSequenceAnimator] + ///will invoke [onReadyToPlay] and start playing if [isAutoPlay] is set to true when it approximates that the remaining caching can be completed without + ///causing stutters. This value is only used if [isOnline] is set to true. + final bool waitUntilCacheIsComplete; + + ///Use this function to display a widget until the [ImageSequenceAnimator] is ready to be played. This value is only used if [isOnline] is set to true. + final CacheProgressIndicatorBuilder cacheProgressIndicatorBuilder; + + ///The callback for when the [ImageSequenceAnimator] is ready to start playing. + final ImageSequenceProcessCallback onReadyToPlay; + + ///The callback for when the [ImageSequenceAnimator] starts playing. + final ImageSequenceProcessCallback onStartPlaying; + + ///The callback for when the [ImageSequenceAnimator] is playing. This callback is continuously through the entire process. + final ImageSequenceProcessCallback onPlaying; + + ///The callback for when the [ImageSequenceAnimator] finishes playing. + final ImageSequenceProcessCallback onFinishPlaying; + + const ImageSequenceAnimator( + this.folderName, + this.fileName, + this.suffixStart, + this.suffixCount, + this.fileFormat, + this.frameCount, { + Key key, + this.fullPaths, + this.fps: 60, + this.isLooping: false, + this.isBoomerang: false, + this.isAutoPlay: true, + this.color, + this.isOnline: false, + this.waitUntilCacheIsComplete: false, + this.cacheProgressIndicatorBuilder, + this.onReadyToPlay, + this.onStartPlaying, + this.onPlaying, + this.onFinishPlaying, + }) : super(key: key); + + @override + ImageSequenceAnimatorState createState() { + return ImageSequenceAnimatorState( + folderName, + fileName, + fileFormat, + isLooping, + isBoomerang, + color, + ); + } +} + +class ImageSequenceAnimatorState extends State with SingleTickerProviderStateMixin { + AnimationController _animationController; + final ValueNotifier _changeNotifier = ValueNotifier(0); + + String _folderName; + String _fileName; + String _fileFormat; + double get _frameCount => _useFullPaths ? widget.fullPaths.length * 1.0 : widget.frameCount; + bool get _useFullPaths => widget.fullPaths != null && widget.fullPaths.isNotEmpty; + + ///Use this value to check if this [ImageSequenceAnimator] is currently looping. + bool get isLooping => _isLooping; + bool _isLooping; + + ///Use this value to check if this [ImageSequenceAnimator] is currently boomeranging. + bool get isBoomerang => _isBoomerang; + bool _isBoomerang; + + ///Use this value to check the current color of this [ImageSequenceAnimator]. + Color color; + + bool _isReadyToPlay = false; + bool _isCacheComplete = false; + bool _colorChanged = false; + + int _previousFrame = 0; + int get _newFrame => _animationController.value.floor(); + int _previousCacheFrame = 0; + int _newCacheFrame; + + Widget _currentOfflineFrame; + Widget _currentCachedOnlineFrame; + Widget _currentDisplayedOnlineFrame; + + Timer _cacheTimer; + DateTime _cacheStartDateTime; + int get _cacheMillisProgressed => DateTime.now().difference(_cacheStartDateTime).inMilliseconds; + double get _cacheMillisRemaining => _cacheMillisProgressed.toDouble() / _previousCacheFrame.toDouble() * (_frameCount - _previousCacheFrame).toDouble(); + double get _cacheMillisTotal => _cacheMillisProgressed + _cacheMillisRemaining; + + bool get isPlaying => _animationController != null && _animationController.isAnimating; + int get _fpsInMilliseconds => (1.0 / widget.fps * 1000.0).floor(); + + ///Use this value to get the current time of the animation in frames. + double get currentProgress => _animationController == null ? 0.0 : _animationController.value; + + ///Use this value to get the total time of the animation in frames. + double get totalProgress => _animationController == null ? 0.0 : _animationController.upperBound; + + ///Use this value to get the current time of the animation in milliseconds. + double get currentTime => currentProgress * _fpsInMilliseconds; + + ///Use this value to get the total time of the animation in milliseconds. + double get totalTime => totalProgress * _fpsInMilliseconds; + + ImageSequenceAnimatorState( + this._folderName, + this._fileName, + this._fileFormat, + this._isLooping, + this._isBoomerang, + this.color, + ); + + void animationListener() { + _changeNotifier.value++; + + if (widget.onPlaying != null) widget.onPlaying(this); + } + + void animationStatusListener(AnimationStatus animationStatus) { + switch (animationStatus) { + case AnimationStatus.completed: + if (widget.onFinishPlaying != null) widget.onFinishPlaying(this); + + if (isLooping) restart(); + if (isBoomerang) rewind(); + break; + case AnimationStatus.dismissed: + if (widget.onFinishPlaying != null) widget.onFinishPlaying(this); + + if (isLooping || isBoomerang) play(); + break; + default: + break; + } + } + + @override + void initState() { + super.initState(); + + _animationController = AnimationController( + vsync: this, + lowerBound: 0, + upperBound: _frameCount, + duration: Duration(milliseconds: _frameCount.ceil() * _fpsInMilliseconds), + ) + ..addListener(animationListener) + ..addStatusListener(animationStatusListener); + + if (isLooping) _isBoomerang = false; + + if (_folderName.endsWith("/")) _folderName = _folderName.substring(0, _folderName.indexOf(("/"))); + if (_fileFormat.startsWith(".")) _fileFormat = _fileFormat.substring(1); + + if (!widget.isOnline) { + _isReadyToPlay = true; + if (widget.onReadyToPlay != null) widget.onReadyToPlay(this); + if (widget.isAutoPlay) play(); + } + } + + @override + void dispose() { + _reset(); + + _animationController.removeListener(animationListener); + _animationController.removeStatusListener(animationStatusListener); + _animationController.dispose(); + + super.dispose(); + } + + ///Use this function to set the value for [ImageSequenceAnimatorState.isLooping] at runtime. + void setIsLooping(bool isLooping) { + if (!_isReadyToPlay) return; + + this._isLooping = isLooping; + if (this.isLooping) { + _isBoomerang = false; + if (!_animationController.isAnimating) restart(); + } + } + + ///Use this function to set the value for [ImageSequenceAnimatorState.isBoomerang] at runtime. + void setIsBoomerang(bool isBoomerang) { + if (!_isReadyToPlay) return; + + this._isBoomerang = isBoomerang; + if (this.isBoomerang) { + _isLooping = false; + if (!_animationController.isAnimating) restart(); + } + } + + ///Use this function to set the value for [ImageSequenceAnimatorState.color] at runtime. + void changeColor(Color color) { + if (!_isReadyToPlay) return; + + this.color = color; + _colorChanged = true; + _changeNotifier.value++; + } + + ///Use this function to play this [ImageSequenceAnimator]. + void play({double from: -1.0}) { + if (!_isReadyToPlay) return; + + if (!_animationController.isAnimating && widget.onStartPlaying != null) widget.onStartPlaying(this); + + if (from == -1.0) + _animationController.forward(); + else + _animationController.forward(from: from); + } + + ///Use this function to rewind this [ImageSequenceAnimator]. + void rewind({double from: -1.0}) { + if (!_isReadyToPlay) return; + + if (!_animationController.isAnimating && widget.onStartPlaying != null) widget.onStartPlaying(this); + + if (from == -1.0) + _animationController.reverse(); + else + _animationController.reverse(from: from); + } + + ///Use this function to pause this [ImageSequenceAnimator]. + void pause() { + if (!_isReadyToPlay) return; + + _animationController.stop(); + } + + ///Only use either value or percentage. + void skip(double value, {double percentage: -1.0}) { + if (!_isReadyToPlay) return; + + if (percentage != -1.0) + _animationController.value = totalTime * percentage; + else + _animationController.value = value; + } + + ///Use this function to restart this [ImageSequenceAnimator]. + void restart() { + if (!_isReadyToPlay) return; + + stop(); + play(); + } + + ///Use this function to stop this [ImageSequenceAnimator]. + void stop() { + if (!_isReadyToPlay) return; + + _reset(); + } + + void _reset() { + _animationController.value = 0; + _animationController.stop(canceled: true); + _previousFrame = 0; + _currentOfflineFrame = null; + } + + void _cache() { + int _value = _previousCacheFrame; + _value++; + + if (_value < _frameCount) { + _previousCacheFrame = _value; + _changeNotifier.value++; + } else + _isCacheComplete = true; + + if (!_isReadyToPlay) { + if ((widget.waitUntilCacheIsComplete && _isCacheComplete) || (!widget.waitUntilCacheIsComplete && _cacheMillisRemaining * 0.85 < totalTime)) { + _isReadyToPlay = true; + if (widget.onReadyToPlay != null) widget.onReadyToPlay(this); + if (widget.isAutoPlay) play(from: 0.0); + } + } + } + + String _getSuffix(String value) { + while (value.length < widget.suffixCount) value = "0" + value; + return value; + } + + String _getDirectory() { + if (_useFullPaths) { + return widget.fullPaths[_previousFrame]; + } + return _folderName + "/" + _fileName + _getSuffix((widget.suffixStart + _previousFrame).toString()) + "." + _fileFormat; + } + + String _getCacheDirectory() { + if (_useFullPaths) { + return widget.fullPaths[_previousCacheFrame]; + } + return _folderName + "/" + _fileName + _getSuffix((widget.suffixStart + _previousCacheFrame).toString()) + "." + _fileFormat; + } + + @override + Widget build(BuildContext context) { + if (!widget.isOnline) + return ValueListenableBuilder( + builder: (BuildContext context, int change, Widget cachedChild) { + if (_currentOfflineFrame == null || _animationController.value.floor() != _previousFrame || _colorChanged) { + _colorChanged = false; + _previousFrame = _animationController.value.floor(); + if (_previousFrame < _frameCount) + _currentOfflineFrame = Image.asset( + _getDirectory(), + color: color, + gaplessPlayback: true, + ); + } + + return _currentOfflineFrame; + }, + valueListenable: _changeNotifier, + ); + else + return ValueListenableBuilder( + builder: (BuildContext context, int change, Widget cachedChild) { + if (!_isCacheComplete) { + if (_currentCachedOnlineFrame == null || _newCacheFrame != _previousCacheFrame) { + _newCacheFrame = _previousCacheFrame; + if (_cacheStartDateTime == null) _cacheStartDateTime = DateTime.now(); + _currentCachedOnlineFrame = CachedNetworkImage( + imageUrl: _getCacheDirectory(), + progressIndicatorBuilder: (context, url, downloadProgress) { + if (downloadProgress.progress == null) { + _cacheTimer?.cancel(); + _cacheTimer = Timer(const Duration(milliseconds: 25), () => _cache()); + } else { + _cacheTimer?.cancel(); + if (downloadProgress.progress == 1.0) _cache(); + } + if (!_isReadyToPlay && widget.cacheProgressIndicatorBuilder != null) + return widget.cacheProgressIndicatorBuilder(context, 1.0 - _cacheMillisRemaining / _cacheMillisTotal); + else + return Container(); + }, + color: Colors.transparent, + ); + } + } else + _currentCachedOnlineFrame = Container(); + if (_isReadyToPlay) { + if (_currentDisplayedOnlineFrame == null || _newFrame != _previousFrame || _colorChanged) { + _colorChanged = false; + _previousFrame = _animationController.value.floor(); + if (_previousFrame < _frameCount) + _currentDisplayedOnlineFrame = CachedNetworkImage( + imageUrl: _getDirectory(), + color: color, + useOldImageOnUrlChange: _isCacheComplete, + fadeOutDuration: const Duration(milliseconds: 0), + fadeInDuration: const Duration(milliseconds: 0), + ); + } + } else + _currentDisplayedOnlineFrame = Container(); + + return Stack( + alignment: Alignment.center, + children: [ + _currentCachedOnlineFrame, + _currentDisplayedOnlineFrame, + ], + ); + }, + valueListenable: _changeNotifier, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_image_sequence_animator/main.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_image_sequence_animator/main.dart new file mode 100644 index 00000000..1cf06d49 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_image_sequence_animator/main.dart @@ -0,0 +1,329 @@ +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// © Cosmos Software | Ali Yigit Bireroglu / +// All material used in the making of this code, project, program, application, software et cetera (the "Intellectual Property") / +// belongs completely and solely to Ali Yigit Bireroglu. This includes but is not limited to the source code, the multimedia and / +// other asset files. If you were granted this Intellectual Property for personal use, you are obligated to include this copyright / +// text at all times. / +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//@formatter:off + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:spring_button/spring_button.dart'; + +import 'lib/image_sequence_animator.dart'; + + +void main() => runApp(ImageSequenceAnimatorApp()); + +class ImageSequenceAnimatorApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Image Sequence Animator Demo', + theme: ThemeData(primarySwatch: Colors.blue), + home: MyHomePage(title: 'Image Sequence Animator Demo'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + ImageSequenceAnimatorState get imageSequenceAnimator => isOnline ? onlineImageSequenceAnimator : offlineImageSequenceAnimator; + ImageSequenceAnimatorState offlineImageSequenceAnimator; + ImageSequenceAnimatorState onlineImageSequenceAnimator; + + bool isOnline = false; + bool wasPlaying = false; + + Color color1 = Colors.greenAccent; + Color color2 = Colors.indigo; + + String onlineOfflineText = "Use Online"; + String loopText = "Start Loop"; + String boomerangText = "Start Boomerang"; + + bool _useFullPaths = false; + List _fullPathsOffline; + List _fullPathsOnline; + + void onOfflineReadyToPlay(ImageSequenceAnimatorState _imageSequenceAnimator) { + offlineImageSequenceAnimator = _imageSequenceAnimator; + } + + void onOfflinePlaying(ImageSequenceAnimatorState _imageSequenceAnimator) { + setState(() {}); + } + + void onOnlineReadyToPlay(ImageSequenceAnimatorState _imageSequenceAnimator) { + onlineImageSequenceAnimator = _imageSequenceAnimator; + } + + void onOnlinePlaying(ImageSequenceAnimatorState _imageSequenceAnimator) { + setState(() {}); + } + + Widget row(String text, Color color) { + return Padding( + padding: EdgeInsets.all(3.125), + child: Container( + decoration: BoxDecoration( + color: color, + borderRadius: const BorderRadius.all(const Radius.circular(10.0)), + ), + child: Center( + child: Text( + text, + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 12.5, + ), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + if (_fullPathsOffline == null && _fullPathsOnline == null) { + _fullPathsOffline = []; + _fullPathsOnline = []; + for (int i = 0; i < 60; i++) { + String _value = i.toString(); + while (_value.length < 5) _value = "0" + _value; + _fullPathsOffline.add("assets/ImageSequence/Frame_" + _value + ".png"); + _fullPathsOnline.add("https://www.cosmossoftware.coffee/AppData/ImageSequenceAnimator/ImageSequence/Frame_" + _value + ".png"); + } + } + return Scaffold( + appBar: AppBar(title: Text(widget.title)), + body: Column( + children: [ + Expanded( + flex: 4, + child: Padding( + padding: EdgeInsets.all(25), + child: isOnline + ? ImageSequenceAnimator( + "https://www.cosmossoftware.coffee/AppData/ImageSequenceAnimator/ImageSequence", + "Frame_", + 0, + 5, + "png", + 60, + key: Key("online"), + fullPaths: _useFullPaths ? _fullPathsOffline : null, + isAutoPlay: true, + isOnline: true, +// waitUntilCacheIsComplete: true, +// cacheProgressIndicatorBuilder: (context, progress) { +// return CircularProgressIndicator( +// value: progress, +// backgroundColor: color1, +// ); +// }, + color: color1, + onReadyToPlay: onOnlineReadyToPlay, + onPlaying: onOnlinePlaying, + ) + : ImageSequenceAnimator( + "assets/ImageSequence", + "Frame_", + 0, + 5, + "png", + 60, + key: Key("offline"), + fullPaths: _useFullPaths ? _fullPathsOffline : null, + color: color1, + onReadyToPlay: onOfflineReadyToPlay, + onPlaying: onOfflinePlaying, + ), + ), + ), + Expanded( + child: Row( + children: [ + Expanded( + flex: 4, + child: CupertinoSlider( + value: imageSequenceAnimator == null ? 0.0 : imageSequenceAnimator.currentProgress, + min: 0.0, + max: imageSequenceAnimator == null ? 100.0 : imageSequenceAnimator.totalProgress, + onChangeStart: (double value) { + wasPlaying = imageSequenceAnimator.isPlaying; + imageSequenceAnimator.pause(); + }, + onChanged: (double value) { + imageSequenceAnimator.skip(value); + }, + onChangeEnd: (double value) { + if (wasPlaying) imageSequenceAnimator.play(); + }, + ), + ), + Expanded( + child: Center( + child: Text( + imageSequenceAnimator == null ? "0.0" : ((imageSequenceAnimator.currentTime.floor()).toString() + "/" + (imageSequenceAnimator.totalTime.floor()).toString()), + textAlign: TextAlign.center, + ), + ), + ), + ], + ), + ), + Expanded( + child: Row( + children: [ + Expanded( + child: SpringButton( + SpringButtonType.OnlyScale, + row( + loopText, + Colors.cyan, + ), + useCache: false, + onTap: () { + setState(() { + loopText = imageSequenceAnimator.isLooping ? "Start Loop" : "Stop Loop"; + boomerangText = "Start Boomerang"; + imageSequenceAnimator.setIsLooping(!imageSequenceAnimator.isLooping); + }); + }, + ), + ), + Expanded( + child: SpringButton( + SpringButtonType.OnlyScale, + row( + boomerangText, + Colors.deepPurpleAccent, + ), + useCache: false, + onTap: () { + setState(() { + loopText = "Start Loop"; + boomerangText = imageSequenceAnimator.isBoomerang ? "Start Boomerang" : "Stop Boomerang"; + imageSequenceAnimator.setIsBoomerang(!imageSequenceAnimator.isBoomerang); + }); + }, + ), + ), + ], + ), + ), + Expanded( + child: Row( + children: [ + Expanded( + child: SpringButton( + SpringButtonType.OnlyScale, + row( + onlineOfflineText, + Colors.orangeAccent, + ), + useCache: false, + onTap: () { + setState(() { + imageSequenceAnimator.stop(); + isOnline = !isOnline; + loopText = imageSequenceAnimator == null || imageSequenceAnimator.isLooping ? "Start Loop" : "Stop Loop"; + boomerangText = imageSequenceAnimator == null || imageSequenceAnimator.isBoomerang ? "Start Boomerang" : "Stop Boomerang"; + onlineOfflineText = isOnline ? "Use Offline" : "Use Onfline"; + }); + }, + ), + ), + Expanded( + child: SpringButton( + SpringButtonType.OnlyScale, + row( + "Change Colour", + Colors.redAccent, + ), + onTap: () { + imageSequenceAnimator.changeColor(imageSequenceAnimator.color == color1 ? color2 : color1); + }, + ), + ), + ], + ), + ), + Expanded( + child: Row( + children: [ + Expanded( + child: SpringButton( + SpringButtonType.OnlyScale, + row( + "Play/Pause", + Colors.deepOrangeAccent, + ), + onTap: () { + setState(() { + imageSequenceAnimator.isPlaying ? imageSequenceAnimator.pause() : imageSequenceAnimator.play(); + }); + }, + ), + ), + Expanded( + child: SpringButton( + SpringButtonType.OnlyScale, + row( + "Stop", + Colors.green, + ), + onTap: () { + imageSequenceAnimator.stop(); + }, + ), + ), + ], + ), + ), + Expanded( + child: Row( + children: [ + Expanded( + child: SpringButton( + SpringButtonType.OnlyScale, + row( + "Restart", + Colors.teal, + ), + onTap: () { + imageSequenceAnimator.restart(); + }, + ), + ), + Expanded( + child: SpringButton( + SpringButtonType.OnlyScale, + row( + "Rewind", + Colors.indigoAccent, + ), + onTap: () { + imageSequenceAnimator.rewind(); + }, + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/accessibility/neumorphic_accessibility.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/accessibility/neumorphic_accessibility.dart new file mode 100644 index 00000000..4a22c97c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/accessibility/neumorphic_accessibility.dart @@ -0,0 +1,630 @@ +import '../lib/color_selector.dart'; +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +class NeumorphicAccessibility extends StatefulWidget { + @override + createState() => _NeumorphicAccessibilityState(); +} + +class _NeumorphicAccessibilityState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + baseColor: Color(0xffDDDDDD), + lightSource: LightSource.topLeft, + depth: 6, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + __PageState createState() => __PageState(); +} + +class __PageState extends State<_Page> { + LightSource lightSource = LightSource.topLeft; + NeumorphicShape shape = NeumorphicShape.flat; + NeumorphicBoxShape boxShape = + NeumorphicBoxShape.roundRect(BorderRadius.circular(12)); + double depth = 5; + double intensity = 0.8; + double surfaceIntensity = 0.5; + double cornerRadius = 20; + double height = 150.0; + double width = 150.0; + + Color borderColor; + double borderWidth; + + static final minWidth = 50.0; + static final maxWidth = 200.0; + static final minHeight = 50.0; + static final maxHeight = 200.0; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + borderColor = NeumorphicTheme.currentTheme(context).borderColor; + borderWidth = NeumorphicTheme.currentTheme(context).borderWidth; + } + + @override + Widget build(BuildContext context) { + return SafeArea( + child: NeumorphicBackground( + child: Scaffold( + backgroundColor: Colors.transparent, + body: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: + const EdgeInsets.only(left: 8.0, right: 8.0, top: 8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + color: Theme.of(context).accentColor, + child: Text( + "back", + style: TextStyle(color: Colors.white), + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + Flexible( + flex: 1, + child: Stack( + fit: StackFit.expand, + children: [ + lightSourceWidgets(), + Center(child: neumorphic()), + ], + ), + ), + Flexible( + flex: 1, + child: _configurators(), + ) + ], + )), + ), + ); + } + + int selectedConfiguratorIndex = 0; + + Widget _configurators() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color textActiveColor = Colors.white; + final Color textInactiveColor = Colors.black.withOpacity(0.3); + + return Card( + margin: EdgeInsets.all(8), + elevation: 12, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + color: Colors.grey[300], + child: Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + color: selectedConfiguratorIndex == 0 + ? buttonActiveColor + : buttonInnactiveColor, + child: Text( + "Style", + style: TextStyle( + color: selectedConfiguratorIndex == 0 + ? textActiveColor + : textInactiveColor, + ), + ), + onPressed: () { + setState(() { + selectedConfiguratorIndex = 0; + }); + }, + ), + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + child: Text( + "Element", + style: TextStyle( + color: selectedConfiguratorIndex == 1 + ? textActiveColor + : textInactiveColor, + ), + ), + color: selectedConfiguratorIndex == 1 + ? buttonActiveColor + : buttonInnactiveColor, + onPressed: () { + setState(() { + selectedConfiguratorIndex = 1; + }); + }, + ), + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + child: Text( + "Border", + style: TextStyle( + color: selectedConfiguratorIndex == 2 + ? textActiveColor + : textInactiveColor, + ), + ), + color: selectedConfiguratorIndex == 2 + ? buttonActiveColor + : buttonInnactiveColor, + onPressed: () { + setState(() { + selectedConfiguratorIndex = 2; + }); + }, + ), + ), + ), + ], + ), + _configuratorsChild(), + ], + ), + ); + } + + Widget _configuratorsChild() { + switch (selectedConfiguratorIndex) { + case 0: + return styleCustomizer(); + break; + case 1: + return elementCustomizer(); + break; + case 2: + return borderCustomizer(); + break; + } + return null; + } + + Widget styleCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + depthSelector(), + intensitySelector(), + surfaceIntensitySelector(), + colorPicker(), + ], + ); + } + + Widget elementCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + cornerRadiusSelector(), + shapeWidget(), + sizeSelector(), + ], + ); + } + + Widget borderCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + borderColorPicker(), + borderWidthSelector(), + ], + ); + } + + Widget colorPicker() { + return Row( + children: [ + SizedBox( + width: 12, + ), + Text("Color "), + SizedBox( + width: 4, + ), + ColorSelector( + onColorChanged: (color) { + setState(() { + NeumorphicTheme.of(context) + .updateCurrentTheme(NeumorphicThemeData(baseColor: color)); + }); + }, + color: NeumorphicTheme.baseColor(context), + ), + ], + ); + } + + Widget borderColorPicker() { + return Row( + children: [ + SizedBox( + width: 12, + ), + Text("BorderColor "), + SizedBox( + width: 4, + ), + ColorSelector( + onColorChanged: (color) { + setState(() { + borderColor = color; + }); + }, + color: borderColor, + ), + ], + ); + } + + Widget neumorphic() { + return NeumorphicButton( + padding: EdgeInsets.zero, + duration: Duration(milliseconds: 300), + onPressed: () { + setState(() {}); + }, + style: NeumorphicStyle( + boxShape: boxShape, + border: NeumorphicBorder( + isEnabled: true, width: this.borderWidth, color: this.borderColor), + shape: this.shape, + intensity: this.intensity, + /* + shadowLightColor: Colors.red, + shadowDarkColor: Colors.blue, + shadowLightColorEmboss: Colors.red, + shadowDarkColorEmboss: Colors.blue, + */ + surfaceIntensity: this.surfaceIntensity, + depth: depth, + lightSource: this.lightSource, + ), + child: SizedBox( + height: height, + width: width, + child: Container( + //color: Colors.blue, + child: Center(child: Text("")), + ), + ), + ); + } + + Widget depthSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Depth"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_DEPTH, + max: Neumorphic.MAX_DEPTH, + value: depth, + onChanged: (value) { + setState(() { + depth = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(depth.floor().toString()), + ), + ], + ); + } + + Widget borderWidthSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("BorderWidth"), + ), + Expanded( + child: Slider( + min: 0, + max: 10, + value: borderWidth, + onChanged: (value) { + setState(() { + borderWidth = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(borderWidth.floor().toString()), + ), + ], + ); + } + + Widget sizeSelector() { + return Row( + children: [ + SizedBox( + width: 12, + ), + Text("W: "), + Expanded( + child: Slider( + min: minWidth, + max: maxWidth, + value: width, + onChanged: (value) { + setState(() { + width = value; + }); + }, + ), + ), + Text("H: "), + Expanded( + child: Slider( + min: minHeight, + max: maxHeight, + value: height, + onChanged: (value) { + setState(() { + height = value; + }); + }, + ), + ), + ], + ); + } + + Widget cornerRadiusSelector() { + if (boxShape.isRoundRect) { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Corner"), + ), + Expanded( + child: Slider( + min: 0, + max: 30, + value: cornerRadius, + onChanged: (value) { + setState(() { + cornerRadius = value; + if (boxShape.isRoundRect) { + boxShape = NeumorphicBoxShape.roundRect( + BorderRadius.circular(this.cornerRadius)); + } + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(cornerRadius.floor().toString()), + ), + ], + ); + } else { + return SizedBox(); + } + } + + Widget intensitySelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Intensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: intensity, + onChanged: (value) { + setState(() { + intensity = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((intensity * 100).floor() / 100).toString()), + ), + ], + ); + } + + Widget surfaceIntensitySelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("SurfaceIntensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: surfaceIntensity, + onChanged: (value) { + setState(() { + surfaceIntensity = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((surfaceIntensity * 100).floor() / 100).toString()), + ), + ], + ); + } + + Widget shapeWidget() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color iconActiveColor = Colors.white; + final Color iconInactiveColor = Colors.black.withOpacity(0.3); + + return Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.concave; + }); + }, + color: shape == NeumorphicShape.concave + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/concave.png", + color: shape == NeumorphicShape.concave + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.convex; + }); + }, + color: shape == NeumorphicShape.convex + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/convex.png", + color: shape == NeumorphicShape.convex + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.flat; + }); + }, + color: shape == NeumorphicShape.flat + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/flat.png", + color: shape == NeumorphicShape.flat + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + ], + ); + } + + Widget lightSourceWidgets() { + return Stack( + children: [ + Positioned( + left: 10, + right: 10, + child: Slider( + min: -1, + max: 1, + value: lightSource.dx, + onChanged: (value) { + setState(() { + lightSource = lightSource.copyWith(dx: value); + }); + }, + ), + ), + Positioned( + left: 0, + top: 10, + bottom: 10, + child: RotatedBox( + quarterTurns: 1, + child: Slider( + min: -1, + max: 1, + value: lightSource.dy, + onChanged: (value) { + setState(() { + lightSource = lightSource.copyWith(dy: value); + }); + }, + ), + ), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/generated/i18n.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/generated/i18n.dart new file mode 100644 index 00000000..79ba6663 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/generated/i18n.dart @@ -0,0 +1,130 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +// ignore_for_file: non_constant_identifier_names +// ignore_for_file: camel_case_types +// ignore_for_file: prefer_single_quotes + +// This file is automatically generated. DO NOT EDIT, all your changes would be lost. +class S implements WidgetsLocalizations { + const S(); + + static S current; + + static const GeneratedLocalizationsDelegate delegate = + GeneratedLocalizationsDelegate(); + + static S of(BuildContext context) => Localizations.of(context, S); + + @override + TextDirection get textDirection => TextDirection.ltr; +} + +class $en extends S { + const $en(); +} + +class GeneratedLocalizationsDelegate extends LocalizationsDelegate { + const GeneratedLocalizationsDelegate(); + + List get supportedLocales { + return const [ + Locale("en", ""), + ]; + } + + LocaleListResolutionCallback listResolution( + {Locale fallback, bool withCountry = true}) { + return (List locales, Iterable supported) { + if (locales == null || locales.isEmpty) { + return fallback ?? supported.first; + } else { + return _resolve(locales.first, fallback, supported, withCountry); + } + }; + } + + LocaleResolutionCallback resolution( + {Locale fallback, bool withCountry = true}) { + return (Locale locale, Iterable supported) { + return _resolve(locale, fallback, supported, withCountry); + }; + } + + @override + Future load(Locale locale) { + final String lang = getLang(locale); + if (lang != null) { + switch (lang) { + case "en": + S.current = const $en(); + return SynchronousFuture(S.current); + default: + // NO-OP. + } + } + S.current = const S(); + return SynchronousFuture(S.current); + } + + @override + bool isSupported(Locale locale) => _isSupported(locale, true); + + @override + bool shouldReload(GeneratedLocalizationsDelegate old) => false; + + /// + /// Internal method to resolve a locale from a list of locales. + /// + Locale _resolve(Locale locale, Locale fallback, Iterable supported, + bool withCountry) { + if (locale == null || !_isSupported(locale, withCountry)) { + return fallback ?? supported.first; + } + + final Locale languageLocale = Locale(locale.languageCode, ""); + if (supported.contains(locale)) { + return locale; + } else if (supported.contains(languageLocale)) { + return languageLocale; + } else { + final Locale fallbackLocale = fallback ?? supported.first; + return fallbackLocale; + } + } + + /// + /// Returns true if the specified locale is supported, false otherwise. + /// + bool _isSupported(Locale locale, bool withCountry) { + if (locale != null) { + for (Locale supportedLocale in supportedLocales) { + // Language must always match both locales. + if (supportedLocale.languageCode != locale.languageCode) { + continue; + } + + // If country code matches, return this locale. + if (supportedLocale.countryCode == locale.countryCode) { + return true; + } + + // If no country requirement is requested, check if this locale has no country. + if (true != withCountry && + (supportedLocale.countryCode == null || + supportedLocale.countryCode.isEmpty)) { + return true; + } + } + } + return false; + } +} + +String getLang(Locale l) => l == null + ? null + : l.countryCode != null && l.countryCode.isEmpty + ? l.languageCode + : l.toString(); diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/Code.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/Code.dart new file mode 100644 index 00000000..7e02ee7e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/Code.dart @@ -0,0 +1,69 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class Code extends StatelessWidget { + final String text; + + Code(this.text); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(8), + color: Colors.grey.withOpacity(0.2), + child: Text( + text, + style: TextStyle(color: Colors.black.withOpacity(0.8)), + ), + ); + } +} + +class MyIntWidget extends StatefulWidget { + final int value; + + MyIntWidget({this.value}); + + @override + _MyIntWidgetState createState() => _MyIntWidgetState(); +} + +class _MyIntWidgetState extends State + with TickerProviderStateMixin { + int _value; + AnimationController _controller; + Animation _valueAnimation; + + @override + void initState() { + this._value = widget.value; + _controller = + AnimationController(duration: Duration(milliseconds: 300), vsync: this); + super.initState(); + } + + @override + void didUpdateWidget(MyIntWidget oldWidget) { + if (oldWidget.value != widget.value) { + _controller.reset(); + _valueAnimation = + Tween(begin: _value, end: widget.value).animate(_controller) + ..addListener(() { + _value = _valueAnimation.value; + }); + _controller.forward(); + } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Text("current : $_value"); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/ThemeColorSelector.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/ThemeColorSelector.dart new file mode 100644 index 00000000..eeb69e63 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/ThemeColorSelector.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +import 'color_selector.dart'; +import 'flutter_neumorphic.dart'; + +class ThemeColorSelector extends StatefulWidget { + final BuildContext customContext; + + ThemeColorSelector({this.customContext}); + + @override + _ThemeColorSelectorState createState() => _ThemeColorSelectorState(); +} + +class _ThemeColorSelectorState extends State { + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(4), + color: Colors.black, + child: ColorSelector( + color: NeumorphicTheme.baseColor(widget.customContext ?? context), + onColorChanged: (color) { + setState(() { + NeumorphicTheme.update(widget.customContext ?? context, + (current) => current.copyWith(baseColor: color)); + }); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/ThemeConfigurator.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/ThemeConfigurator.dart new file mode 100644 index 00000000..834444b2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/ThemeConfigurator.dart @@ -0,0 +1,143 @@ +import 'package:flutter/material.dart'; + +import 'ThemeColorSelector.dart'; +import 'flutter_neumorphic.dart'; + +class ThemeConfigurator extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicButton( + padding: EdgeInsets.all(18), + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Icon( + Icons.settings, + color: NeumorphicTheme.isUsingDark(context) + ? Colors.white70 + : Colors.black87, + ), + onPressed: () { + _changeColor(context); + }, + ); + } + + void _changeColor(BuildContext context) { + showDialog( + useRootNavigator: false, + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Update Theme'), + content: SingleChildScrollView( + child: _ThemeConfiguratorDialog(contextContainingTheme: context), + ), + actions: [ + NeumorphicButton( + child: const Text('Close'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }); + } +} + +class _ThemeConfiguratorDialog extends StatefulWidget { + final BuildContext contextContainingTheme; + + _ThemeConfiguratorDialog({this.contextContainingTheme}); + + @override + _ThemeConfiguratorState createState() => _ThemeConfiguratorState(); +} + +class _ThemeConfiguratorState extends State<_ThemeConfiguratorDialog> { + @override + Widget build(BuildContext context) { + return Column( + children: [ + ThemeColorSelector( + customContext: widget.contextContainingTheme, + ), + intensitySelector(), + depthSelector(), + ], + ); + } + + Widget intensitySelector() { + final intensity = NeumorphicTheme.intensity(widget.contextContainingTheme); + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Intensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: intensity, + onChanged: (value) { + setState(() { + NeumorphicTheme.update( + widget.contextContainingTheme, + (current) => current.copyWith( + intensity: value, + ), + ); + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Container( + width: 40, + child: Text(((intensity * 100).floor() / 100).toString()), + ), + ), + ], + ); + } + + Widget depthSelector() { + final depth = NeumorphicTheme.depth(widget.contextContainingTheme); + + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Depth"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_DEPTH, + max: Neumorphic.MAX_DEPTH, + value: depth, + onChanged: (value) { + setState(() { + NeumorphicTheme.update( + widget.contextContainingTheme, + (current) => current.copyWith(depth: value), + ); + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Container( + width: 40, + child: Text(depth.floor().toString()), + ), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/back_button.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/back_button.dart new file mode 100644 index 00000000..7df28f15 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/back_button.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'flutter_neumorphic.dart'; + +class NeumorphicBack extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicButton( + padding: EdgeInsets.all(18), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.flat, + ), + child: Icon( + Icons.arrow_back, + color: NeumorphicTheme.isUsingDark(context) + ? Colors.white70 + : Colors.black87, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/color_selector.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/color_selector.dart new file mode 100644 index 00000000..c112f55d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/color_selector.dart @@ -0,0 +1,62 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +@immutable +class ColorSelector extends StatelessWidget { + final Color color; + final ValueChanged onColorChanged; + final double height; + final double width; + + const ColorSelector( + {this.height = 40, this.width = 40, this.color, this.onColorChanged}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + _changeColor(context); + }, + child: Container( + height: this.height, + width: this.width, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: this.color, + border: Border.all( + color: Colors.grey, + width: 1, + )), + ), + ); + } + + void _changeColor(BuildContext context) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Pick a color'), + content: SingleChildScrollView( + child: ColorPicker( + pickerColor: color, + onColorChanged: this.onColorChanged, + showLabel: true, + pickerAreaHeightPercent: 0.8, + ), + ), + actions: [ + FlatButton( + child: const Text('Close'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/flutter_neumorphic.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/flutter_neumorphic.dart new file mode 100644 index 00000000..a373b70e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/flutter_neumorphic.dart @@ -0,0 +1,38 @@ +library flutter_neumorphic; + +export 'package:flutter/material.dart' + show + TextTheme, + ThemeMode, + RouteFactory, + GenerateAppTitle, + InitialRouteListFactory; +export 'package:flutter/widgets.dart'; + +export 'src/colors.dart'; +export 'src/neumorphic_box_shape.dart'; +export 'src/shape.dart'; +export 'src/shape/neumorphic_path_provider.dart'; +export 'src/theme/app_bar.dart'; +export 'src/theme/neumorphic_theme.dart'; +export 'src/theme/theme.dart'; +export 'src/widget/app.dart'; +export 'src/widget/app_bar.dart'; +export 'src/widget/back_button.dart'; +export 'src/widget/background.dart'; +export 'src/widget/button.dart'; +export 'src/widget/checkbox.dart'; +export 'src/widget/close_button.dart'; +export 'src/widget/container.dart'; +export 'src/widget/icon.dart'; +export 'src/widget/indicator.dart'; +export 'src/widget/progress.dart'; +export 'src/widget/radio.dart'; +export 'src/widget/range_slider.dart'; +export 'src/widget/slider.dart'; +export 'src/widget/switch.dart'; +export 'src/widget/text.dart'; +export 'src/widget/toggle.dart'; +export 'src/widget/floating_action_button.dart'; + +export 'package:flutter/material.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/generated/i18n.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/generated/i18n.dart new file mode 100644 index 00000000..3c6f1482 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/generated/i18n.dart @@ -0,0 +1,130 @@ +// import 'dart:async'; +// +// import 'package:flutter/foundation.dart'; +// import 'package:flutter/material.dart'; +// +// // ignore_for_file: non_constant_identifier_names +// // ignore_for_file: camel_case_types +// // ignore_for_file: prefer_single_quotes +// +// // This file is automatically generated. DO NOT EDIT, all your changes would be lost. +// class S implements WidgetsLocalizations { +// const S(); +// +// static S current; +// +// static const GeneratedLocalizationsDelegate delegate = +// GeneratedLocalizationsDelegate(); +// +// static S of(BuildContext context) => Localizations.of(context, S); +// +// @override +// TextDirection get textDirection => TextDirection.ltr; +// } +// +// class $en extends S { +// const $en(); +// } +// +// class GeneratedLocalizationsDelegate extends LocalizationsDelegate { +// const GeneratedLocalizationsDelegate(); +// +// List get supportedLocales { +// return const [ +// Locale("en", ""), +// ]; +// } +// +// LocaleListResolutionCallback listResolution( +// {Locale fallback, bool withCountry = true}) { +// return (List locales, Iterable supported) { +// if (locales == null || locales.isEmpty) { +// return fallback ?? supported.first; +// } else { +// return _resolve(locales.first, fallback, supported, withCountry); +// } +// }; +// } +// +// LocaleResolutionCallback resolution( +// {Locale fallback, bool withCountry = true}) { +// return (Locale locale, Iterable supported) { +// return _resolve(locale, fallback, supported, withCountry); +// }; +// } +// +// @override +// Future load(Locale locale) { +// final String lang = getLang(locale); +// if (lang != null) { +// switch (lang) { +// case "en": +// S.current = const $en(); +// return SynchronousFuture(S.current); +// default: +// // NO-OP. +// } +// } +// S.current = const S(); +// return SynchronousFuture(S.current); +// } +// +// @override +// bool isSupported(Locale locale) => _isSupported(locale, true); +// +// @override +// bool shouldReload(GeneratedLocalizationsDelegate old) => false; +// +// /// +// /// Internal method to resolve a locale from a list of locales. +// /// +// Locale _resolve(Locale locale, Locale fallback, Iterable supported, +// bool withCountry) { +// if (locale == null || !_isSupported(locale, withCountry)) { +// return fallback ?? supported.first; +// } +// +// final Locale languageLocale = Locale(locale.languageCode, ""); +// if (supported.contains(locale)) { +// return locale; +// } else if (supported.contains(languageLocale)) { +// return languageLocale; +// } else { +// final Locale fallbackLocale = fallback ?? supported.first; +// return fallbackLocale; +// } +// } +// +// /// +// /// Returns true if the specified locale is supported, false otherwise. +// /// +// bool _isSupported(Locale locale, bool withCountry) { +// if (locale != null) { +// for (Locale supportedLocale in supportedLocales) { +// // Language must always match both locales. +// if (supportedLocale.languageCode != locale.languageCode) { +// continue; +// } +// +// // If country code matches, return this locale. +// if (supportedLocale.countryCode == locale.countryCode) { +// return true; +// } +// +// // If no country requirement is requested, check if this locale has no country. +// if (true != withCountry && +// (supportedLocale.countryCode == null || +// supportedLocale.countryCode.isEmpty)) { +// return true; +// } +// } +// } +// return false; +// } +// } +// +// String getLang(Locale l) => l == null +// ? null +// : l.countryCode != null && l.countryCode.isEmpty +// ? l.languageCode +// : l.toString(); diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/colors.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/colors.dart new file mode 100644 index 00000000..4b114a0a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/colors.dart @@ -0,0 +1,96 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/painting.dart'; + +import '../flutter_neumorphic.dart'; + +/// Defines default colors used in Neumorphic theme & shadows generators +@immutable +class NeumorphicColors { + static const background = Color(0xFFDDE6E8); + static const accent = Color(0xFF2196F3); + static const variant = Color(0xFF00BCD4); + static const disabled = Color(0xFF9E9E9E); + + static const darkBackground = Color(0xFF2D2F2F); + static const darkAccent = Color(0xFF4CAF50); + static const darkVariant = Color(0xFF607D8B); + static const darkDisabled = Color(0xB3FFFFFF); + static const darkDefaultTextColor = Color(0xB3FFFFFF); + + static const Color defaultBorder = Color(0x33000000); + static const Color darkDefaultBorder = Color(0x33FFFFFF); + + static const Color decorationMaxWhiteColor = + Color(0xFFFFFFFF); //for intensity = 1 + static const Color decorationMaxDarkColor = + Color(0x8A000000); //for intensity = 1 + + static const Color embossMaxWhiteColor = + Color(0x99FFFFFF); //for intensity = 1 + static const Color embossMaxDarkColor = Color(0x73000000); //for intensity = 1 + + static const Color _gradientShaderDarkColor = Color(0x8A000000); + static const Color _gradientShaderWhiteColor = Color(0xFFFFFFFF); + + static const Color defaultTextColor = Color(0xFF000000); + + NeumorphicColors._(); + + static Color decorationWhiteColor(Color color, {@required double intensity}) { + // intensity act on opacity; + return _applyPercentageOnOpacity( + maxColor: color, + percent: intensity, + ); + } + + static Color decorationDarkColor(Color color, {@required double intensity}) { + // intensity act on opacity; + return _applyPercentageOnOpacity( + maxColor: color, + percent: intensity, + ); + } + + static Color embossWhiteColor(Color color, {@required double intensity}) { + // intensity act on opacity; + return _applyPercentageOnOpacity( + maxColor: color, + percent: intensity, + ); + } + + static Color embossDarkColor(Color color, {@required double intensity}) { + // intensity act on opacity; + return _applyPercentageOnOpacity( + maxColor: color, + percent: intensity, + ); + } + + static Color gradientShaderDarkColor({@required double intensity}) { + // intensity act on opacity; + return _applyPercentageOnOpacity( + maxColor: NeumorphicColors._gradientShaderDarkColor, + percent: intensity); + } + + static Color gradientShaderWhiteColor({@required double intensity}) { + // intensity act on opacity; + return _applyPercentageOnOpacity( + maxColor: NeumorphicColors._gradientShaderWhiteColor, + percent: intensity); + } + + static Color _applyPercentageOnOpacity( + {@required Color maxColor, @required double percent}) { + final maxOpacity = maxColor.opacity; + final maxIntensity = Neumorphic.MAX_INTENSITY; + final newOpacity = percent * maxOpacity / maxIntensity; + final newColor = + maxColor.withOpacity(newOpacity); //<-- intensity act on opacity; + return newColor; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/abstract_neumorphic_painter_cache.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/abstract_neumorphic_painter_cache.dart new file mode 100644 index 00000000..98b6d96f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/abstract_neumorphic_painter_cache.dart @@ -0,0 +1,187 @@ +import 'dart:math'; +import 'dart:ui'; + +import '../../../flutter_neumorphic.dart'; + +abstract class AbstractNeumorphicEmbossPainterCache { + Offset _cacheOffset; + Offset get originOffset => _cacheOffset ?? Offset.zero; + + double _cacheWidth; + double get width => _cacheWidth ?? 0; + double _cacheHeight; + double get height => _cacheHeight ?? 0; + double _cacheRadius; + double get cacheRadius => _cacheRadius ?? 0; + + Rect _layerRect; + Rect get layerRect => _layerRect; + + AbstractNeumorphicEmbossPainterCache(); + + bool updateSize({@required Offset newOffset, @required Size newSize}) { + if (this._cacheOffset != newOffset || + this._cacheWidth != newSize.width || + this._cacheHeight != newSize.height) { + this._cacheWidth = newSize.width; + this._cacheHeight = newSize.height; + this._cacheOffset = newOffset; + + var middleWidth = newSize.width / 2; + var middleHeight = newSize.height / 2; + + _layerRect = this.updateLayerRect(newOffset: newOffset, newSize: newSize); + + this._cacheRadius = min(middleWidth, middleHeight); + + return true; + } + + return false; + } + + Rect updateLayerRect({@required Offset newOffset, @required Size newSize}); + + double _cacheStyleDepth; //old style depth + double _depth; //depth used to draw + double get depth => _depth ?? 0; //depth used to draw + bool updateStyleDepth(double newStyleDepth, double radiusFactor) { + if (_cacheStyleDepth != newStyleDepth) { + _cacheStyleDepth = newStyleDepth; + + final depth = + newStyleDepth.abs().clamp(0.0, _cacheRadius ?? 0 / radiusFactor); + _depth = depth; + + this._updateMaskFilter(newDepth: depth); + + return true; + } + return false; + } + + Offset _depthOffset; + Offset get depthOffset => _depthOffset ?? Offset.zero; + void updateDepthOffset() { + if (_depth != null) { + _depthOffset = this.lightSource.offset.scale(_depth, _depth); + } + } + + Color _cacheColor; + Color get backgroundColor => _cacheColor ?? Colors.transparent; + bool updateStyleColor(Color newColor) { + if (_cacheColor != newColor) { + _cacheColor = newColor; + + return true; + } + return false; + } + + bool + _cacheOppositeShadowLightSource; //store the old style lightsource property + LightSource _cacheLightSource; //store the old style lightsource + + LightSource _lightSource; //used to draw + LightSource get lightSource => + _lightSource ?? LightSource.bottom; //used to draw + bool updateLightSource( + LightSource newLightSource, bool newOppositeShadowLightSource) { + bool invalidateLightSource = false; + if (newLightSource != _cacheLightSource) { + _cacheLightSource = newLightSource; + invalidateLightSource = true; + } + + bool invalidateOppositeLightSource = false; + if (newOppositeShadowLightSource != _cacheOppositeShadowLightSource) { + _cacheOppositeShadowLightSource = newOppositeShadowLightSource; + invalidateOppositeLightSource = true; + } + + final cacheLightSource = this._cacheLightSource; + final cacheOppositeShadowLightSource = this._cacheOppositeShadowLightSource; + if (cacheOppositeShadowLightSource != null && + cacheLightSource != null && + (invalidateLightSource || invalidateOppositeLightSource)) { + if (cacheOppositeShadowLightSource) { + _lightSource = cacheLightSource.invert(); + } else { + _lightSource = cacheLightSource; + } + + return true; + } + + return false; + } + + MaskFilter _maskFilterBlur; + MaskFilter get maskFilterBlur => _maskFilterBlur; + void _updateMaskFilter({@required double newDepth}) { + this._maskFilterBlur = MaskFilter.blur(BlurStyle.normal, newDepth); + } + + double _styleIntensity; + Color _styleShadowLightColor; + Color _shadowLightColor; + Color get shadowLightColor => _shadowLightColor; + Color _styleShadowDarkColor; + Color _shadowDarkColor; + Color get shadowDarkColor => _shadowDarkColor; + + Color generateShadowLightColor( + {@required Color color, @required double intensity}); + + Color generateShadowDarkColor( + {@required Color color, @required double intensity}); + + bool updateShadowColor({ + @required Color newShadowLightColorEmboss, + @required Color newShadowDarkColorEmboss, + @required double newIntensity, + }) { + bool invalidateIntensity = false; + bool invalidate = false; + if (_styleIntensity != newIntensity) { + invalidate = true; + invalidateIntensity = true; + _styleIntensity = newIntensity; + } + //light + if (invalidateIntensity || + _styleShadowLightColor != newShadowLightColorEmboss) { + _styleShadowLightColor = newShadowLightColorEmboss; + _shadowLightColor = this.generateShadowLightColor( + color: newShadowLightColorEmboss, intensity: newIntensity); + + invalidate = true; + } + //dark + if (invalidate || _styleShadowDarkColor != newShadowDarkColorEmboss) { + _styleShadowDarkColor = newShadowDarkColorEmboss; + _shadowDarkColor = this.generateShadowDarkColor( + color: newShadowDarkColorEmboss, + intensity: newIntensity, + ); + invalidate = true; + } + return invalidate; + } + + //call after _cacheWidth & _cacheHeight set + void updateTranslations(); + + final List subPaths = []; + Path _path; + Path get path => _path ?? Path(); + void updatePath({@required Path newPath}) { + this._path = newPath; + subPaths.clear(); + var pathMetrics = newPath.computeMetrics(); + for (var item in pathMetrics) { + subPaths.add(item.extractPath(0, item.length)); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/neumorphic_emboss_painter_cache.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/neumorphic_emboss_painter_cache.dart new file mode 100644 index 00000000..10d3014a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/neumorphic_emboss_painter_cache.dart @@ -0,0 +1,66 @@ +import 'dart:ui'; + +import '../../../flutter_neumorphic.dart'; +import 'abstract_neumorphic_painter_cache.dart'; + +class NeumorphicEmbossPainterCache + extends AbstractNeumorphicEmbossPainterCache { + @override + Color generateShadowDarkColor( + {@required Color color, @required double intensity}) { + return NeumorphicColors.embossDarkColor( + color, + intensity: intensity, + ); + } + + @override + Color generateShadowLightColor( + {@required Color color, @required double intensity}) { + return NeumorphicColors.embossWhiteColor( + color, + intensity: intensity, + ); + } + + Rect updateLayerRect({@required Offset newOffset, @required Size newSize}) { + return newOffset & newSize; + } + + NeumorphicEmbossPainterCache() : super(); + + double xDepth; + double yDepth; + double xPadding; + double yPadding; + double blackShadowLeftTranslation; + double blackShadowTopTranslation; + double witheShadowLeftTranslation; + double witheShadowTopTranslation; + double scaledWidth; + double scaledHeight; + + double scaleX; + double scaleY; + + //call after _cacheWidth & _cacheHeight set + @override + void updateTranslations() { + this.xDepth = this.lightSource.dx * this.depth; + this.yDepth = this.lightSource.dy * this.depth; + this.xPadding = 2 * (1 - this.lightSource.dx.abs()) * this.depth; + this.yPadding = 2 * (1 - this.lightSource.dy.abs()) * this.depth; + + this.witheShadowLeftTranslation = xDepth - xPadding; + this.witheShadowTopTranslation = yDepth - yPadding; + + this.blackShadowLeftTranslation = -(xDepth + xPadding); + this.blackShadowTopTranslation = -(yDepth + yPadding); + + this.scaledWidth = this.width + 2 * xPadding; + this.scaledHeight = this.height + 2 * yPadding; + + this.scaleX = this.scaledWidth / this.width; + this.scaleY = this.scaledHeight / this.height; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/neumorphic_painter_cache.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/neumorphic_painter_cache.dart new file mode 100644 index 00000000..80fbe48d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/cache/neumorphic_painter_cache.dart @@ -0,0 +1,33 @@ +import 'dart:ui'; + +import '../../../flutter_neumorphic.dart'; +import 'abstract_neumorphic_painter_cache.dart'; + +class NeumorphicPainterCache extends AbstractNeumorphicEmbossPainterCache { + @override + Color generateShadowDarkColor( + {@required Color color, @required double intensity}) { + return NeumorphicColors.decorationDarkColor(color, intensity: intensity); + } + + @override + Color generateShadowLightColor( + {@required Color color, @required double intensity}) { + return NeumorphicColors.decorationWhiteColor(color, intensity: intensity); + } + + @override + void updateTranslations() { + //no-op, used only for emboss + } + + @override + Rect updateLayerRect({@required Offset newOffset, @required Size newSize}) { + return Rect.fromLTRB( + originOffset.dx - newSize.width, + originOffset.dy - newSize.height, + originOffset.dx + 2 * newSize.width, + originOffset.dy + 2 * newSize.height, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_box_decoration_helper.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_box_decoration_helper.dart new file mode 100644 index 00000000..a19ee254 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_box_decoration_helper.dart @@ -0,0 +1,28 @@ +import 'package:flutter/widgets.dart'; + +import '../theme/theme.dart'; + +Shader getGradientShader( + {@required Rect gradientRect, + @required LightSource source, + double intensity = 0.25}) { + var sourceInvert = source.invert(); + + final currentIntensity = intensity * (3 / 5); + + final Gradient gradient = LinearGradient( + begin: Alignment(source.dx, source.dy), + end: Alignment(sourceInvert.dx, sourceInvert.dy), + colors: [ + NeumorphicColors.gradientShaderDarkColor(intensity: currentIntensity), + NeumorphicColors.gradientShaderWhiteColor( + intensity: currentIntensity * (2 / 5)), + ], + stops: [ + 0, + 0.75, //was 1 but set to 0.75 to be less dark + ], + ); + + return gradient.createShader(gradientRect); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_decoration_painter.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_decoration_painter.dart new file mode 100644 index 00000000..fd03232d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_decoration_painter.dart @@ -0,0 +1,224 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/painting.dart'; + +import '../neumorphic_box_shape.dart'; +import '../theme/theme.dart'; +import 'cache/neumorphic_painter_cache.dart'; +import 'neumorphic_box_decoration_helper.dart'; +import 'neumorphic_emboss_decoration_painter.dart'; + +class NeumorphicDecorationPainter extends BoxPainter { + final NeumorphicStyle style; + final NeumorphicBoxShape shape; + + NeumorphicPainterCache _cache = NeumorphicPainterCache(); + + Paint _backgroundPaint; + Paint _whiteShadowPaint; + Paint _whiteShadowMaskPaint; + Paint _blackShadowPaint; + Paint _blackShadowMaskPaint; + Paint _gradientPaint; + Paint _borderPaint; + + void generatePainters() { + this._backgroundPaint = Paint(); + this._whiteShadowPaint = Paint(); + this._whiteShadowMaskPaint = Paint()..blendMode = BlendMode.dstOut; + this._blackShadowPaint = Paint(); + this._blackShadowMaskPaint = Paint()..blendMode = BlendMode.dstOut; + this._gradientPaint = Paint(); + + this._borderPaint = Paint() + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.bevel + ..style = PaintingStyle.stroke; + } + + final bool drawGradient; + final bool drawShadow; + final bool drawBackground; + final bool renderingByPath; + + NeumorphicDecorationPainter({ + @required this.style, + @required this.shape, + @required this.drawGradient, + @required this.drawShadow, + @required this.drawBackground, + @required VoidCallback onChanged, + this.renderingByPath = true, + }) : super(onChanged) { + generatePainters(); + } + + void _updateCache(Offset offset, ImageConfiguration configuration) { + bool invalidateSize = false; + if (configuration.size != null) { + invalidateSize = this + ._cache + .updateSize(newOffset: offset, newSize: configuration.size); + if (invalidateSize) { + _cache.updatePath( + newPath: + shape.customShapePathProvider.getPath(configuration.size)); + } + } + + bool invalidateLightSource = false; + if (style.color != null) { + invalidateLightSource = this._cache.updateLightSource( + style.lightSource, style.oppositeShadowLightSource); + } + + bool invalidateColor = false; + if (style.color != null) { + invalidateColor = this._cache.updateStyleColor(style.color); + if (invalidateColor) { + _backgroundPaint..color = _cache.backgroundColor; + } + } + + bool invalidateDepth = false; + if (style.depth != null) { + invalidateDepth = this._cache.updateStyleDepth(style.depth, 3); + if (invalidateDepth) { + _blackShadowPaint..maskFilter = _cache.maskFilterBlur; + _whiteShadowPaint..maskFilter = _cache.maskFilterBlur; + } + } + + bool invalidateShadowColors = false; + if (style.shadowLightColor != null && + style.shadowDarkColor != null && + style.intensity != null) { + invalidateShadowColors = this._cache.updateShadowColor( + newShadowLightColorEmboss: style.shadowLightColor, + newShadowDarkColorEmboss: style.shadowDarkColor, + newIntensity: style.intensity, + ); + if (invalidateShadowColors) { + if (_cache.shadowLightColor != null) { + _whiteShadowPaint..color = _cache.shadowLightColor; + } + if (_cache.shadowDarkColor != null) { + _blackShadowPaint..color = _cache.shadowDarkColor; + } + } + } + + if (invalidateDepth || invalidateLightSource) { + _cache.updateDepthOffset(); + } + + if (invalidateLightSource || invalidateDepth || invalidateSize) { + _cache.updateTranslations(); + } + } + + @override + void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { + _updateCache(offset, configuration); + + for (var subPath in _cache.subPaths) { + if (drawShadow) { + _drawShadow(offset: offset, canvas: canvas, path: subPath); + } + } + + if (renderingByPath) { + for (var subPath in _cache.subPaths) { + _drawElement(offset: offset, canvas: canvas, path: subPath); + } + } else { + _drawElement(offset: offset, canvas: canvas, path: _cache.path); + } + } + + void _drawElement( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (drawBackground) { + _drawBackground(offset: offset, canvas: canvas, path: path); + } + if (this.drawGradient) { + _drawGradient(offset: offset, canvas: canvas, path: path); + } + if (style.border.isEnabled) { + _drawBorder(canvas: canvas, offset: offset, path: path); + } + } + + void _drawBorder( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (style.border.width != null && style.border.width > 0) { + canvas + ..save() + ..translate(offset.dx, offset.dy) + ..drawPath( + path, + _borderPaint + ..color = style.border.color ?? Color(0x00000000) + ..strokeWidth = style.border.width ?? 0) + ..restore(); + } + } + + void _drawBackground( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + canvas + ..save() + ..translate(offset.dx, offset.dy) + ..drawPath(path, _backgroundPaint) + ..restore(); + } + + void _drawShadow( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (style.depth != null && style.depth.abs() >= 0.1) { + canvas + ..saveLayer(_cache.layerRect, _whiteShadowPaint) + ..translate(offset.dx + _cache.depthOffset.dx, + offset.dy + _cache.depthOffset.dy) + ..drawPath(path, _whiteShadowPaint) + ..translate(-_cache.depthOffset.dx, -_cache.depthOffset.dy) + ..drawPath(path, _whiteShadowMaskPaint) + ..restore(); + + canvas + ..saveLayer(_cache.layerRect, _blackShadowPaint) + ..translate(offset.dx - _cache.depthOffset.dx, + offset.dy - _cache.depthOffset.dy) + ..drawPath(path, _blackShadowPaint) + ..translate(_cache.depthOffset.dx, _cache.depthOffset.dy) + ..drawPath(path, _blackShadowMaskPaint) + ..restore(); + } + } + + void _drawGradient( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (style.shape == NeumorphicShape.concave || + style.shape == NeumorphicShape.convex) { + final pathRect = path.getBounds(); + + _gradientPaint + ..shader = getGradientShader( + gradientRect: pathRect, + intensity: style.surfaceIntensity, + source: style.shape == NeumorphicShape.concave + ? this.style.lightSource + : this.style.lightSource.invert(), + ); + + canvas + ..saveLayer( + pathRect.translate(offset.dx, offset.dy), + _gradientPaint, + ) + ..translate(offset.dx, offset.dy) + ..drawPath(path, _gradientPaint) + ..restore(); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_decorations.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_decorations.dart new file mode 100644 index 00000000..d364e4e2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_decorations.dart @@ -0,0 +1,136 @@ +import 'dart:ui'; + +import 'package:flutter/widgets.dart'; + +import '../neumorphic_box_shape.dart'; +import 'neumorphic_decoration_painter.dart'; +import 'neumorphic_emboss_decoration_painter.dart'; + +@immutable +class NeumorphicDecoration extends Decoration { + final NeumorphicStyle style; + final NeumorphicBoxShape shape; + final bool splitBackgroundForeground; + final bool renderingByPath; + final bool isForeground; + + NeumorphicDecoration({ + @required this.style, + @required this.isForeground, + @required this.renderingByPath, + @required this.splitBackgroundForeground, + @required this.shape, + }); + + @override + BoxPainter createBoxPainter([VoidCallback onChanged]) { + //print("createBoxPainter : ${style.depth}"); + if (style.depth != null && style.depth >= 0) { + return NeumorphicDecorationPainter( + style: style, + drawGradient: (isForeground && splitBackgroundForeground) || + (!isForeground && !splitBackgroundForeground), + drawBackground: !isForeground, + //only box draw background + drawShadow: !isForeground, + //only box draw shadow + renderingByPath: this.renderingByPath, + onChanged: onChanged ?? () {}, + shape: shape, + ); + } else { + return NeumorphicEmbossDecorationPainter( + drawBackground: !isForeground, + style: style, + drawShadow: (isForeground && splitBackgroundForeground) || + (!isForeground && !splitBackgroundForeground), + onChanged: onChanged ?? () {}, + shape: shape, + ); + } + } + + @override + NeumorphicDecoration lerpFrom(Decoration a, double t) { + if (a == null) return scale(t); + if (a is NeumorphicDecoration) + return NeumorphicDecoration.lerp(a, this, t); + return super.lerpFrom(a, t) as NeumorphicDecoration; + } + + @override + NeumorphicDecoration lerpTo(Decoration b, double t) { + if (b == null) return scale(1.0 - t); + if (b is NeumorphicDecoration) + return NeumorphicDecoration.lerp(this, b, t); + return super.lerpTo(b, t) as NeumorphicDecoration; + } + + NeumorphicDecoration scale(double factor) { + print("scale"); + return NeumorphicDecoration( + isForeground: this.isForeground, + renderingByPath: this.renderingByPath, + splitBackgroundForeground: this.splitBackgroundForeground, + shape: NeumorphicBoxShape.lerp(null, shape, factor), + style: style.copyWith()); + } + + static NeumorphicDecoration lerp( + NeumorphicDecoration a, NeumorphicDecoration b, double t) { + //print("lerp $t ${a.style.depth}, ${b.style.depth}"); + + if (a == null && b == null) return null; + if (a == null) return b.scale(t); + if (b == null) return a.scale(1.0 - t); + if (t == 0.0) { + //print("return a"); + return a; + } + if (t == 1.0) { + //print("return b (1.0)"); + return b; + } + + var aStyle = a.style; + var bStyle = b.style; + + return NeumorphicDecoration( + isForeground: a.isForeground, + shape: NeumorphicBoxShape.lerp(a.shape, b.shape, t), + splitBackgroundForeground: a.splitBackgroundForeground, + renderingByPath: a.renderingByPath, + style: a.style.copyWith( + border: NeumorphicBorder.lerp(aStyle.border, bStyle.border, t), + intensity: lerpDouble(aStyle.intensity, bStyle.intensity, t), + surfaceIntensity: + lerpDouble(aStyle.surfaceIntensity, bStyle.surfaceIntensity, t), + depth: lerpDouble(aStyle.depth, bStyle.depth, t), + color: Color.lerp(aStyle.color, bStyle.color, t), + lightSource: + LightSource.lerp(aStyle.lightSource, bStyle.lightSource, t), + )); + } + + @override + bool get isComplex => true; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicDecoration && + runtimeType == other.runtimeType && + style == other.style && + shape == other.shape && + splitBackgroundForeground == other.splitBackgroundForeground && + isForeground == other.isForeground && + renderingByPath == other.renderingByPath; + + @override + int get hashCode => + style.hashCode ^ + shape.hashCode ^ + splitBackgroundForeground.hashCode ^ + isForeground.hashCode ^ + renderingByPath.hashCode; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_emboss_decoration_painter.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_emboss_decoration_painter.dart new file mode 100644 index 00000000..1e4987fb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_emboss_decoration_painter.dart @@ -0,0 +1,176 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/painting.dart'; + +import '../neumorphic_box_shape.dart'; +import '../theme/theme.dart'; +import 'cache/neumorphic_emboss_painter_cache.dart'; + +export '../theme/theme.dart'; + +class NeumorphicEmbossDecorationPainter extends BoxPainter { + NeumorphicEmbossPainterCache _cache; + + final NeumorphicStyle style; + final NeumorphicBoxShape shape; + + Paint _backgroundPaint; + Paint _whiteShadowPaint; + Paint _whiteShadowMaskPaint; + Paint _blackShadowPaint; + Paint _blackShadowMaskPaint; + Paint _borderPaint; + + final bool drawShadow; + final bool drawBackground; + + NeumorphicEmbossDecorationPainter( + {@required this.style, + @required this.drawBackground, + @required this.drawShadow, + @required VoidCallback onChanged, + NeumorphicBoxShape shape}) + : this.shape = shape ?? NeumorphicBoxShape.rect(), + _cache = NeumorphicEmbossPainterCache(), + super(onChanged) { + _generatePainters(); + } + + void _generatePainters() { + this._backgroundPaint = Paint(); + this._whiteShadowPaint = Paint(); + this._whiteShadowMaskPaint = Paint()..blendMode = BlendMode.dstOut; + this._blackShadowPaint = Paint(); + this._blackShadowMaskPaint = Paint()..blendMode = BlendMode.dstOut; + + this._borderPaint = Paint() + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.bevel + ..style = PaintingStyle.stroke; + } + + void _updateCache( + {@required Offset offset, + @required ImageConfiguration configuration, + @required NeumorphicStyle newStyle}) { + bool invalidateSize = false; + if (configuration.size != null) { + invalidateSize = this + ._cache + .updateSize(newOffset: offset, newSize: configuration.size); + if (invalidateSize) { + _cache.updatePath( + newPath: + shape.customShapePathProvider.getPath(configuration.size)); + } + } + + bool invalidateLightSource = false; + invalidateLightSource = this + ._cache + .updateLightSource(style.lightSource, style.oppositeShadowLightSource); + + bool invalidateColor = false; + if (style.color != null) { + invalidateColor = this._cache.updateStyleColor(style.color); + if (invalidateColor) { + _backgroundPaint..color = _cache.backgroundColor; + } + } + bool invalidateDepth = false; + if (style.depth != null) { + invalidateDepth = this._cache.updateStyleDepth(style.depth, 5); + if (invalidateDepth) { + _blackShadowMaskPaint..maskFilter = _cache.maskFilterBlur; + _whiteShadowMaskPaint..maskFilter = _cache.maskFilterBlur; + } + } + + final bool invalidateShadowColors = this._cache.updateShadowColor( + newShadowLightColorEmboss: + style.shadowLightColorEmboss ?? Color(0xFFFFFFFF), + newShadowDarkColorEmboss: + style.shadowDarkColorEmboss ?? Color(0xFF000000), + newIntensity: style.intensity ?? 0.25, + ); + if (invalidateShadowColors) { + if (_cache.shadowLightColor != null) { + _whiteShadowPaint..color = _cache.shadowLightColor; + } + if (_cache.shadowDarkColor != null) { + _blackShadowPaint..color = _cache.shadowDarkColor; + } + } + + if (invalidateLightSource || invalidateDepth || invalidateSize) { + _cache.updateTranslations(); + } + } + + void _paintBackground(Canvas canvas, Path path) { + canvas + ..save() + ..translate(_cache.originOffset.dx, _cache.originOffset.dy) + ..drawPath(path, _backgroundPaint) + ..restore(); + } + + void _drawBorder( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (style.border.width != null && style.border.width > 0) { + canvas + ..save() + ..translate(offset.dx, offset.dy) + ..drawPath( + path, + _borderPaint + ..color = style.border.color ?? Color(0x00000000) + ..strokeWidth = style.border.width ?? 0) + ..restore(); + } + } + + void _paintShadows(Canvas canvas, Path path) { + final Matrix4 matrix4 = Matrix4.identity() + ..scale(_cache.scaleX, _cache.scaleY); + + canvas + ..saveLayer(_cache.layerRect, _whiteShadowPaint) + ..translate(_cache.originOffset.dx, _cache.originOffset.dy) + ..drawPath(path, _whiteShadowPaint) + ..translate( + _cache.witheShadowLeftTranslation, _cache.witheShadowTopTranslation) + ..drawPath(path.transform(matrix4.storage), _whiteShadowMaskPaint) + ..restore(); + + canvas + ..saveLayer(_cache.layerRect, _blackShadowPaint) + ..translate(_cache.originOffset.dx, _cache.originOffset.dy) + ..drawPath(path, _blackShadowPaint) + ..translate( + _cache.blackShadowLeftTranslation, _cache.blackShadowTopTranslation) + ..drawPath(path.transform(matrix4.storage), _blackShadowMaskPaint) + ..restore(); + } + + @override + void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { + _updateCache( + offset: offset, configuration: configuration, newStyle: this.style); + for (var subPath in _cache.subPaths) { + if (drawBackground) { + _paintBackground(canvas, subPath); + } + + if (style.border.isEnabled) { + _drawBorder(canvas: canvas, offset: offset, path: subPath); + } + + if (drawShadow) { + _paintShadows(canvas, subPath); + } + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_text_decoration_painter.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_text_decoration_painter.dart new file mode 100644 index 00000000..5e6de72c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_text_decoration_painter.dart @@ -0,0 +1,287 @@ +import 'dart:ui' as ui; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/painting.dart'; + +import '../theme/theme.dart'; +import 'cache/neumorphic_painter_cache.dart'; +import 'neumorphic_box_decoration_helper.dart'; +import 'neumorphic_emboss_decoration_painter.dart'; + +class NeumorphicEmptyTextPainter extends BoxPainter { + NeumorphicEmptyTextPainter({@required VoidCallback onChanged}) + : super(onChanged); + + @override + void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { + //does nothing + } +} + +class NeumorphicDecorationTextPainter extends BoxPainter { + final NeumorphicStyle style; + final String text; + final TextStyle textStyle; + final TextAlign textAlign; + + NeumorphicPainterCache _cache; + + Paint _backgroundPaint; + Paint _whiteShadowPaint; + Paint _whiteShadowMaskPaint; + Paint _blackShadowPaint; + Paint _blackShadowMaskPaint; + Paint _gradientPaint; + Paint _borderPaint; + + ui.Paragraph _textParagraph; + ui.Paragraph _innerTextParagraph; + ui.Paragraph _whiteShadowParagraph; + ui.Paragraph _whiteShadowMaskParagraph; + ui.Paragraph _blackShadowTextParagraph; + ui.Paragraph _blackShadowTextMaskParagraph; + ui.Paragraph _gradientParagraph; + + void generatePainters() { + this._backgroundPaint = Paint(); + this._whiteShadowPaint = Paint(); + this._whiteShadowMaskPaint = Paint()..blendMode = BlendMode.dstOut; + this._blackShadowPaint = Paint(); + this._blackShadowMaskPaint = Paint()..blendMode = BlendMode.dstOut; + this._gradientPaint = Paint(); + + this._borderPaint = Paint() + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.bevel + ..style = PaintingStyle.stroke + ..strokeWidth = style.border.width ?? 0.0 + ..color = style.border.color ?? Color(0xFFFFFFFF); + } + + final bool drawGradient; + final bool drawShadow; + final bool drawBackground; + final bool renderingByPath; + + NeumorphicDecorationTextPainter({ + @required this.style, + @required this.textStyle, + @required this.text, + @required this.drawGradient, + @required this.drawShadow, + @required this.drawBackground, + @required VoidCallback onChanged, + @required this.textAlign, + this.renderingByPath = true, + }) : _cache = NeumorphicPainterCache(), + super(onChanged) { + generatePainters(); + } + + void _updateCache(Offset offset, ImageConfiguration configuration) { + bool invalidateSize = false; + if (configuration.size != null) { + invalidateSize = this + ._cache + .updateSize(newOffset: offset, newSize: configuration.size); + } + + final bool invalidateLightSource = this + ._cache + .updateLightSource(style.lightSource, style.oppositeShadowLightSource); + + bool invalidateColor = false; + if (style.color != null) { + invalidateColor = this._cache.updateStyleColor(style.color); + if (invalidateColor) { + _backgroundPaint..color = _cache.backgroundColor; + } + } + + bool invalidateDepth = false; + if (style.depth != null) { + invalidateDepth = this._cache.updateStyleDepth(style.depth, 3); + if (invalidateDepth) { + _blackShadowPaint..maskFilter = _cache.maskFilterBlur; + _whiteShadowPaint..maskFilter = _cache.maskFilterBlur; + } + } + + bool invalidateShadowColors = false; + if (style.shadowLightColor != null && + style.shadowDarkColor != null && + style.intensity != null) { + invalidateShadowColors = this._cache.updateShadowColor( + newShadowLightColorEmboss: style.shadowLightColor, + newShadowDarkColorEmboss: style.shadowDarkColor, + newIntensity: style.intensity ?? neumorphicDefaultTheme.intensity, + ); + if (invalidateShadowColors) { + if (_cache.shadowLightColor != null) { + _whiteShadowPaint..color = _cache.shadowLightColor; + } + if (_cache.shadowDarkColor != null) { + _blackShadowPaint..color = _cache.shadowDarkColor; + } + } + } + + final constraints = ui.ParagraphConstraints(width: _cache.width); + final paragraphStyle = textStyle.getParagraphStyle( + textDirection: TextDirection.ltr, textAlign: this.textAlign); + + final textParagraphBuilder = ui.ParagraphBuilder(paragraphStyle) + ..pushStyle(ui.TextStyle( + foreground: _borderPaint, + )) + ..addText(text); + + final innerTextParagraphBuilder = ui.ParagraphBuilder(paragraphStyle) + ..pushStyle(ui.TextStyle( + foreground: _backgroundPaint, + )) + ..addText(text); + + final whiteShadowParagraphBuilder = ui.ParagraphBuilder(paragraphStyle) + ..pushStyle(ui.TextStyle( + foreground: _whiteShadowPaint, + )) + ..addText(text); + + final whiteShadowMaskParagraphBuilder = ui.ParagraphBuilder(paragraphStyle) + ..pushStyle(ui.TextStyle( + foreground: _whiteShadowMaskPaint, + )) + ..addText(text); + + final blackShadowParagraphBuilder = ui.ParagraphBuilder(paragraphStyle) + ..pushStyle(ui.TextStyle( + foreground: _blackShadowPaint, + )) + ..addText(text); + + final blackShadowMaskParagraphBuilder = ui.ParagraphBuilder(paragraphStyle) + ..pushStyle(ui.TextStyle( + foreground: _blackShadowMaskPaint, + )) + ..addText(text); + + _textParagraph = textParagraphBuilder.build()..layout(constraints); + _innerTextParagraph = innerTextParagraphBuilder.build() + ..layout(constraints); + + _whiteShadowParagraph = whiteShadowParagraphBuilder.build() + ..layout(constraints); + _whiteShadowMaskParagraph = whiteShadowMaskParagraphBuilder.build() + ..layout(constraints); + + _blackShadowTextParagraph = blackShadowParagraphBuilder.build() + ..layout(constraints); + _blackShadowTextMaskParagraph = blackShadowMaskParagraphBuilder.build() + ..layout(constraints); + + //region gradient + final gradientParagraphBuilder = ui.ParagraphBuilder(paragraphStyle) + ..pushStyle(ui.TextStyle( + foreground: _gradientPaint + ..shader = getGradientShader( + gradientRect: Rect.fromLTRB(0, 0, _cache.width, _cache.height), + intensity: style.surfaceIntensity, + source: style.shape == NeumorphicShape.concave + ? this.style.lightSource + : this.style.lightSource.invert(), + ), + )) + ..addText(text); + + _gradientParagraph = gradientParagraphBuilder.build() + ..layout(ui.ParagraphConstraints(width: _cache.width)); + //endregion + + if (invalidateDepth || invalidateLightSource) { + _cache.updateDepthOffset(); + } + + if (invalidateLightSource || invalidateDepth || invalidateSize) { + _cache.updateTranslations(); + } + } + + @override + void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { + _updateCache(offset, configuration); + + _drawShadow(offset: offset, canvas: canvas, path: _cache.path); + + _drawElement(offset: offset, canvas: canvas, path: _cache.path); + } + + void _drawElement( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (true) { + _drawBackground(offset: offset, canvas: canvas, path: path); + } + if (this.drawGradient) { + _drawGradient(offset: offset, canvas: canvas, path: path); + } + if (style.border.isEnabled) { + _drawBorder(canvas: canvas, offset: offset, path: path); + } + } + + void _drawBorder( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (style.border.width != null && style.border.width > 0) { + canvas + ..save() + ..translate(offset.dx, offset.dy) + ..drawParagraph(_textParagraph, Offset.zero) + ..restore(); + } + } + + void _drawBackground( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + canvas + ..save() + ..translate(offset.dx, offset.dy) + ..drawParagraph(_innerTextParagraph, Offset.zero) + ..restore(); + } + + void _drawShadow( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (style.depth != null && style.depth.abs() >= 0.1) { + canvas + ..saveLayer(_cache.layerRect, _whiteShadowPaint) + ..translate(offset.dx + _cache.depthOffset.dx, + offset.dy + _cache.depthOffset.dy) + ..drawParagraph(_whiteShadowParagraph, Offset.zero) + ..translate(-_cache.depthOffset.dx, -_cache.depthOffset.dy) + ..drawParagraph(_whiteShadowMaskParagraph, Offset.zero) + ..restore(); + + canvas + ..saveLayer(_cache.layerRect, _blackShadowPaint) + ..translate(offset.dx - _cache.depthOffset.dx, + offset.dy - _cache.depthOffset.dy) + ..drawParagraph(_blackShadowTextParagraph, Offset.zero) + ..translate(_cache.depthOffset.dx, _cache.depthOffset.dy) + ..drawParagraph(_blackShadowTextMaskParagraph, Offset.zero) + ..restore(); + } + } + + void _drawGradient( + {@required Canvas canvas, @required Offset offset, @required Path path}) { + if (style.shape == NeumorphicShape.concave || + style.shape == NeumorphicShape.convex) { + canvas + ..saveLayer(_cache.layerRect, _gradientPaint) + ..translate(offset.dx, offset.dy) + ..drawParagraph(_gradientParagraph, Offset.zero) + ..restore(); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_text_decorations.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_text_decorations.dart new file mode 100644 index 00000000..53a431f2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/decoration/neumorphic_text_decorations.dart @@ -0,0 +1,142 @@ +import 'dart:ui'; + +import 'package:flutter/widgets.dart'; + +import 'neumorphic_emboss_decoration_painter.dart'; +import 'neumorphic_text_decoration_painter.dart'; + +@immutable +class NeumorphicTextDecoration extends Decoration { + final NeumorphicStyle style; + final TextStyle textStyle; + final String text; + final bool renderingByPath; + final bool isForeground; + final TextAlign textAlign; + + NeumorphicTextDecoration({ + @required this.style, + @required this.textStyle, + @required this.isForeground, + @required this.renderingByPath, + @required this.text, + @required this.textAlign, + }); + + @override + BoxPainter createBoxPainter([VoidCallback onChanged]) { + //print("createBoxPainter : ${style.depth}"); + if (style.depth != null && style.depth >= 0) { + return NeumorphicDecorationTextPainter( + style: style, + textStyle: textStyle, + textAlign: textAlign, + drawGradient: true, + drawBackground: !isForeground, + //only box draw background + drawShadow: !isForeground, + //only box draw shadow + renderingByPath: this.renderingByPath, + onChanged: onChanged ?? () {}, + text: text, + ); + } else { + return NeumorphicEmptyTextPainter(onChanged: onChanged ?? () {}); + } + /* else { + return NeumorphicEmbossDecorationPainter( + drawBackground: !isForeground, + style: style, + drawShadow: (isForeground && splitBackgroundForeground) || + (!isForeground && !splitBackgroundForeground), + onChanged: onChanged, + shape: shape, + ); + } + */ + } + + @override + NeumorphicTextDecoration lerpFrom(Decoration a, double t) { + if (a == null) return scale(t); + if (a is NeumorphicTextDecoration) + return NeumorphicTextDecoration.lerp(a, this, t); + return super.lerpFrom(a, t) as NeumorphicTextDecoration; + } + + @override + NeumorphicTextDecoration lerpTo(Decoration b, double t) { + if (b == null) return scale(1.0 - t); + if (b is NeumorphicTextDecoration) + return NeumorphicTextDecoration.lerp(this, b, t); + return super.lerpTo(b, t) as NeumorphicTextDecoration; + } + + NeumorphicTextDecoration scale(double factor) { + print("scale"); + return NeumorphicTextDecoration( + textAlign: this.textAlign, + isForeground: this.isForeground, + renderingByPath: this.renderingByPath, + text: text, + textStyle: textStyle, + style: style.copyWith()); + } + + static NeumorphicTextDecoration lerp( + NeumorphicTextDecoration a, NeumorphicTextDecoration b, double t) { + //print("lerp $t ${a.style.depth}, ${b.style.depth}"); + + if (a == null && b == null) return null; + if (a == null) return b.scale(t); + if (b == null) return a.scale(1.0 - t); + if (t == 0.0) { + //print("return a"); + return a; + } + if (t == 1.0) { + //print("return b (1.0)"); + return b; + } + + var aStyle = a.style; + var bStyle = b.style; + + return NeumorphicTextDecoration( + isForeground: a.isForeground, + text: a.text, + textAlign: a.textAlign, + textStyle: TextStyle.lerp(a.textStyle, b.textStyle, t) ?? TextStyle(), + renderingByPath: a.renderingByPath, + style: a.style.copyWith( + border: NeumorphicBorder.lerp(aStyle.border, bStyle.border, t), + intensity: lerpDouble(aStyle.intensity, bStyle.intensity, t), + depth: lerpDouble(aStyle.depth, bStyle.depth, t), + color: Color.lerp(aStyle.color, bStyle.color, t), + lightSource: + LightSource.lerp(aStyle.lightSource, bStyle.lightSource, t), + )); + } + + @override + bool get isComplex => true; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicTextDecoration && + runtimeType == other.runtimeType && + style == other.style && + text == other.text && + textStyle == other.textStyle && + isForeground == other.isForeground && + renderingByPath == other.renderingByPath; + + @override + int get hashCode => + style.hashCode ^ + text.hashCode ^ + textStyle.hashCode ^ + isForeground.hashCode ^ + renderingByPath.hashCode; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/light_source.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/light_source.dart new file mode 100644 index 00000000..cafc93ba --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/light_source.dart @@ -0,0 +1,73 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; + +/// A custom offset that define a source of light used to project a shadow of a widget +/// left -1 <= dx <= 1 right +/// top -1 <= dy <= 1 bottom +/// +/// constants like "top", "topLeft", "topRight" are providen in LightSource +/// +@immutable +class LightSource { + final double dx; + final double dy; + + const LightSource(this.dx, this.dy); + + Offset get offset => Offset(dx, dy); + + static const top = const LightSource(0, -1); + static const topLeft = const LightSource(-1, -1); + static const topRight = const LightSource(1, -1); + static const bottom = const LightSource(0, 1); + static const bottomLeft = const LightSource(-1, 1); + static const bottomRight = const LightSource(1, 1); + static const left = const LightSource(-1, 0); + static const right = const LightSource(1, 0); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LightSource && + runtimeType == other.runtimeType && + offset == other.offset; + + @override + int get hashCode => offset.hashCode; + + Offset toOffset(double distance) { + return offset.scale(distance, distance); + } + + @override + String toString() { + return 'LightSource{dx: $dx, dy: $dy}'; + } + + LightSource invert() => LightSource(dx * -1, dy * -1); + + static LightSource lerp(LightSource a, LightSource b, double t) { + if (a == null && b == null) return null; + if (a == null) return b; + if (b == null) return a; + if (a == b) return a; + if (t == 0.0) return a; + if (t == 1.0) return b; + + return LightSource( + (a.dx != b.dx ? lerpDouble(a.dx, b.dx, t) : a.dx), + (a.dy != b.dy ? lerpDouble(a.dy, b.dy, t) : a.dy), + ); + } + + LightSource copyWith({ + double dx, + double dy, + }) { + return LightSource( + dx ?? this.dx, + dy ?? this.dy, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/neumorphic_box_shape.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/neumorphic_box_shape.dart new file mode 100644 index 00000000..47d7defb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/neumorphic_box_shape.dart @@ -0,0 +1,102 @@ +import 'package:flutter/widgets.dart'; + +import 'shape/beveled_path_provider.dart'; +import 'shape/circle_path_provider.dart'; +import 'shape/neumorphic_path_provider.dart'; +import 'shape/rect_path_provider.dart'; +import 'shape/rrect_path_provider.dart'; +import 'shape/stadium_path_provider.dart'; + +export 'shape/path/flutter_logo_path_provider.dart'; + +/// Define a Neumorphic container box shape + +class NeumorphicBoxShape { + final NeumorphicPathProvider customShapePathProvider; + + const NeumorphicBoxShape._(this.customShapePathProvider); + + const NeumorphicBoxShape.circle() : this._(const CirclePathProvider()); + + const NeumorphicBoxShape.path(NeumorphicPathProvider pathProvider) + : this._(pathProvider); + + const NeumorphicBoxShape.rect() : this._(const RectPathProvider()); + + const NeumorphicBoxShape.stadium() : this._(const StadiumPathProvider()); + + NeumorphicBoxShape.roundRect(BorderRadius borderRadius) + : this._(RRectPathProvider(borderRadius)); + + NeumorphicBoxShape.beveled(BorderRadius borderRadius) + : this._(BeveledPathProvider(borderRadius)); + + bool get isCustomPath => + !isStadium && !isRect && !isCircle && !isRoundRect && !isBeveled; + + bool get isStadium => + customShapePathProvider.runtimeType == StadiumPathProvider; + + bool get isCircle => + customShapePathProvider.runtimeType == CirclePathProvider; + + bool get isRect => customShapePathProvider.runtimeType == RectPathProvider; + + bool get isRoundRect => + customShapePathProvider.runtimeType == RRectPathProvider; + + bool get isBeveled => + customShapePathProvider.runtimeType == BeveledPathProvider; + + static NeumorphicBoxShape lerp( + NeumorphicBoxShape a, NeumorphicBoxShape b, double t) { + if (a == null && b == null) return null; + + if (t == 0.0) return a; + if (t == 1.0) return b; + + if (a == null) { + if (b.isCircle || b.isRect || b.isStadium || b.isCustomPath) { + return b; + } else { + return NeumorphicBoxShape.roundRect(BorderRadius.lerp( + null, + (b.customShapePathProvider as RRectPathProvider).borderRadius, + t, + )); + } + } + if (a.isCircle || a.isRect || a.isStadium || a.isCustomPath) { + return a; + } + + if (b == null) { + if (a.isCircle || a.isRect || a.isStadium || a.isCustomPath) { + return a; + } else { + return NeumorphicBoxShape.roundRect(BorderRadius.lerp( + null, + (a.customShapePathProvider as RRectPathProvider).borderRadius, + t, + )); + } + } + if (b.isCircle || b.isRect || b.isStadium || b.isCustomPath) { + return b; + } + + if (a.isBeveled && b.isBeveled) { + return NeumorphicBoxShape.beveled(BorderRadius.lerp( + (a.customShapePathProvider as BeveledPathProvider).borderRadius, + (b.customShapePathProvider as BeveledPathProvider).borderRadius, + t, + )); + } + + return NeumorphicBoxShape.roundRect(BorderRadius.lerp( + (a.customShapePathProvider as RRectPathProvider).borderRadius, + (b.customShapePathProvider as RRectPathProvider).borderRadius, + t, + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/neumorphic_icons.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/neumorphic_icons.dart new file mode 100755 index 00000000..5705e0a2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/neumorphic_icons.dart @@ -0,0 +1,30 @@ +/// Flutter icons NeumorphicIcons +/// Copyright (C) 2020 by original authors @ fluttericon.com, fontello.com +/// This font was generated by FlutterIcon.com, which is derived from Fontello. +/// +/// To use this font, place it in your fonts/ directory and include the +/// following in your pubspec.yaml +/// +/// flutter: +/// fonts: +/// - family: NeumorphicIcons +/// fonts: +/// - asset: fonts/NeumorphicIcons.ttf +/// +/// +/// * Material Design Icons, Copyright (C) Google, Inc +/// Author: Google +/// License: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) +/// Homepage: https://design.google.com/icons/ +/// +import 'package:flutter/widgets.dart'; + +class NeumorphicIcons { + NeumorphicIcons._(); + + static const _kFontFam = 'NeumorphicIcons'; + static const _kFontPkg = "flutter_neumorphic"; + + static const IconData check = + IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape.dart new file mode 100644 index 00000000..8f636e95 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape.dart @@ -0,0 +1,9 @@ +/// Define the neumorphic curve of the top of the widget +/// +/// @see https://github.com/Idean/Flutter-Neumorphic/#-shapes +/// +enum NeumorphicShape { + concave, + convex, + flat, +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/beveled_path_provider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/beveled_path_provider.dart new file mode 100644 index 00000000..1390874e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/beveled_path_provider.dart @@ -0,0 +1,57 @@ +import '../../flutter_neumorphic.dart'; +import 'neumorphic_path_provider.dart'; +import 'dart:math' as math; + +class BeveledPathProvider extends NeumorphicPathProvider { + final BorderRadius borderRadius; + + const BeveledPathProvider(this.borderRadius, {Listenable reclip}); + + @override + bool shouldReclip(NeumorphicPathProvider oldClipper) { + return true; + } + + @override + Path getPath(Size size) { + final rrect = RRect.fromLTRBAndCorners(0, 0, size.width, size.height, + topLeft: borderRadius.topLeft, + topRight: borderRadius.topRight, + bottomLeft: borderRadius.bottomLeft, + bottomRight: borderRadius.bottomRight); + return _getPath(rrect); + } + + //from material + Path _getPath(RRect rrect) { + final Offset centerLeft = Offset(rrect.left, rrect.center.dy); + final Offset centerRight = Offset(rrect.right, rrect.center.dy); + final Offset centerTop = Offset(rrect.center.dx, rrect.top); + final Offset centerBottom = Offset(rrect.center.dx, rrect.bottom); + + final double tlRadiusX = math.max(0.0, rrect.tlRadiusX); + final double tlRadiusY = math.max(0.0, rrect.tlRadiusY); + final double trRadiusX = math.max(0.0, rrect.trRadiusX); + final double trRadiusY = math.max(0.0, rrect.trRadiusY); + final double blRadiusX = math.max(0.0, rrect.blRadiusX); + final double blRadiusY = math.max(0.0, rrect.blRadiusY); + final double brRadiusX = math.max(0.0, rrect.brRadiusX); + final double brRadiusY = math.max(0.0, rrect.brRadiusY); + + final List vertices = [ + Offset(rrect.left, math.min(centerLeft.dy, rrect.top + tlRadiusY)), + Offset(math.min(centerTop.dx, rrect.left + tlRadiusX), rrect.top), + Offset(math.max(centerTop.dx, rrect.right - trRadiusX), rrect.top), + Offset(rrect.right, math.min(centerRight.dy, rrect.top + trRadiusY)), + Offset(rrect.right, math.max(centerRight.dy, rrect.bottom - brRadiusY)), + Offset(math.max(centerBottom.dx, rrect.right - brRadiusX), rrect.bottom), + Offset(math.min(centerBottom.dx, rrect.left + blRadiusX), rrect.bottom), + Offset(rrect.left, math.max(centerLeft.dy, rrect.bottom - blRadiusY)), + ]; + + return Path()..addPolygon(vertices, true); + } + + @override + bool get oneGradientPerPath => false; //because only 1 path +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/circle_path_provider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/circle_path_provider.dart new file mode 100644 index 00000000..0d009097 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/circle_path_provider.dart @@ -0,0 +1,27 @@ +import 'dart:math'; + +import '../../flutter_neumorphic.dart'; +import 'neumorphic_path_provider.dart'; + +class CirclePathProvider extends NeumorphicPathProvider { + const CirclePathProvider({Listenable reclip}); + + @override + bool shouldReclip(NeumorphicPathProvider oldClipper) { + return true; + } + + @override + Path getPath(Size size) { + final middleHeight = size.height / 2; + final middleWidth = size.width / 2; + return Path() + ..addOval(Rect.fromCircle( + center: Offset(middleWidth, middleHeight), + radius: min(middleHeight, middleWidth))) + ..close(); + } + + @override + bool get oneGradientPerPath => false; //because only 1 path +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/neumorphic_path_provider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/neumorphic_path_provider.dart new file mode 100644 index 00000000..1b2f2739 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/neumorphic_path_provider.dart @@ -0,0 +1,23 @@ +import '../../flutter_neumorphic.dart'; + +abstract class NeumorphicPathProvider extends CustomClipper { + const NeumorphicPathProvider({Listenable reclip}) : super(reclip: reclip); + + @override + Path getClip(Size size) { + return getPath(size); + } + + /// only used when shape == convex || concave + /// when you have multiple path (with some moveTo) inside : + /// true -> draw a different gradient for each sub path + /// false -> draw an unique gradient for all the widget + bool get oneGradientPerPath; + + Path getPath(Size size); + + @override + bool shouldReclip(NeumorphicPathProvider oldClipper) { + return false; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/path/flutter_logo_path_provider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/path/flutter_logo_path_provider.dart new file mode 100644 index 00000000..f3a7f680 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/path/flutter_logo_path_provider.dart @@ -0,0 +1,30 @@ +import '../../../flutter_neumorphic.dart'; + +class NeumorphicFlutterLogoPathProvider extends NeumorphicPathProvider { + @override + bool shouldReclip(NeumorphicPathProvider oldClipper) { + return true; + } + + @override + Path getPath(Size size) { + var scaleX = size.width / 166; + var scaleY = size.height / 202; + + return Path() + ..moveTo(37.7 * scaleX, 128.9 * scaleY) + ..lineTo(9.8 * scaleX, 101.0 * scaleY) + ..lineTo(100.4 * scaleX, 10.4 * scaleY) + ..lineTo(156.2 * scaleX, 10.4 * scaleY) + ..moveTo(156.2 * scaleX, 94.0 * scaleY) + ..lineTo(100.4 * scaleX, 94.0 * scaleY) + ..lineTo(51.6 * scaleX, 142.8 * scaleY) + ..lineTo(100.4 * scaleX, 191.6 * scaleY) + ..lineTo(156.2 * scaleX, 191.6 * scaleY) + ..lineTo(107.4 * scaleX, 142.8 * scaleY) + ..close(); + } + + @override + bool get oneGradientPerPath => true; //one shape(convex/concave) / subPath +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/rect_path_provider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/rect_path_provider.dart new file mode 100644 index 00000000..45329a58 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/rect_path_provider.dart @@ -0,0 +1,21 @@ +import '../../flutter_neumorphic.dart'; +import 'neumorphic_path_provider.dart'; + +class RectPathProvider extends NeumorphicPathProvider { + const RectPathProvider({Listenable reclip}); + + @override + bool shouldReclip(NeumorphicPathProvider oldClipper) { + return true; + } + + @override + Path getPath(Size size) { + return Path() + ..addRect(Rect.fromLTWH(0, 0, size.width, size.height)) + ..close(); + } + + @override + bool get oneGradientPerPath => false; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/rrect_path_provider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/rrect_path_provider.dart new file mode 100644 index 00000000..b6563863 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/rrect_path_provider.dart @@ -0,0 +1,27 @@ +import '../../flutter_neumorphic.dart'; +import 'neumorphic_path_provider.dart'; + +class RRectPathProvider extends NeumorphicPathProvider { + final BorderRadius borderRadius; + + const RRectPathProvider(this.borderRadius, {Listenable reclip}); + + @override + bool shouldReclip(NeumorphicPathProvider oldClipper) { + return true; + } + + @override + Path getPath(Size size) { + return Path() + ..addRRect(RRect.fromLTRBAndCorners(0, 0, size.width, size.height, + topLeft: borderRadius.topLeft, + topRight: borderRadius.topRight, + bottomLeft: borderRadius.bottomLeft, + bottomRight: borderRadius.bottomRight)) + ..close(); + } + + @override + bool get oneGradientPerPath => false; //because only 1 path +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/stadium_path_provider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/stadium_path_provider.dart new file mode 100644 index 00000000..984c5e93 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/shape/stadium_path_provider.dart @@ -0,0 +1,11 @@ +import '../../flutter_neumorphic.dart'; +import 'rrect_path_provider.dart'; + +class StadiumPathProvider extends RRectPathProvider { + const StadiumPathProvider({Listenable reclip}) + : super( + const BorderRadius.all( + const Radius.circular(1000), + ), + reclip: reclip); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/app_bar.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/app_bar.dart new file mode 100644 index 00000000..ffe2aaef --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/app_bar.dart @@ -0,0 +1,90 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; + + +@immutable +class NeumorphicAppBarThemeData { + final Color color; + final IconThemeData iconTheme; + final NeumorphicStyle buttonStyle; + final EdgeInsets buttonPadding; + final bool centerTitle; + final TextStyle textStyle; + final NeumorphicAppBarIcons icons; + + const NeumorphicAppBarThemeData({ + this.color = Colors.transparent, + this.iconTheme, + this.textStyle, + this.buttonStyle = const NeumorphicStyle(), + this.centerTitle, + this.buttonPadding = const EdgeInsets.all(0), + this.icons = const NeumorphicAppBarIcons(), + }); +} + +class NeumorphicAppBarIcons { + final Icon closeIcon; + final Icon menuIcon; + final Icon _backIcon; + final Icon _forwardIcon; + + const NeumorphicAppBarIcons({ + this.menuIcon = const Icon(Icons.menu), + this.closeIcon = const Icon(Icons.close), + Icon backIcon, + Icon forwardIcon, + }) : _backIcon = backIcon, + _forwardIcon = forwardIcon; + + //if back icon null then get platform oriented icon + Icon get backIcon => _backIcon ?? _getBackIcon; + Icon get _getBackIcon => Platform.isIOS || Platform.isMacOS + ? const Icon(Icons.arrow_back_ios) + : const Icon(Icons.arrow_back); + + Icon get forwardIcon => _forwardIcon ?? _getForwardIcon; + Icon get _getForwardIcon => Platform.isIOS || Platform.isMacOS + ? const Icon(Icons.arrow_forward_ios) + : const Icon(Icons.arrow_forward); + + NeumorphicAppBarIcons copyWith({ + Icon backIcon, + Icon closeIcon, + Icon menuIcon, + Icon forwardIcon, + }) { + return NeumorphicAppBarIcons( + backIcon: backIcon ?? this.backIcon, + closeIcon: closeIcon ?? this.closeIcon, + menuIcon: menuIcon ?? this.menuIcon, + forwardIcon: forwardIcon ?? this.forwardIcon, + ); + } + + @override + bool operator ==(Object o) { + if (identical(this, o)) return true; + + return o is NeumorphicAppBarIcons && + o.backIcon == backIcon && + o.closeIcon == closeIcon && + o.menuIcon == menuIcon && + o.forwardIcon == forwardIcon; + } + + @override + int get hashCode => + backIcon.hashCode ^ + closeIcon.hashCode ^ + menuIcon.hashCode ^ + forwardIcon.hashCode; + + @override + String toString() => + 'NeumorphicAppBarIcons(backIcon: $backIcon, closeIcon: $closeIcon, menuIcon: $menuIcon, forwardIcon: $forwardIcon)'; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/inherited_neumorphic_theme.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/inherited_neumorphic_theme.dart new file mode 100644 index 00000000..fee8b0b4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/inherited_neumorphic_theme.dart @@ -0,0 +1,67 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; +import 'theme.dart'; +import 'theme_wrapper.dart'; + +export 'theme.dart'; +export 'theme_wrapper.dart'; + +typedef NeumorphicThemeUpdater = NeumorphicThemeData Function( + NeumorphicThemeData current); + +class NeumorphicThemeInherited extends InheritedWidget { + final Widget child; + final ThemeWrapper value; + final ValueChanged onChanged; + + NeumorphicThemeInherited( + {Key key, + @required this.child, + @required this.value, + @required this.onChanged}) + : super(key: key, child: child); + + @override + bool updateShouldNotify(NeumorphicThemeInherited old) => value != old.value; + + NeumorphicThemeData get current { + return this.value.current; + } + + bool get isUsingDark { + return value.useDark; + } + + ThemeMode get themeMode => value.themeMode; + + set themeMode(ThemeMode currentTheme) { + this.onChanged(value.copyWith(currentTheme: currentTheme)); + } + + void updateCurrentTheme(NeumorphicThemeData update) { + if (value.useDark) { + final newValue = value.copyWith(darkTheme: update); + //this.value = newValue; + this.onChanged(newValue); + } else { + final newValue = value.copyWith(theme: update); + //this.value = newValue; + this.onChanged(newValue); + } + } + + void update(NeumorphicThemeUpdater themeUpdater) { + final update = themeUpdater(value.current); + if (value.useDark) { + final newValue = value.copyWith(darkTheme: update); + //this.value = newValue; + this.onChanged(newValue); + } else { + final newValue = value.copyWith(theme: update); + //this.value = newValue; + this.onChanged(newValue); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/neumorphic_theme.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/neumorphic_theme.dart new file mode 100644 index 00000000..bc9803da --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/neumorphic_theme.dart @@ -0,0 +1,183 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; +import 'inherited_neumorphic_theme.dart'; +import 'theme.dart'; +import 'theme_wrapper.dart'; + +export 'inherited_neumorphic_theme.dart'; +export 'theme.dart'; +export 'theme_wrapper.dart'; + +/// The NeumorphicTheme (provider) +/// 1. Defines the used neumorphic theme used in child widgets +/// +/// @see NeumorphicThemeData +/// +/// NeumorphicTheme( +/// theme: NeumorphicThemeData(...), +/// darkTheme: NeumorphicThemeData(...), +/// currentTheme: CurrentTheme.LIGHT, +/// child: ... +/// +/// 2. Provide by static methods the current theme +/// +/// NeumorphicThemeData theme = NeumorphicTheme.getCurrentTheme(context); +/// +/// 3. Provide by static methods the current theme's colors +/// +/// Color baseColor = NeumorphicTheme.baseColor(context); +/// Color accent = NeumorphicTheme.accentColor(context); +/// Color variant = NeumorphicTheme.variantColor(context); +/// +/// 4. Tells if the current theme is dark +/// +/// bool dark = NeumorphicTheme.isUsingDark(context); +/// +/// 5. Provides a way to update the current theme +/// +/// NeumorphicTheme.of(context).updateCurrentTheme( +/// NeumorphicThemeData( +/// /* new values */ +/// ) +/// ) +/// +class NeumorphicTheme extends StatefulWidget { + final NeumorphicThemeData theme; + final NeumorphicThemeData darkTheme; + final Widget child; + final ThemeMode themeMode; + + NeumorphicTheme({ + Key key, + @required this.child, + this.theme = neumorphicDefaultTheme, + this.darkTheme = neumorphicDefaultDarkTheme, + this.themeMode = ThemeMode.system, + }); + + @override + _NeumorphicThemeState createState() => _NeumorphicThemeState(); + + static NeumorphicThemeInherited of(BuildContext context) { + try { + return context + .dependOnInheritedWidgetOfExactType(); + } catch (t) { + return null; + } + } + + static void update(BuildContext context, NeumorphicThemeUpdater updater) { + final theme = of(context); + if (theme == null) return; + return theme.update(updater); + } + + static bool isUsingDark(BuildContext context) { + final theme = of(context); + if (theme == null) return false; + return theme.isUsingDark; + } + + static Color accentColor(BuildContext context) { + return currentTheme(context).accentColor; + } + + static Color baseColor(BuildContext context) { + return currentTheme(context).baseColor; + } + + static Color variantColor(BuildContext context) { + return currentTheme(context).variantColor; + } + + static Color disabledColor(BuildContext context) { + return currentTheme(context).disabledColor; + } + + static double intensity(BuildContext context) { + return currentTheme(context).intensity; + } + + static double depth(BuildContext context) { + return currentTheme(context).depth; + } + + static double embossDepth(BuildContext context) { + if (currentTheme(context).depth == null) return null; + return -currentTheme(context).depth.abs(); + } + + static Color defaultTextColor(BuildContext context) { + return currentTheme(context).defaultTextColor; + } + + static NeumorphicThemeData currentTheme(BuildContext context) { + final provider = NeumorphicTheme.of(context); + if (provider == null) return neumorphicDefaultTheme; + return provider.current == null + ? neumorphicDefaultTheme + : provider.current; + } +} + +double applyThemeDepthEnable( + {@required BuildContext context, + @required bool styleEnableDepth, + @required double depth}) { + final NeumorphicThemeData theme = NeumorphicTheme.currentTheme(context); + return wrapDepthWithThemeData( + themeData: theme, styleEnableDepth: styleEnableDepth, depth: depth); +} + +double wrapDepthWithThemeData( + {@required NeumorphicThemeData themeData, + @required bool styleEnableDepth, + @required double depth}) { + if (themeData.disableDepth) { + return 0; + } else { + return depth; + } +} + +class _NeumorphicThemeState extends State { + ThemeWrapper _themeHost; + + @override + void initState() { + super.initState(); + _themeHost = ThemeWrapper( + theme: widget.theme, + themeMode: widget.themeMode, + darkTheme: widget.darkTheme, + ); + } + + @override + void didUpdateWidget(NeumorphicTheme oldWidget) { + super.didUpdateWidget(oldWidget); + setState(() { + _themeHost = ThemeWrapper( + theme: widget.theme, + themeMode: widget.themeMode, + darkTheme: widget.darkTheme, + ); + }); + } + + @override + Widget build(BuildContext context) { + return NeumorphicThemeInherited( + value: _themeHost, + onChanged: (value) { + setState(() { + _themeHost = value; + }); + }, + child: widget.child, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/theme.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/theme.dart new file mode 100644 index 00000000..a53f26ef --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/theme.dart @@ -0,0 +1,524 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart' show IconThemeData, TextTheme; +import 'package:flutter/painting.dart'; + +import '../../flutter_neumorphic.dart'; +import '../colors.dart'; +import '../light_source.dart'; +import '../shape.dart'; + +export '../colors.dart'; +export '../light_source.dart'; +export '../shape.dart'; + +//region theme +const double _defaultDepth = 4; +const double _defaultIntensity = 0.7; +const Color _defaultAccent = NeumorphicColors.accent; +const Color _defaultVariant = NeumorphicColors.variant; +const Color _defaultDisabledColor = NeumorphicColors.disabled; +const Color _defaultTextColor = NeumorphicColors.defaultTextColor; +const LightSource _defaultLightSource = LightSource.topLeft; +const Color _defaultBaseColor = NeumorphicColors.background; +const double _defaultBorderSize = 0.3; + +/// Used with the NeumorphicTheme +/// +/// ``` +/// NeumorphicTheme( +/// theme: NeumorphicThemeData(...) +/// darkTheme: : NeumorphicThemeData(...) +/// child: ... +/// )` +/// `` +/// +/// Contains all default values used in child Neumorphic Elements as +/// default colors : baseColor, accentColor, variantColor +/// default depth & intensities, used to generate white / dark shadows +/// default lightsource, used to calculate the angle of the shadow +/// @see [LightSource] +/// +@immutable +class NeumorphicThemeData { + final Color baseColor; + final Color accentColor; + final Color variantColor; + final Color disabledColor; + + final Color shadowLightColor; + final Color shadowDarkColor; + final Color shadowLightColorEmboss; + final Color shadowDarkColorEmboss; + + final NeumorphicBoxShape _boxShape; + NeumorphicBoxShape get boxShape => + _boxShape ?? NeumorphicBoxShape.roundRect(BorderRadius.circular(8)); + final Color borderColor; + final double borderWidth; + + final Color defaultTextColor; //double maybe use TextStyle here + final double _depth; + final double _intensity; + final LightSource lightSource; + final bool disableDepth; + + /// Default text theme to use and apply across the app + final TextTheme textTheme; + + /// Default button style to use and apply across the app + final NeumorphicStyle buttonStyle; + + /// Default icon theme to use and apply across the app + final IconThemeData iconTheme; + final NeumorphicAppBarThemeData appBarTheme; + + /// Get this theme's depth, clamp to min/max neumorphic constants + double get depth => _depth.clamp(Neumorphic.MIN_DEPTH, Neumorphic.MAX_DEPTH); + + /// Get this theme's intensity, clamp to min/max neumorphic constants + double get intensity => + _intensity.clamp(Neumorphic.MIN_INTENSITY, Neumorphic.MAX_INTENSITY); + + const NeumorphicThemeData({ + this.baseColor = _defaultBaseColor, + double depth = _defaultDepth, + NeumorphicBoxShape boxShape, + double intensity = _defaultIntensity, + this.accentColor = _defaultAccent, + this.variantColor = _defaultVariant, + this.disabledColor = _defaultDisabledColor, + this.shadowLightColor = NeumorphicColors.decorationMaxWhiteColor, + this.shadowDarkColor = NeumorphicColors.decorationMaxDarkColor, + this.shadowLightColorEmboss = NeumorphicColors.embossMaxWhiteColor, + this.shadowDarkColorEmboss = NeumorphicColors.embossMaxDarkColor, + this.defaultTextColor = _defaultTextColor, + this.lightSource = _defaultLightSource, + this.textTheme = const TextTheme(), + this.iconTheme = const IconThemeData(), + this.buttonStyle, + this.appBarTheme = const NeumorphicAppBarThemeData(), + this.borderColor = NeumorphicColors.defaultBorder, + this.borderWidth = _defaultBorderSize, + this.disableDepth = false, + }) : this._depth = depth, + this._boxShape = boxShape, + this._intensity = intensity; + + const NeumorphicThemeData.dark({ + this.baseColor = NeumorphicColors.darkBackground, + double depth = _defaultDepth, + NeumorphicBoxShape boxShape, + double intensity = _defaultIntensity, + this.accentColor = _defaultAccent, + this.textTheme = const TextTheme(), + this.buttonStyle, + this.iconTheme = const IconThemeData(), + this.appBarTheme = const NeumorphicAppBarThemeData(), + this.variantColor = NeumorphicColors.darkVariant, + this.disabledColor = NeumorphicColors.darkDisabled, + this.shadowLightColor = NeumorphicColors.decorationMaxWhiteColor, + this.shadowDarkColor = NeumorphicColors.decorationMaxDarkColor, + this.shadowLightColorEmboss = NeumorphicColors.embossMaxWhiteColor, + this.shadowDarkColorEmboss = NeumorphicColors.embossMaxDarkColor, + this.defaultTextColor = NeumorphicColors.darkDefaultTextColor, + this.lightSource = _defaultLightSource, + this.borderColor = NeumorphicColors.darkDefaultBorder, + this.borderWidth = _defaultBorderSize, + this.disableDepth = false, + }) : this._depth = depth, + this._boxShape = boxShape, + this._intensity = intensity; + + @override + String toString() { + return 'NeumorphicTheme{baseColor: $baseColor, boxShape: $boxShape, disableDepth: $disableDepth, accentColor: $accentColor, variantColor: $variantColor, disabledColor: $disabledColor, _depth: $_depth, intensity: $intensity, lightSource: $lightSource}'; + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicThemeData && + runtimeType == other.runtimeType && + baseColor == other.baseColor && + boxShape == other.boxShape && + textTheme == other.textTheme && + iconTheme == other.iconTheme && + buttonStyle == other.buttonStyle && + appBarTheme == other.appBarTheme && + accentColor == other.accentColor && + shadowDarkColor == other.shadowDarkColor && + shadowLightColor == other.shadowLightColor && + shadowDarkColorEmboss == other.shadowDarkColorEmboss && + shadowLightColorEmboss == other.shadowLightColorEmboss && + disabledColor == other.disabledColor && + variantColor == other.variantColor && + disableDepth == other.disableDepth && + defaultTextColor == other.defaultTextColor && + borderWidth == other.borderWidth && + borderColor == other.borderColor && + _depth == other._depth && + _intensity == other._intensity && + lightSource == other.lightSource; + + @override + int get hashCode => + baseColor.hashCode ^ + textTheme.hashCode ^ + iconTheme.hashCode ^ + buttonStyle.hashCode ^ + appBarTheme.hashCode ^ + accentColor.hashCode ^ + variantColor.hashCode ^ + disabledColor.hashCode ^ + shadowDarkColor.hashCode ^ + shadowLightColor.hashCode ^ + shadowDarkColorEmboss.hashCode ^ + shadowLightColorEmboss.hashCode ^ + defaultTextColor.hashCode ^ + disableDepth.hashCode ^ + borderWidth.hashCode ^ + borderColor.hashCode ^ + _depth.hashCode ^ + boxShape.hashCode ^ + _intensity.hashCode ^ + lightSource.hashCode; + + /// Create a copy of this theme + /// With possibly new values given from this method's arguments + NeumorphicThemeData copyWith({ + Color baseColor, + Color accentColor, + Color variantColor, + Color disabledColor, + Color shadowLightColor, + Color shadowDarkColor, + Color shadowLightColorEmboss, + Color shadowDarkColorEmboss, + Color defaultTextColor, + NeumorphicBoxShape boxShape, + TextTheme textTheme, + NeumorphicStyle buttonStyle, + IconThemeData iconTheme, + NeumorphicAppBarThemeData appBarTheme, + NeumorphicStyle defaultStyle, + bool disableDepth, + double depth, + double intensity, + Color borderColor, + double borderSize, + LightSource lightSource, + }) { + return new NeumorphicThemeData( + baseColor: baseColor ?? this.baseColor, + textTheme: textTheme ?? this.textTheme, + iconTheme: iconTheme ?? this.iconTheme, + buttonStyle: buttonStyle ?? this.buttonStyle, + boxShape: boxShape ?? this.boxShape, + appBarTheme: appBarTheme ?? this.appBarTheme, + accentColor: accentColor ?? this.accentColor, + variantColor: variantColor ?? this.variantColor, + disabledColor: disabledColor ?? this.disabledColor, + defaultTextColor: defaultTextColor ?? this.defaultTextColor, + disableDepth: disableDepth ?? this.disableDepth, + shadowDarkColor: shadowDarkColor ?? this.shadowDarkColor, + shadowLightColor: shadowLightColor ?? this.shadowLightColor, + shadowDarkColorEmboss: + shadowDarkColorEmboss ?? this.shadowDarkColorEmboss, + shadowLightColorEmboss: + shadowLightColorEmboss ?? this.shadowLightColorEmboss, + depth: depth ?? this._depth, + borderWidth: borderSize ?? this.borderWidth, + borderColor: borderColor ?? this.borderColor, + intensity: intensity ?? this._intensity, + lightSource: lightSource ?? this.lightSource, + ); + } + + /// Create a copy of this theme + /// With possibly new values given from the given second theme + NeumorphicThemeData copyFrom({ + @required NeumorphicThemeData other, + }) { + return new NeumorphicThemeData( + baseColor: other.baseColor, + accentColor: other.accentColor, + variantColor: other.variantColor, + disableDepth: other.disableDepth, + disabledColor: other.disabledColor, + defaultTextColor: other.defaultTextColor, + shadowDarkColor: other.shadowDarkColor, + shadowLightColor: other.shadowLightColor, + shadowDarkColorEmboss: other.shadowDarkColorEmboss, + shadowLightColorEmboss: other.shadowLightColorEmboss, + textTheme: other.textTheme, + iconTheme: other.iconTheme, + buttonStyle: other.buttonStyle, + appBarTheme: other.appBarTheme, + depth: other.depth, + boxShape: other.boxShape, + borderColor: other.borderColor, + borderWidth: other.borderWidth, + intensity: other.intensity, + lightSource: other.lightSource, + ); + } +} +//endregion + +//region style +const NeumorphicShape _defaultShape = NeumorphicShape.flat; +//const double _defaultBorderRadius = 5; + +const neumorphicDefaultTheme = NeumorphicThemeData(); +const neumorphicDefaultDarkTheme = NeumorphicThemeData.dark(); + +class NeumorphicBorder { + final bool isEnabled; + final Color color; + final double width; + + const NeumorphicBorder({ + this.isEnabled = true, + this.color, + this.width, + }); + + const NeumorphicBorder.none() + : this.isEnabled = true, + this.color = const Color(0x00000000), + this.width = 0; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicBorder && + runtimeType == other.runtimeType && + isEnabled == other.isEnabled && + color == other.color && + width == other.width; + + @override + int get hashCode => isEnabled.hashCode ^ color.hashCode ^ width.hashCode; + + @override + String toString() { + return 'NeumorphicBorder{isEnabled: $isEnabled, color: $color, width: $width}'; + } + + static NeumorphicBorder lerp( + NeumorphicBorder a, NeumorphicBorder b, double t) { + if (a == null && b == null) return null; + + if (t == 0.0) return a; + if (t == 1.0) return b; + + return NeumorphicBorder( + color: Color.lerp(a.color, b.color, t), + isEnabled: a.isEnabled, + width: lerpDouble(a.width, b.width, t), + ); + } + + NeumorphicBorder copyWithThemeIfNull({Color color, double width}) { + return NeumorphicBorder( + isEnabled: this.isEnabled, + color: this.color ?? color, + width: this.width ?? width, + ); + } +} + +class NeumorphicStyle { + final Color color; + final double _depth; + final double _intensity; + final double _surfaceIntensity; + final LightSource lightSource; + final bool disableDepth; + + final NeumorphicBorder border; + + final bool oppositeShadowLightSource; + + final NeumorphicShape shape; + final NeumorphicBoxShape boxShape; + final NeumorphicThemeData theme; + + //override the "white" color + final Color shadowLightColor; + + //override the "dark" color + final Color shadowDarkColor; + + //override the "white" color + final Color shadowLightColorEmboss; + + //override the "dark" color + final Color shadowDarkColorEmboss; + + const NeumorphicStyle({ + this.shape = _defaultShape, + this.lightSource = LightSource.topLeft, + this.border = const NeumorphicBorder.none(), + this.color, + this.boxShape, //nullable by default, will use the one defined in theme if not set + this.shadowLightColor, + this.shadowDarkColor, + this.shadowLightColorEmboss, + this.shadowDarkColorEmboss, + double depth, + double intensity, + double surfaceIntensity = 0.25, + this.disableDepth, + this.oppositeShadowLightSource = false, + }) : this._depth = depth, + this.theme = null, + this._intensity = intensity, + this._surfaceIntensity = surfaceIntensity; + + // with theme constructor is only available privately, please use copyWithThemeIfNull + const NeumorphicStyle._withTheme({ + this.theme, + this.shape = _defaultShape, + this.lightSource = LightSource.topLeft, + this.color, + this.boxShape, + this.border = const NeumorphicBorder.none(), + this.shadowLightColor, + this.shadowDarkColor, + this.shadowLightColorEmboss, + this.shadowDarkColorEmboss, + this.oppositeShadowLightSource = false, + this.disableDepth, + double depth, + double intensity, + double surfaceIntensity = 0.25, + }) : this._depth = depth, + this._intensity = intensity, + this._surfaceIntensity = surfaceIntensity; + + double get depth => + _depth?.clamp(Neumorphic.MIN_DEPTH, Neumorphic.MAX_DEPTH); + + double get intensity => + _intensity?.clamp(Neumorphic.MIN_INTENSITY, Neumorphic.MAX_INTENSITY); + + double get surfaceIntensity => _surfaceIntensity.clamp( + Neumorphic.MIN_INTENSITY, Neumorphic.MAX_INTENSITY); + + NeumorphicStyle copyWithThemeIfNull(NeumorphicThemeData theme) { + return NeumorphicStyle._withTheme( + theme: theme, + color: this.color ?? theme.baseColor, + boxShape: this.boxShape ?? theme.boxShape, + shape: this.shape, + border: this.border.copyWithThemeIfNull( + color: theme.borderColor, width: theme.borderWidth), + shadowDarkColor: this.shadowDarkColor ?? theme.shadowDarkColor, + shadowLightColor: this.shadowLightColor ?? theme.shadowLightColor, + shadowDarkColorEmboss: + this.shadowDarkColorEmboss ?? theme.shadowDarkColorEmboss, + shadowLightColorEmboss: + this.shadowLightColorEmboss ?? theme.shadowLightColorEmboss, + depth: this.depth ?? theme.depth, + intensity: this.intensity ?? theme.intensity, + disableDepth: this.disableDepth ?? theme.disableDepth, + surfaceIntensity: this.surfaceIntensity, + oppositeShadowLightSource: this.oppositeShadowLightSource, + lightSource: this.lightSource); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicStyle && + runtimeType == other.runtimeType && + color == other.color && + boxShape == other.boxShape && + border == other.border && + shadowDarkColor == other.shadowDarkColor && + shadowLightColor == other.shadowLightColor && + shadowDarkColorEmboss == other.shadowDarkColorEmboss && + shadowLightColorEmboss == other.shadowLightColorEmboss && + disableDepth == other.disableDepth && + _depth == other._depth && + _intensity == other._intensity && + _surfaceIntensity == other._surfaceIntensity && + lightSource == other.lightSource && + oppositeShadowLightSource == other.oppositeShadowLightSource && + shape == other.shape && + theme == other.theme; + + @override + int get hashCode => + color.hashCode ^ + shadowDarkColor.hashCode ^ + boxShape.hashCode ^ + shadowLightColor.hashCode ^ + shadowDarkColorEmboss.hashCode ^ + shadowLightColorEmboss.hashCode ^ + _depth.hashCode ^ + border.hashCode ^ + _intensity.hashCode ^ + disableDepth.hashCode ^ + _surfaceIntensity.hashCode ^ + lightSource.hashCode ^ + oppositeShadowLightSource.hashCode ^ + shape.hashCode ^ + theme.hashCode; + + NeumorphicStyle copyWith({ + Color color, + NeumorphicBorder border, + NeumorphicBoxShape boxShape, + Color shadowLightColor, + Color shadowDarkColor, + Color shadowLightColorEmboss, + Color shadowDarkColorEmboss, + double depth, + double intensity, + double surfaceIntensity, + LightSource lightSource, + bool disableDepth, + double borderRadius, + bool oppositeShadowLightSource, + NeumorphicShape shape, + }) { + return NeumorphicStyle._withTheme( + color: color ?? this.color, + border: border ?? this.border, + boxShape: boxShape ?? this.boxShape, + shadowDarkColor: shadowDarkColor ?? this.shadowDarkColor, + shadowLightColor: shadowLightColor ?? this.shadowLightColor, + shadowDarkColorEmboss: + shadowDarkColorEmboss ?? this.shadowDarkColorEmboss, + shadowLightColorEmboss: + shadowLightColorEmboss ?? this.shadowLightColorEmboss, + depth: depth ?? this.depth, + theme: this.theme, + intensity: intensity ?? this.intensity, + surfaceIntensity: surfaceIntensity ?? this.surfaceIntensity, + disableDepth: disableDepth ?? this.disableDepth, + lightSource: lightSource ?? this.lightSource, + oppositeShadowLightSource: + oppositeShadowLightSource ?? this.oppositeShadowLightSource, + shape: shape ?? this.shape, + ); + } + + @override + String toString() { + return 'NeumorphicStyle{color: $color, boxShape: $boxShape, _depth: $_depth, intensity: $intensity, disableDepth: $disableDepth, lightSource: $lightSource, shape: $shape, theme: $theme, oppositeShadowLightSource: $oppositeShadowLightSource}'; + } + + NeumorphicStyle applyDisableDepth() { + if (disableDepth == true) { + return this.copyWith(depth: 0); + } else { + return this; + } + } +} +//endregion diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/theme_wrapper.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/theme_wrapper.dart new file mode 100644 index 00000000..fc1481c7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/theme/theme_wrapper.dart @@ -0,0 +1,61 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import 'theme.dart'; + +export 'theme.dart'; + +/// A immutable contained by the NeumorhicTheme +/// That will save the current definition of the theme +/// It will be accessible to the childs widgets by an InheritedWidget +class ThemeWrapper { + final NeumorphicThemeData theme; + final NeumorphicThemeData darkTheme; + final ThemeMode themeMode; + + const ThemeWrapper({ + @required this.theme, + this.darkTheme, + this.themeMode = ThemeMode.system, + }); + + bool get useDark => + //forced to use DARK by user + themeMode == ThemeMode.dark || + //The setting indicating the current brightness mode of the host platform. If the platform has no preference, platformBrightness defaults to Brightness.light. + (themeMode == ThemeMode.system && + window.platformBrightness == Brightness.dark); + + NeumorphicThemeData get current { + if (useDark) { + return darkTheme; + } else { + return theme; + } + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ThemeWrapper && + runtimeType == other.runtimeType && + theme == other.theme && + darkTheme == other.darkTheme && + themeMode == other.themeMode; + + @override + int get hashCode => theme.hashCode ^ darkTheme.hashCode ^ themeMode.hashCode; + + ThemeWrapper copyWith({ + NeumorphicThemeData theme, + NeumorphicThemeData darkTheme, + ThemeMode currentTheme, + }) { + return new ThemeWrapper( + theme: theme ?? this.theme, + darkTheme: darkTheme ?? this.darkTheme, + themeMode: currentTheme ?? this.themeMode, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/animation/animated_scale.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/animation/animated_scale.dart new file mode 100644 index 00000000..e9cc12c0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/animation/animated_scale.dart @@ -0,0 +1,80 @@ +import 'package:flutter/widgets.dart'; + +/// A implicit animated widget than update the child's scale depending on the +/// parameter `scale` and `duration` +/// +/// eg: in an statefull widget +/// +/// double _scale = 1; +/// +/// AnimatedScale( +/// scale: _scale, +/// child: /* a widget */ +/// ) +/// +/// then use +/// +/// setState((){ +/// _scale = 0.5 +/// }); +/// +/// This will aimate the child's scale from 1 to 0.5 in 150ms (default duration) +/// +class AnimatedScale extends StatefulWidget { + final Widget child; + final double scale; + final Duration duration; + final Alignment alignment; + + const AnimatedScale({ + this.child, + this.scale = 1, + this.duration = const Duration(milliseconds: 150), + this.alignment = Alignment.center, + }); + + @override + _AnimatedScaleState createState() => _AnimatedScaleState(); +} + +class _AnimatedScaleState extends State + with TickerProviderStateMixin { + AnimationController _controller; + Animation _animation; + double oldScale = 1; + + @override + void initState() { + _controller = AnimationController(duration: widget.duration, vsync: this); + _animation = Tween(begin: widget.scale, end: widget.scale) + .animate(_controller); + super.initState(); + } + + @override + void didUpdateWidget(AnimatedScale oldWidget) { + if (oldWidget.scale != widget.scale) { + _controller.reset(); + oldScale = oldWidget.scale; + _animation = Tween(begin: oldScale, end: widget.scale) + .animate(_controller); + _controller.forward(); + } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return ScaleTransition( + scale: _animation, + alignment: widget.alignment, + child: widget.child, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/app.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/app.dart new file mode 100644 index 00000000..88bf1e8b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/app.dart @@ -0,0 +1,149 @@ +import 'package:flutter/material.dart'; + +import '../../flutter_neumorphic.dart'; + +class NeumorphicApp extends StatelessWidget { + final String title; + final ThemeMode themeMode; + final NeumorphicThemeData theme; + final NeumorphicThemeData darkTheme; + final ThemeData materialDarkTheme; + final ThemeData materialTheme; + final String initialRoute; + final Color color; + final Iterable> localizationsDelegates; + final Locale locale; + final Widget home; + final Iterable supportedLocales; + final Map routes; + final RouteFactory onGenerateRoute; + final RouteFactory onUnknownRoute; + final GenerateAppTitle onGenerateTitle; + final GlobalKey navigatorKey; + final List navigatorObservers; + final InitialRouteListFactory onGenerateInitialRoutes; + final bool debugShowCheckedModeBanner; + final Widget Function(BuildContext, Widget) builder; + final Locale Function(Locale, Iterable) localeResolutionCallback; + final ThemeData highContrastTheme; + final ThemeData highContrastDarkTheme; + final LocaleListResolutionCallback localeListResolutionCallback; + final bool showPerformanceOverlay; + final bool checkerboardRasterCacheImages; + final bool checkerboardOffscreenLayers; + final bool showSemanticsDebugger; + final Map shortcuts; + final Map> actions; + + final bool debugShowMaterialGrid; + + const NeumorphicApp({ + Key key, + this.title = '', + this.color, + this.initialRoute, + this.routes = const {}, + this.home, + this.debugShowCheckedModeBanner = true, + this.navigatorKey, + this.navigatorObservers = const [], + this.onGenerateRoute, + this.onGenerateTitle, + this.onGenerateInitialRoutes, + this.onUnknownRoute, + this.theme = neumorphicDefaultTheme, + this.darkTheme = neumorphicDefaultDarkTheme, + this.locale, + this.localizationsDelegates, + this.supportedLocales = const [Locale('en', 'US')], + this.themeMode = ThemeMode.system, + this.materialDarkTheme, + this.materialTheme, + this.builder, + this.localeResolutionCallback, + this.highContrastTheme, + this.highContrastDarkTheme, + this.localeListResolutionCallback, + this.showPerformanceOverlay = false, + this.checkerboardRasterCacheImages = false, + this.checkerboardOffscreenLayers = false, + this.showSemanticsDebugger = false, + this.debugShowMaterialGrid = false, + this.shortcuts, + this.actions, + }) : super(key: key); + + ThemeData _getMaterialTheme(NeumorphicThemeData theme) { + final color = theme.accentColor; + + if (color is MaterialColor) { + return ThemeData( + primarySwatch: color, + textTheme: theme.textTheme, + iconTheme: theme.iconTheme, + scaffoldBackgroundColor: theme.baseColor, + ); + } + + return ThemeData( + primaryColor: theme.accentColor, + accentColor: theme.variantColor, + iconTheme: theme.iconTheme, + brightness: ThemeData.estimateBrightnessForColor(theme.baseColor), + primaryColorBrightness: + ThemeData.estimateBrightnessForColor(theme.accentColor), + accentColorBrightness: + ThemeData.estimateBrightnessForColor(theme.variantColor), + textTheme: theme.textTheme, + scaffoldBackgroundColor: theme.baseColor, + ); + } + + @override + Widget build(BuildContext context) { + final materialTheme = this.materialTheme ?? _getMaterialTheme(theme); + final materialDarkTheme = + this.materialDarkTheme ?? _getMaterialTheme(darkTheme); + return NeumorphicTheme( + theme: theme, + darkTheme: darkTheme, + themeMode: themeMode, + child: Builder( + builder: (context) => IconTheme( + data: NeumorphicTheme.currentTheme(context).iconTheme, + child: MaterialApp( + title: title, + color: color, + theme: materialTheme, + darkTheme: materialDarkTheme, + initialRoute: initialRoute, + routes: routes, + themeMode: themeMode, + localizationsDelegates: localizationsDelegates, + supportedLocales: supportedLocales, + locale: locale, + home: home, + onGenerateRoute: onGenerateRoute, + onUnknownRoute: onUnknownRoute, + onGenerateTitle: onGenerateTitle, + onGenerateInitialRoutes: onGenerateInitialRoutes, + navigatorKey: navigatorKey, + navigatorObservers: navigatorObservers, + debugShowCheckedModeBanner: debugShowCheckedModeBanner, + builder: builder, + localeResolutionCallback: localeResolutionCallback, + highContrastTheme: highContrastTheme, + highContrastDarkTheme: highContrastDarkTheme, + localeListResolutionCallback: localeListResolutionCallback, + showPerformanceOverlay: showPerformanceOverlay, + checkerboardRasterCacheImages: checkerboardRasterCacheImages, + checkerboardOffscreenLayers: checkerboardOffscreenLayers, + showSemanticsDebugger: showSemanticsDebugger, + shortcuts: shortcuts, + actions: actions, + debugShowMaterialGrid: debugShowMaterialGrid), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/app_bar.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/app_bar.dart new file mode 100644 index 00000000..cb380416 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/app_bar.dart @@ -0,0 +1,255 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; + +class NeumorphicAppBar extends StatefulWidget implements PreferredSizeWidget { + static const toolbarHeight = kToolbarHeight + 16 * 2; + static const defaultSpacing = 4.0; + + /// The primary widget displayed in the app bar. + /// + /// Typically a [Text] widget that contains a description of the current + /// contents of the app. + final Widget title; + + /// A widget to display before the [title]. + /// + /// Typically the [leading] widget is an [Icon] or an [IconButton]. + /// + /// Becomes the leading component of the [NavigationToolBar] built + /// by this widget. The [leading] widget's width and height are constrained to + /// be no bigger than toolbar's height, which is [kToolbarHeight]. + /// + /// If this is null and [automaticallyImplyLeading] is set to true, the + /// [NeumorphicAppBar] will imply an appropriate widget. For example, if the [NeumorphicAppBar] is + /// in a [Scaffold] that also has a [Drawer], the [Scaffold] will fill this + /// widget with an [IconButton] that opens the drawer (using [Icons.menu]). If + /// there's no [Drawer] and the parent [Navigator] can go back, the [NeumorphicAppBar] + /// will use a [NeumorphicBackButton] that calls [Navigator.maybePop]. + final Widget leading; + + /// Whether the title should be centered. + /// + /// Defaults to being adapted to the current [TargetPlatform]. + final bool centerTitle; + + /// Widgets to display in a row after the [title] widget. + /// + /// Typically these widgets are [IconButton]s representing common operations. + /// For less common operations, consider using a [PopupMenuButton] as the + /// last action. + /// + /// The [actions] become the trailing component of the [NavigationToolBar] built + /// by this widget. The height of each action is constrained to be no bigger + /// than the toolbar's height, which is [kToolbarHeight]. + final List actions; + + /// Controls whether we should try to imply the leading widget if null. + /// + /// If true and [leading] is null, automatically try to deduce what the leading + /// widget should be. If false and [leading] is null, leading space is given to [title]. + /// If leading widget is not null, this parameter has no effect. + final bool automaticallyImplyLeading; + + /// The spacing around [title] content on the horizontal axis. This spacing is + /// applied even if there is no [leading] content or [actions]. If you want + /// [title] to take all the space available, set this value to 0.0. + /// + /// Defaults to [NavigationToolbar.kMiddleSpacing]. + final double titleSpacing; + + /// The spacing [actions] left side, useful to have spacing between actions + /// + /// Defaults to [NeumorphicAppBar.defaultSpacing]. + final double actionSpacing; + + /// Force background color of the app bar + final Color color; + + /// Force color of the icon inside app bar + final IconThemeData iconTheme; + + @override + final Size preferredSize; + + final NeumorphicStyle buttonStyle; + + final EdgeInsets buttonPadding; + + final TextStyle textStyle; + + final double padding; + + NeumorphicAppBar({ + Key key, + this.title, + this.buttonPadding, + this.buttonStyle, + this.iconTheme, + this.color, + this.actions, + this.textStyle, + this.leading, + this.automaticallyImplyLeading = true, + this.centerTitle, + this.titleSpacing = NavigationToolbar.kMiddleSpacing, + this.actionSpacing = defaultSpacing, + this.padding = 16, + }) : preferredSize = Size.fromHeight(toolbarHeight), + super(key: key); + + @override + NeumorphicAppBarState createState() => NeumorphicAppBarState(); + + bool _getEffectiveCenterTitle(ThemeData theme, NeumorphicThemeData nTheme) { + if (centerTitle != null || nTheme.appBarTheme.centerTitle != null) + return centerTitle ?? nTheme.appBarTheme.centerTitle; + switch (theme.platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + return false; + case TargetPlatform.iOS: + case TargetPlatform.macOS: + return actions == null || actions.length < 2; + } + } +} + +class NeumorphicAppBarTheme extends InheritedWidget { + final Widget child; + + NeumorphicAppBarTheme({@required this.child}) : super(child: child); + + @override + bool updateShouldNotify(InheritedWidget oldWidget) { + return false; + } + + static NeumorphicAppBarTheme of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } +} + +class NeumorphicAppBarState extends State { + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final nTheme = NeumorphicTheme.of(context); + final ModalRoute parentRoute = ModalRoute.of(context); + final bool canPop = parentRoute?.canPop ?? false; + final bool useCloseButton = + parentRoute is PageRoute && parentRoute.fullscreenDialog; + final ScaffoldState scaffold = Scaffold.maybeOf(context); + final bool hasDrawer = scaffold?.hasDrawer ?? false; + final bool hasEndDrawer = scaffold?.hasEndDrawer ?? false; + + Widget leading = widget.leading; + if (leading == null && widget.automaticallyImplyLeading) { + if (hasDrawer) { + leading = NeumorphicButton( + padding: widget.buttonPadding, + style: widget.buttonStyle, + child: nTheme?.current?.appBarTheme.icons.menuIcon, + onPressed: _handleDrawerButton, + tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip, + ); + } else { + if (canPop) + leading = useCloseButton + ? NeumorphicCloseButton( + padding: widget.buttonPadding, + style: widget.buttonStyle, + ) + : NeumorphicBackButton( + padding: widget.buttonPadding, + style: widget.buttonStyle, + ); + } + } + if (leading != null) { + leading = ConstrainedBox( + constraints: const BoxConstraints.tightFor(width: kToolbarHeight), + child: leading, + ); + } + + Widget title = widget.title; + if (title != null) { + final AppBarTheme appBarTheme = AppBarTheme.of(context); + title = DefaultTextStyle( + style: (appBarTheme.textTheme?.headline5 ?? + Theme.of(context).textTheme.headline5) + .merge(widget.textStyle ?? nTheme?.current?.appBarTheme.textStyle), + softWrap: false, + overflow: TextOverflow.ellipsis, + child: title, + ); + } + + Widget actions; + if (widget.actions != null && widget.actions.isNotEmpty) { + actions = Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: widget.actions + .map((child) => Padding( + padding: EdgeInsets.only(left: widget.actionSpacing), + child: ConstrainedBox( + constraints: const BoxConstraints.tightFor( + width: kToolbarHeight, height: kToolbarHeight), + child: child, + ), + )) + .toList(growable: false), + ); + } else if (hasEndDrawer) { + actions = ConstrainedBox( + constraints: const BoxConstraints.tightFor( + width: kToolbarHeight, height: kToolbarHeight), + child: NeumorphicButton( + padding: widget.buttonPadding, + style: widget.buttonStyle, + child: nTheme?.current?.appBarTheme.icons.menuIcon, + onPressed: _handleDrawerButtonEnd, + tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip, + ), + ); + } + return Container( + color: widget.color ?? nTheme?.current?.appBarTheme.color, + child: SafeArea( + bottom: false, + child: NeumorphicAppBarTheme( + child: Padding( + padding: EdgeInsets.all(widget.padding), + child: IconTheme( + data: widget.iconTheme ?? + nTheme?.current?.appBarTheme.iconTheme ?? + nTheme?.current?.iconTheme ?? + const IconThemeData(), + child: NavigationToolbar( + leading: leading, + middle: title, + trailing: actions, + centerMiddle: + widget._getEffectiveCenterTitle(theme, nTheme.current), + middleSpacing: widget.titleSpacing, + ), + ), + ), + ), + ), + ); + } + + void _handleDrawerButton() { + Scaffold.of(context).openDrawer(); + } + + void _handleDrawerButtonEnd() { + Scaffold.of(context).openEndDrawer(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/back_button.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/back_button.dart new file mode 100644 index 00000000..970cafa2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/back_button.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; + +class NeumorphicBackButton extends StatelessWidget { + final VoidCallback onPressed; + final NeumorphicStyle style; + final EdgeInsets padding; + final bool forward; + + const NeumorphicBackButton({ + Key key, + this.onPressed, + this.style, + this.padding, + this.forward = false, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final nThemeIcons = NeumorphicTheme.of(context).current.appBarTheme.icons; + return NeumorphicButton( + style: style, + padding: padding, + tooltip: MaterialLocalizations.of(context).backButtonTooltip, + child: forward ? nThemeIcons.forwardIcon : nThemeIcons.backIcon, + onPressed: onPressed ?? () => Navigator.maybePop(context), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/background.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/background.dart new file mode 100644 index 00000000..6306feb7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/background.dart @@ -0,0 +1,50 @@ +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; + +/// A container that takes the current [NeumorphicTheme] baseColor as backgroundColor +/// @see [NeumorphicTheme] +/// +/// +/// It can provide too a roundRect clip of the screen border using [borderRadius], [margin] and [backendColor] +/// +/// ``` +/// NeumorphicBackground( +/// borderRadius: BorderRadius.circular(12), +/// margin: EdgeInsets.all(12), +/// child: ...` +/// ) +/// ``` +@immutable +class NeumorphicBackground extends StatelessWidget { + final Widget child; + final EdgeInsets padding; + final EdgeInsets margin; + final Color backendColor; + final BorderRadius borderRadius; + + const NeumorphicBackground({ + this.child, + this.padding, + this.margin, + this.borderRadius, + this.backendColor = const Color(0xFF000000), + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: this.margin, + color: this.backendColor, + child: ClipRRect( + borderRadius: this.borderRadius ?? BorderRadius.circular(0), + child: AnimatedContainer( + color: NeumorphicTheme.baseColor(context), + padding: this.padding, + duration: const Duration(milliseconds: 100), + child: this.child, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/button.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/button.dart new file mode 100644 index 00000000..5bebd390 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/button.dart @@ -0,0 +1,238 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import '../theme/neumorphic_theme.dart'; +import '../widget/app_bar.dart'; +import 'animation/animated_scale.dart'; +import 'container.dart'; + +typedef void NeumorphicButtonClickListener(); + +/// A Neumorphic Button +/// +/// When pressed, it will fire a call to its [NeumorphicButtonClickListener] click parameter +/// The animation starts from style.depth (or theme.depth is not defined in the style) +/// @see [NeumorphicStyle] +/// +/// And finished to `minDistance`, in [duration] (time) +/// +/// You can force the pressed state using [pressed] +/// - true : forced as pressed +/// - false : forced as unpressed +/// - null : can be pressed by user +/// +/// It takes a [padding], default EdgeInsets.symmetric(horizontal: 8, vertical: 4)` +/// +/// It takes a [NeumorphicStyle] @see [Neumorphi] +/// +/// ``` +/// NeumorphicButton( +/// onClick: () { +/// setState(() { +/// ... +/// }); +/// }, +/// boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(12)), +/// style: NeumorphicStyle( +/// shape: NeumorphicShape.flat, +/// ), +/// child: ... +/// ) +/// ``` +/// +@immutable +class NeumorphicButton extends StatefulWidget { + static const double PRESSED_SCALE = 0.98; + static const double UNPRESSED_SCALE = 1.0; + + final Widget child; + final NeumorphicStyle style; + final double minDistance; + final EdgeInsets padding; + final EdgeInsets margin; + final bool pressed; //null, true, false + final Duration duration; + final Curve curve; + final NeumorphicButtonClickListener onPressed; + final bool drawSurfaceAboveChild; + final bool provideHapticFeedback; + final String tooltip; + + NeumorphicButton({ + Key key, + this.padding, + this.margin = EdgeInsets.zero, + this.child, + this.tooltip, + this.drawSurfaceAboveChild = true, + this.pressed, //true/false if you want to change the state of the button + this.duration = Neumorphic.DEFAULT_DURATION, + this.curve = Neumorphic.DEFAULT_CURVE, + //this.accent, + this.onPressed, + this.minDistance = 0, + this.style, + this.provideHapticFeedback = true, + }) : super(key: key); + + bool get isEnabled => onPressed != null; + + @override + _NeumorphicButtonState createState() => _NeumorphicButtonState(); +} + +class _NeumorphicButtonState extends State { + NeumorphicStyle initialStyle; + + double depth; + bool pressed = false; //overwrite widget.pressed when click for animation + + void updateInitialStyle() { + final appBarPresent = NeumorphicAppBarTheme.of(context) != null; + + final theme = NeumorphicTheme.currentTheme(context); + this.initialStyle = widget.style ?? + (appBarPresent + ? theme.appBarTheme.buttonStyle + : (theme.buttonStyle ?? const NeumorphicStyle())); + depth = widget.style?.depth ?? + (appBarPresent ? theme.appBarTheme.buttonStyle.depth : theme.depth) ?? + 0.0; + + setState(() {}); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + updateInitialStyle(); + } + + @override + void didUpdateWidget(NeumorphicButton oldWidget) { + super.didUpdateWidget(oldWidget); + updateInitialStyle(); + } + + Future _handlePress() async { + hasFinishedAnimationDown = false; + setState(() { + pressed = true; + depth = widget.minDistance; + }); + + await Future.delayed(widget.duration); //wait until animation finished + hasFinishedAnimationDown = true; + + //haptic vibration + if (widget.provideHapticFeedback) { + HapticFeedback.lightImpact(); + } + + _resetIfTapUp(); + } + + bool hasDisposed = false; + + @override + void dispose() { + super.dispose(); + hasDisposed = true; + } + + //used to stay pressed if no tap up + void _resetIfTapUp() { + if (hasFinishedAnimationDown == true && hasTapUp == true && !hasDisposed) { + setState(() { + pressed = false; + depth = initialStyle.depth ?? neumorphicDefaultTheme.depth; + + hasFinishedAnimationDown = false; + hasTapUp = false; + }); + } + } + + bool get clickable { + return widget.isEnabled && widget.onPressed != null; + } + + bool hasFinishedAnimationDown = false; + bool hasTapUp = false; + + @override + Widget build(BuildContext context) { + final result = _build(context); + if (widget.tooltip != null) { + return Tooltip( + message: widget.tooltip, + child: result, + ); + } else { + return result; + } + } + + Widget _build(BuildContext context) { + final appBarPresent = NeumorphicAppBarTheme.of(context) != null; + final appBarTheme = NeumorphicTheme.currentTheme(context).appBarTheme; + + return GestureDetector( + onTapDown: (detail) { + hasTapUp = false; + if (clickable && !pressed) { + _handlePress(); + } + }, + onTapUp: (details) { + if (clickable) { + widget.onPressed(); + } + hasTapUp = true; + _resetIfTapUp(); + }, + onTapCancel: () { + hasTapUp = true; + _resetIfTapUp(); + }, + child: AnimatedScale( + scale: _getScale(), + child: Neumorphic( + margin: widget.margin ?? const EdgeInsets.all(0), + drawSurfaceAboveChild: widget.drawSurfaceAboveChild, + duration: widget.duration, + curve: widget.curve, + padding: widget.padding ?? + (appBarPresent ? appBarTheme.buttonPadding : null) ?? + const EdgeInsets.symmetric(horizontal: 18, vertical: 10), + style: initialStyle.copyWith( + depth: _getDepth(), + ), + child: widget.child, + ), + ), + ); + } + + double _getDepth() { + if (widget.isEnabled) { + return this.depth; + } else { + return 0; + } + } + + double _getScale() { + if (widget.pressed != null) { + //defined by the widget that use it + return widget.pressed + ? NeumorphicButton.PRESSED_SCALE + : NeumorphicButton.UNPRESSED_SCALE; + } else { + return this.pressed + ? NeumorphicButton.PRESSED_SCALE + : NeumorphicButton.UNPRESSED_SCALE; + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/checkbox.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/checkbox.dart new file mode 100644 index 00000000..fc03d27c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/checkbox.dart @@ -0,0 +1,211 @@ +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; +import '../neumorphic_box_shape.dart'; +import '../neumorphic_icons.dart'; +import '../theme/neumorphic_theme.dart'; +import 'button.dart'; + +typedef void NeumorphicCheckboxListener(T value); + +/// A Style used to customize a NeumorphicCheckbox +/// +/// selectedDepth : the depth when checked +/// unselectedDepth : the depth when unchecked (default : theme.depth) +/// selectedColor : the color when checked (default: theme.accent) +/// +class NeumorphicCheckboxStyle { + final double selectedDepth; + final double unselectedDepth; + final bool disableDepth; + final double selectedIntensity; + final double unselectedIntensity; + final Color selectedColor; + final Color disabledColor; + final LightSource lightSource; + final NeumorphicBorder border; + final NeumorphicBoxShape boxShape; + + const NeumorphicCheckboxStyle({ + this.selectedDepth, + this.border = const NeumorphicBorder.none(), + this.selectedColor, + this.unselectedDepth, + this.disableDepth, + this.lightSource, + this.disabledColor, + this.boxShape, + this.selectedIntensity = 1, + this.unselectedIntensity = 0.7, + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicCheckboxStyle && + runtimeType == other.runtimeType && + selectedDepth == other.selectedDepth && + border == other.border && + unselectedDepth == other.unselectedDepth && + disableDepth == other.disableDepth && + selectedIntensity == other.selectedIntensity && + lightSource == other.lightSource && + unselectedIntensity == other.unselectedIntensity && + boxShape == other.boxShape && + selectedColor == other.selectedColor && + disabledColor == other.disabledColor; + + @override + int get hashCode => + selectedDepth.hashCode ^ + unselectedDepth.hashCode ^ + border.hashCode ^ + lightSource.hashCode ^ + disableDepth.hashCode ^ + selectedIntensity.hashCode ^ + unselectedIntensity.hashCode ^ + boxShape.hashCode ^ + selectedColor.hashCode ^ + disabledColor.hashCode; +} + +/// A Neumorphic Checkbox +/// +/// takes a NeumorphicCheckboxStyle as `style` +/// takes the current checked state as `value` +/// +/// notifies the parent when user interact with this widget with `onChanged` +/// +/// ``` +/// bool check1 = false; +/// bool check2 = false; +/// bool check3 = false; +/// +/// Widget _buildChecks() { +/// return Row( +/// children: [ +/// +/// NeumorphicCheckbox( +/// value: check1, +/// onChanged: (value) { +/// setState(() { +/// check1 = value; +/// }); +/// }, +/// ), +/// +/// NeumorphicCheckbox( +/// value: check2, +/// onChanged: (value) { +/// setState(() { +/// check2 = value; +/// }); +/// }, +/// ), +/// +/// NeumorphicCheckbox( +/// value: check3, +/// onChanged: (value) { +/// setState(() { +/// check3 = value; +/// }); +/// }, +/// ), +/// +/// ], +/// ); +/// } +/// ``` +/// +@immutable +class NeumorphicCheckbox extends StatelessWidget { + final bool value; + final NeumorphicCheckboxStyle style; + final NeumorphicCheckboxListener onChanged; + final isEnabled; + final EdgeInsets padding; + final EdgeInsets margin; + final Duration duration; + final Curve curve; + + NeumorphicCheckbox({ + this.style = const NeumorphicCheckboxStyle(), + @required this.value, + @required this.onChanged, + this.curve = Neumorphic.DEFAULT_CURVE, + this.duration = Neumorphic.DEFAULT_DURATION, + this.padding = const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), + this.margin = const EdgeInsets.all(0), + this.isEnabled = true, + }); + + bool get isSelected => this.value; + + void _onClick() { + this.onChanged(!this.value); + } + + @override + Widget build(BuildContext context) { + final NeumorphicThemeData theme = NeumorphicTheme.currentTheme(context); + final selectedColor = this.style.selectedColor ?? theme.accentColor; + + final double selectedDepth = + -1 * (this.style.selectedDepth ?? theme.depth).abs(); + final double unselectedDepth = + (this.style.unselectedDepth ?? theme.depth).abs(); + final double selectedIntensity = + (this.style.selectedIntensity ?? theme.intensity) + .abs() + .clamp(Neumorphic.MIN_INTENSITY, Neumorphic.MAX_INTENSITY); + final double unselectedIntensity = this + .style + .unselectedIntensity + .clamp(Neumorphic.MIN_INTENSITY, Neumorphic.MAX_INTENSITY); + + double depth = isSelected ? selectedDepth : unselectedDepth; + if (!this.isEnabled) { + depth = 0; + } + + Color color = isSelected ? selectedColor : null; + if (!this.isEnabled) { + color = null; + } + + Color iconColor = isSelected ? theme.baseColor : selectedColor; + if (!this.isEnabled) { + iconColor = theme.disabledColor; + } + + return NeumorphicButton( + padding: this.padding, + pressed: isSelected, + margin: this.margin, + duration: this.duration, + curve: this.curve, + onPressed: () { + if (this.isEnabled) { + _onClick(); + } + }, + drawSurfaceAboveChild: true, + minDistance: selectedDepth.abs(), + child: Icon( + NeumorphicIcons.check, + color: iconColor, + size: 20.0, + ), + style: NeumorphicStyle( + boxShape: this.style.boxShape, + border: this.style.border, + color: color, + depth: depth, + lightSource: this.style.lightSource ?? theme.lightSource, + disableDepth: this.style.disableDepth, + intensity: isSelected ? selectedIntensity : unselectedIntensity, + shape: NeumorphicShape.flat, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/clipper/neumorphic_box_shape_clipper.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/clipper/neumorphic_box_shape_clipper.dart new file mode 100644 index 00000000..35236c23 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/clipper/neumorphic_box_shape_clipper.dart @@ -0,0 +1,22 @@ +import 'package:flutter/widgets.dart'; + +import '../../neumorphic_box_shape.dart'; + +class NeumorphicBoxShapeClipper extends StatelessWidget { + final NeumorphicBoxShape shape; + final Widget child; + + NeumorphicBoxShapeClipper({@required this.shape, this.child}); + + CustomClipper _getClipper(NeumorphicBoxShape shape) { + return shape.customShapePathProvider; + } + + @override + Widget build(BuildContext context) { + return ClipPath( + clipper: _getClipper(this.shape), + child: child, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/close_button.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/close_button.dart new file mode 100644 index 00000000..e5e5058d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/close_button.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; + +class NeumorphicCloseButton extends StatelessWidget { + final VoidCallback onPressed; + final NeumorphicStyle style; + final EdgeInsets padding; + + const NeumorphicCloseButton({ + Key key, + this.onPressed, + this.style, + this.padding, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final nThemeIcons = NeumorphicTheme.of(context).current.appBarTheme.icons; + return NeumorphicButton( + style: style, + padding: padding, + tooltip: MaterialLocalizations.of(context).closeButtonTooltip, + child: nThemeIcons.closeIcon, + onPressed: onPressed ?? () => Navigator.maybePop(context), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/container.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/container.dart new file mode 100644 index 00000000..22cbbeca --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/container.dart @@ -0,0 +1,150 @@ +import 'package:flutter/material.dart' as material; +import 'package:flutter/widgets.dart'; + +import '../neumorphic_box_shape.dart'; +import '../decoration/neumorphic_decorations.dart'; +import '../theme/neumorphic_theme.dart'; +import 'clipper/neumorphic_box_shape_clipper.dart'; + +export '../neumorphic_box_shape.dart'; +export '../decoration/neumorphic_decorations.dart'; +export '../theme/neumorphic_theme.dart'; + +/// The main container of the Neumorphic UI KIT +/// it takes a Neumorphic style @see [NeumorphicStyle] +/// +/// it's clipped using a [NeumorphicBoxShape] (circle, roundrect, stadium) +/// +/// It can be, depending on its [NeumorphicStyle.shape] : [NeumorphicShape.concave], [NeumorphicShape.convex], [NeumorphicShape.flat] +/// +/// if [NeumorphicStyle.depth] < 0 ----> use the emboss shape +/// +/// The container animates any change for you, with [duration] ! (including style / theme / size / etc.) +/// +/// [drawSurfaceAboveChild] enable to draw emboss, concave, convex effect above this widget child +/// +/// drawSurfaceAboveChild - UseCase 1 : +/// +/// put an image inside a neumorphic(concave) : +/// drawSurfaceAboveChild=false -> the concave effect is below the image +/// drawSurfaceAboveChild=true -> the concave effect is above the image, the image seems concave +/// +/// drawSurfaceAboveChild - UseCase 2 : +/// put an image inside a neumorphic(emboss) : +/// drawSurfaceAboveChild=false -> the emboss effect is below the image -> not visible +/// drawSurfaceAboveChild=true -> the emboss effeect effect is above the image -> visible +/// +@immutable +class Neumorphic extends StatelessWidget { + static const DEFAULT_DURATION = const Duration(milliseconds: 100); + static const DEFAULT_CURVE = Curves.linear; + + static const double MIN_DEPTH = -20.0; + static const double MAX_DEPTH = 20.0; + + static const double MIN_INTENSITY = 0.0; + static const double MAX_INTENSITY = 1.0; + + static const double MIN_CURVE = 0.0; + static const double MAX_CURVE = 1.0; + + final Widget child; + + final NeumorphicStyle style; + final TextStyle textStyle; + final EdgeInsets padding; + final EdgeInsets margin; + final Curve curve; + final Duration duration; + final bool + drawSurfaceAboveChild; //if true => boxDecoration & foreground decoration, else => boxDecoration does all the work + + Neumorphic({ + Key key, + this.child, + this.duration = Neumorphic.DEFAULT_DURATION, + this.curve = Neumorphic.DEFAULT_CURVE, + this.style, + this.textStyle, + this.margin = const EdgeInsets.all(0), + this.padding = const EdgeInsets.all(0), + this.drawSurfaceAboveChild = true, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = NeumorphicTheme.currentTheme(context); + final NeumorphicStyle style = (this.style ?? NeumorphicStyle()) + .copyWithThemeIfNull(theme) + .applyDisableDepth(); + + return _NeumorphicContainer( + padding: this.padding, + textStyle: this.textStyle, + drawSurfaceAboveChild: this.drawSurfaceAboveChild, + duration: this.duration, + style: style, + curve: this.curve, + margin: this.margin, + child: this.child, + ); + } +} + +class _NeumorphicContainer extends StatelessWidget { + final NeumorphicStyle style; + final TextStyle textStyle; + final Widget child; + final EdgeInsets margin; + final Duration duration; + final Curve curve; + final bool drawSurfaceAboveChild; + final EdgeInsets padding; + + _NeumorphicContainer({ + Key key, + this.child, + this.textStyle, + @required this.padding, + @required this.margin, + @required this.duration, + @required this.curve, + @required this.style, + @required this.drawSurfaceAboveChild, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final shape = this.style.boxShape ?? NeumorphicBoxShape.rect(); + + return DefaultTextStyle( + style: this.textStyle ?? material.Theme.of(context).textTheme.bodyText2, + child: AnimatedContainer( + margin: this.margin, + duration: this.duration, + curve: this.curve, + child: NeumorphicBoxShapeClipper( + shape: shape, + child: Padding( + padding: this.padding, + child: this.child, + ), + ), + foregroundDecoration: NeumorphicDecoration( + isForeground: true, + renderingByPath: shape.customShapePathProvider.oneGradientPerPath, + splitBackgroundForeground: this.drawSurfaceAboveChild, + style: this.style, + shape: shape, + ), + decoration: NeumorphicDecoration( + isForeground: false, + renderingByPath: shape.customShapePathProvider.oneGradientPerPath, + splitBackgroundForeground: this.drawSurfaceAboveChild, + style: this.style, + shape: shape, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/floating_action_button.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/floating_action_button.dart new file mode 100644 index 00000000..a2351896 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/floating_action_button.dart @@ -0,0 +1,43 @@ +import '../../flutter_neumorphic.dart'; + +const BoxConstraints _kSizeConstraints = BoxConstraints.tightFor( + width: 56.0, + height: 56.0, +); + +const BoxConstraints _kMiniSizeConstraints = BoxConstraints.tightFor( + width: 40.0, + height: 40.0, +); + +class NeumorphicFloatingActionButton extends StatelessWidget { + final Widget child; + final NeumorphicButtonClickListener onPressed; + final bool mini; + final String tooltip; + final NeumorphicStyle style; + + const NeumorphicFloatingActionButton({ + Key key, + this.mini = false, + this.style, + this.tooltip, + @required this.child, + @required this.onPressed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return ConstrainedBox( + constraints: this.mini ? _kMiniSizeConstraints : _kSizeConstraints, + child: NeumorphicButton( + padding: EdgeInsets.all(0), + onPressed: this.onPressed, + tooltip: this.tooltip, + style: this.style ?? + NeumorphicTheme.currentTheme(context).appBarTheme.buttonStyle, + child: this.child, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/icon.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/icon.dart new file mode 100644 index 00000000..b00a7430 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/icon.dart @@ -0,0 +1,41 @@ +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; +import '../theme/neumorphic_theme.dart'; + +export '../decoration/neumorphic_decorations.dart'; +export '../neumorphic_box_shape.dart'; +export '../theme/neumorphic_theme.dart'; + +@immutable +class NeumorphicIcon extends StatelessWidget { + final IconData icon; + final NeumorphicStyle style; + final Curve curve; + final double size; + final Duration duration; + + NeumorphicIcon( + this.icon, { + Key key, + this.duration = Neumorphic.DEFAULT_DURATION, + this.curve = Neumorphic.DEFAULT_CURVE, + this.style, + this.size = 20, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return NeumorphicText( + String.fromCharCode(icon.codePoint), + textStyle: NeumorphicTextStyle( + fontSize: size, + fontFamily: icon.fontFamily, + package: icon.fontPackage, + ), + duration: this.duration, + style: style, + curve: this.curve, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/indicator.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/indicator.dart new file mode 100644 index 00000000..d01b480c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/indicator.dart @@ -0,0 +1,251 @@ +import 'dart:ui'; + +import 'package:flutter/widgets.dart'; + +import 'container.dart'; + +/// A Style to customize the [NeumorphicIndicator] +/// +/// the gradient will use [accent] and [variant] +/// +/// the gradient shape will be a roundrect, using [borderRadius] +/// +/// you can define a custom [depth] for the roundrect +/// +/// you can update the gradient orientation using [gradientStart] & [gradientEnd] +/// +class IndicatorStyle { + //final double borderRadius; + final double depth; + final bool disableDepth; + final Color accent; + final Color variant; + final LightSource lightSource; + + final AlignmentGeometry gradientStart; + final AlignmentGeometry gradientEnd; + + const IndicatorStyle({ + this.depth = -4, + this.accent, + this.lightSource, + this.variant, + this.disableDepth, + this.gradientStart, + this.gradientEnd, + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is IndicatorStyle && + runtimeType == other.runtimeType && + depth == other.depth && + disableDepth == other.disableDepth && + accent == other.accent && + lightSource == other.lightSource && + variant == other.variant && + gradientStart == other.gradientStart && + gradientEnd == other.gradientEnd; + + @override + int get hashCode => + depth.hashCode ^ + disableDepth.hashCode ^ + accent.hashCode ^ + variant.hashCode ^ + lightSource.hashCode ^ + gradientStart.hashCode ^ + gradientEnd.hashCode; +} + +enum NeumorphicIndicatorOrientation { vertical, horizontal } + +/// An indicator is a horizontal / vertical bar that display a percentage +/// +/// Like a ProgressBar, but with an [orientation] @see [NeumorphicIndicatorOrientation] +/// +/// it takes a [padding], a [width] and [height] +/// +/// the current accented roundrect use the [percent] field +/// +/// Widget _buildIndicators() { +/// +/// final width = 14.0; +/// +/// return SizedBox( +/// height: 130, +/// child: Row( +/// mainAxisAlignment: MainAxisAlignment.center, +/// children: [ +/// NeumorphicIndicator( +/// width: width, +/// percent: 0.4, +/// ), +/// SizedBox(width: 10), +/// NeumorphicIndicator( +/// width: width, +/// percent: 0.2, +/// ), +/// SizedBox(width: 10), +/// NeumorphicIndicator( +/// width: width, +/// percent: 0.5, +/// ), +/// SizedBox(width: 10), +/// NeumorphicIndicator( +/// width: width, +/// percent: 1, +/// ), +/// ], +/// ), +/// ); +/// } +/// +@immutable +class NeumorphicIndicator extends StatefulWidget { + final double percent; + final double width; + final double height; + final EdgeInsets padding; + final NeumorphicIndicatorOrientation orientation; + final IndicatorStyle style; + final Duration duration; + final Curve curve; + + const NeumorphicIndicator({ + Key key, + this.percent = 0.5, + this.orientation = NeumorphicIndicatorOrientation.vertical, + this.height = double.maxFinite, + this.padding = EdgeInsets.zero, + this.width = double.maxFinite, + this.style = const IndicatorStyle(), + this.duration = const Duration(milliseconds: 300), + this.curve = Curves.easeOutCubic, + }) : super(key: key); + + @override + createState() => _NeumorphicIndicatorState(); + + @override + // ignore: invalid_override_of_non_virtual_member + bool operator ==(Object other) => + identical(this, other) || + super == other && + other is NeumorphicIndicator && + runtimeType == other.runtimeType && + percent == other.percent && + width == other.width && + height == other.height && + padding == other.padding && + orientation == other.orientation && + style == other.style && + duration == other.duration && + curve == other.curve; + + @override + // ignore: invalid_override_of_non_virtual_member + int get hashCode => + super.hashCode ^ + percent.hashCode ^ + width.hashCode ^ + height.hashCode ^ + padding.hashCode ^ + orientation.hashCode ^ + style.hashCode ^ + duration.hashCode ^ + curve.hashCode; +} + +class _NeumorphicIndicatorState extends State + with TickerProviderStateMixin { + double oldPercent = 0; + AnimationController _controller; + Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this, duration: widget.duration); + _animation = Tween(begin: widget.percent, end: oldPercent) + .animate(_controller); + } + + @override + void didUpdateWidget(NeumorphicIndicator oldWidget) { + if (oldWidget.percent != widget.percent) { + _controller.reset(); + oldPercent = oldWidget.percent; + _animation = Tween(begin: oldPercent, end: widget.percent) + .animate(CurvedAnimation(parent: _controller, curve: widget.curve)); + _controller.forward(); + } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final NeumorphicThemeData theme = NeumorphicTheme.currentTheme(context); + return SizedBox( + height: widget.height, + width: widget.width, + child: Neumorphic( + padding: EdgeInsets.zero, + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.stadium(), + lightSource: widget.style.lightSource ?? theme.lightSource, + disableDepth: widget.style.disableDepth, + depth: widget.style.depth, + shape: NeumorphicShape.flat, + ), + child: AnimatedBuilder( + animation: _animation, + builder: (_, __) { + return FractionallySizedBox( + heightFactor: widget.orientation == + NeumorphicIndicatorOrientation.vertical + ? _animation.value + : 1, + widthFactor: widget.orientation == + NeumorphicIndicatorOrientation.horizontal + ? _animation.value + : 1, + alignment: widget.orientation == + NeumorphicIndicatorOrientation.horizontal + ? Alignment.centerLeft + : Alignment.bottomCenter, + child: Padding( + padding: widget.padding, + child: Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.stadium(), + lightSource: + widget.style.lightSource ?? theme.lightSource, + ), + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: + widget.style.gradientStart ?? Alignment.topCenter, + end: widget.style.gradientEnd ?? Alignment.bottomCenter, + colors: [ + widget.style.accent ?? theme.accentColor, + widget.style.variant ?? theme.variantColor + ], + ), + )), + ), + ), + ); + }), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/progress.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/progress.dart new file mode 100644 index 00000000..09a13799 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/progress.dart @@ -0,0 +1,366 @@ +import 'dart:ui'; + +import 'package:flutter/widgets.dart'; + +import 'container.dart'; + +/// A style to customize the [NeumorphicProgress] +/// +/// the gradient will use [accent] and [variant] +/// +/// the gradient shape will be a roundrect, using [borderRadius] +/// +/// you can define a custom [depth] for the roundrect +/// +/// you can update the gradient orientation using [progressGradientStart] & [progressGradientEnd] +/// +class ProgressStyle { + final double depth; + final BorderRadius borderRadius; + final BorderRadius gradientBorderRadius; + final Color accent; + final Color variant; + final LightSource lightSource; + + final AlignmentGeometry progressGradientStart; + final AlignmentGeometry progressGradientEnd; + final bool disableDepth; + + final NeumorphicBorder border; + + const ProgressStyle({ + this.depth = 0, + this.disableDepth = false, + this.borderRadius = const BorderRadius.all(Radius.circular(10.0)), + this.gradientBorderRadius, + this.accent, + this.lightSource, + this.progressGradientStart, + this.progressGradientEnd, + this.variant, + this.border = const NeumorphicBorder.none(), + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ProgressStyle && + runtimeType == other.runtimeType && + depth == other.depth && + border == other.border && + disableDepth == other.disableDepth && + lightSource == other.lightSource && + borderRadius == other.borderRadius && + gradientBorderRadius == other.gradientBorderRadius && + accent == other.accent && + variant == other.variant && + progressGradientStart == other.progressGradientStart && + progressGradientEnd == other.progressGradientEnd; + + @override + int get hashCode => + depth.hashCode ^ + disableDepth.hashCode ^ + borderRadius.hashCode ^ + lightSource.hashCode ^ + gradientBorderRadius.hashCode ^ + border.hashCode ^ + accent.hashCode ^ + variant.hashCode ^ + progressGradientStart.hashCode ^ + progressGradientEnd.hashCode; +} + +/// A widget that shows progress along a line. +/// +/// NeumorphicProgress is determinate. +/// +/// Determinate progress indicators have a specific value at each point in time, +/// and the value should increase monotonically from 0.0 to 1.0, at which time the indicator is complete. +/// To create a determinate progress indicator, use a non-null value between 0.0 and 1.0. +/// +/// ``` +/// NeumorphicProgress( +/// height: 15, +/// percent: 0.55, +/// ); +/// ``` +/// +class NeumorphicProgress extends StatefulWidget { + final double _percent; + final double height; + final Duration duration; + final ProgressStyle style; + final Curve curve; + + const NeumorphicProgress( + {Key key, + double percent, + this.height = 10, + this.duration = const Duration(milliseconds: 300), + this.style = const ProgressStyle(), + this.curve = Curves.easeOutCubic}) + : this._percent = percent, + super(key: key); + + @override + _NeumorphicProgressState createState() => _NeumorphicProgressState(); + + double get percent => _percent?.clamp(0, 1); + + @override + // ignore: invalid_override_of_non_virtual_member + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicProgress && + runtimeType == other.runtimeType && + percent == other.percent && + height == other.height && + style == other.style && + curve == other.curve; + + @override + // ignore: invalid_override_of_non_virtual_member + int get hashCode => + percent.hashCode ^ height.hashCode ^ style.hashCode ^ curve.hashCode; +} + +class _NeumorphicProgressState extends State + with TickerProviderStateMixin { + double oldPercent = 0; + + AnimationController _controller; + Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this, duration: widget.duration); + _animation = Tween(begin: widget.percent, end: oldPercent) + .animate(_controller); + } + + @override + void didUpdateWidget(NeumorphicProgress oldWidget) { + if (oldWidget.percent != widget.percent) { + _controller.reset(); + oldPercent = oldWidget.percent; + _animation = Tween(begin: oldPercent, end: widget.percent) + .animate(CurvedAnimation(parent: _controller, curve: widget.curve)); + _controller.forward(); + } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + //print("widget.style.depth: ${widget.style.depth}"); + + final NeumorphicThemeData theme = NeumorphicTheme.currentTheme(context); + return SizedBox( + height: widget.height, + child: FractionallySizedBox( + widthFactor: 1, + //width: constraints.maxWidth, + child: Neumorphic( + padding: EdgeInsets.zero, + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect(widget.style.borderRadius), + disableDepth: widget.style.disableDepth, + border: widget.style.border, + depth: widget.style.depth, + shape: NeumorphicShape.flat, + ), + child: AnimatedBuilder( + animation: _controller, + builder: (_, __) { + return FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: _animation.value, + child: _GradientProgress( + borderRadius: widget.style.gradientBorderRadius ?? + widget.style.borderRadius, + begin: widget.style.progressGradientStart ?? + Alignment.centerLeft, + end: widget.style.progressGradientEnd ?? + Alignment.centerRight, + colors: [ + widget.style.variant ?? theme.variantColor, + widget.style.accent ?? theme.accentColor, + ], + ), + ); + }), + ), + ), + ); + } +} + +/// A widget that shows progress along a line. +/// +/// NeumorphicProgressIndeterminate is indeterminate. +/// +/// You can provide a custom animation [duration] +/// +/// Indeterminate progress indicators do not have a specific value at each point in time and instead indicate that progress is being made +/// without indicating how much progress remains. To create an indeterminate progress indicator, use a null value. +/// +/// ``` +/// NeumorphicProgressIndeterminate( +/// height: 15, +/// ); +/// +/// ``` +/// +class NeumorphicProgressIndeterminate extends StatefulWidget { + final double height; + final ProgressStyle style; + final Duration duration; + final bool reverse; + final Curve curve; + + const NeumorphicProgressIndeterminate({ + Key key, + this.height = 10, + this.style = const ProgressStyle(), + this.duration = const Duration(seconds: 3), + this.reverse = false, + this.curve = Curves.easeInOut, + }) : super(key: key); + + @override + createState() => _NeumorphicProgressIndeterminateState(); + + @override + // ignore: invalid_override_of_non_virtual_member + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicProgressIndeterminate && + runtimeType == other.runtimeType && + height == other.height && + style == other.style && + duration == other.duration && + reverse == other.reverse && + curve == other.curve; + + @override + // ignore: invalid_override_of_non_virtual_member + int get hashCode => + height.hashCode ^ + style.hashCode ^ + duration.hashCode ^ + reverse.hashCode ^ + curve.hashCode; +} + +class _NeumorphicProgressIndeterminateState + extends State + with TickerProviderStateMixin { + AnimationController _controller; + Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController(vsync: this, duration: widget.duration); + _animation = Tween(begin: 0, end: 1) + .animate(CurvedAnimation(parent: _controller, curve: widget.curve)); + _loop(); + } + + void _loop() async { + try { + await _controller + .repeat(min: 0, max: 1, reverse: widget.reverse) + .orCancel; + } on TickerCanceled {} + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final NeumorphicThemeData theme = NeumorphicTheme.currentTheme(context); + + return FractionallySizedBox( + widthFactor: 1, + child: SizedBox( + height: widget.height, + child: Neumorphic( + padding: EdgeInsets.zero, + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect(widget.style.borderRadius), + lightSource: widget.style.lightSource ?? theme.lightSource, + border: widget.style.border, + disableDepth: widget.style.disableDepth, + depth: widget.style.depth, + shape: NeumorphicShape.flat, + ), + child: LayoutBuilder(builder: (context, constraints) { + return AnimatedBuilder( + animation: _animation, + builder: (_, __) { + return Padding( + padding: EdgeInsets.only( + left: constraints.maxWidth * _animation.value), + child: FractionallySizedBox( + heightFactor: 1, + alignment: Alignment.centerLeft, + widthFactor: _animation.value, + child: _GradientProgress( + borderRadius: widget.style.gradientBorderRadius ?? + widget.style.borderRadius, + begin: widget.style.progressGradientStart ?? + Alignment.centerLeft, + end: widget.style.progressGradientEnd ?? + Alignment.centerRight, + colors: [ + widget.style.accent ?? theme.accentColor, + widget.style.variant ?? theme.variantColor + ], + ), + ), + ); + }); + }), + ), + ), + ); + } +} + +class _GradientProgress extends StatelessWidget { + final AlignmentGeometry begin; + final AlignmentGeometry end; + final List colors; + final BorderRadius borderRadius; + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: this.borderRadius, + gradient: LinearGradient( + begin: this.begin, end: this.end, colors: this.colors), + ), + ); + } + + const _GradientProgress({ + @required this.begin, + @required this.end, + @required this.colors, + @required this.borderRadius, + }); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/radio.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/radio.dart new file mode 100644 index 00000000..0a307f5d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/radio.dart @@ -0,0 +1,233 @@ +import 'package:flutter/widgets.dart'; + +import '../neumorphic_box_shape.dart'; +import '../theme/neumorphic_theme.dart'; +import 'button.dart'; +import 'container.dart'; + +typedef void NeumorphicRadioListener(T value); + +/// A Style used to customize a [NeumorphicRadio] +/// +/// [selectedDepth] : the depth when checked +/// [unselectedDepth] : the depth when unchecked (default : theme.depth) +/// +/// [intensity] : a customizable neumorphic intensity for this widget +/// +/// [boxShape] : a customizable neumorphic boxShape for this widget +/// @see [NeumorphicBoxShape] +/// +/// [shape] : a customizable neumorphic shape for this widget +/// @see [NeumorphicShape] (concave, convex, flat) +/// +class NeumorphicRadioStyle { + final double selectedDepth; + final double unselectedDepth; + final bool disableDepth; + + final Color selectedColor; //null for default + final Color unselectedColor; //null for unchanged color + + final double intensity; + final NeumorphicShape shape; + + final NeumorphicBorder border; + final NeumorphicBoxShape boxShape; + + final LightSource lightSource; + + const NeumorphicRadioStyle({ + this.selectedDepth, + this.unselectedDepth, + this.selectedColor, + this.unselectedColor, + this.lightSource, + this.disableDepth = false, + this.boxShape, + this.border = const NeumorphicBorder.none(), + this.intensity, + this.shape, + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicRadioStyle && + runtimeType == other.runtimeType && + disableDepth == other.disableDepth && + lightSource == other.lightSource && + border == other.border && + selectedDepth == other.selectedDepth && + unselectedDepth == other.unselectedDepth && + selectedColor == other.selectedColor && + unselectedColor == other.unselectedColor && + boxShape == other.boxShape && + intensity == other.intensity && + shape == other.shape; + + @override + int get hashCode => + disableDepth.hashCode ^ + selectedDepth.hashCode ^ + lightSource.hashCode ^ + selectedColor.hashCode ^ + unselectedColor.hashCode ^ + boxShape.hashCode ^ + border.hashCode ^ + unselectedDepth.hashCode ^ + intensity.hashCode ^ + shape.hashCode; +} + +/// A Neumorphic Radio +/// +/// It takes a `value` and a `groupValue` +/// if (value == groupValue) => checked +/// +/// takes a NeumorphicRadioStyle as `style` +/// +/// notifies the parent when user interact with this widget with `onChanged` +/// +/// ``` +/// int _groupValue; +/// +/// Widget _buildRadios() { +/// return Row( +/// children: [ +/// +/// NeumorphicRadio( +/// child: SizedBox( +/// height: 50, +/// width: 50, +/// child: Center( +/// child: Text("1"), +/// ), +/// ), +/// value: 1, +/// groupValue: _groupValue, +/// onChanged: (value) { +/// setState(() { +/// _groupValue = value; +/// }); +/// }, +/// ), +/// +/// NeumorphicRadio( +/// child: SizedBox( +/// height: 50, +/// width: 50, +/// child: Center( +/// child: Text("2"), +/// ), +/// ), +/// value: 2, +/// groupValue: _groupValue, +/// onChanged: (value) { +/// setState(() { +/// _groupValue = value; +/// }); +/// }, +/// ), +/// +/// NeumorphicRadio( +/// child: SizedBox( +/// height: 50, +/// width: 50, +/// child: Center( +/// child: Text("3"), +/// ), +/// ), +/// value: 3, +/// groupValue: _groupValue, +/// onChanged: (value) { +/// setState(() { +/// _groupValue = value; +/// }); +/// }, +/// ), +/// +/// ], +/// ); +/// } +/// ``` +/// +@immutable +class NeumorphicRadio extends StatelessWidget { + final Widget child; + final T value; + final T groupValue; + final EdgeInsets padding; + final NeumorphicRadioStyle style; + final NeumorphicRadioListener onChanged; + final bool isEnabled; + + final Duration duration; + final Curve curve; + + NeumorphicRadio({ + this.child, + this.style = const NeumorphicRadioStyle(), + this.value, + this.curve = Neumorphic.DEFAULT_CURVE, + this.duration = Neumorphic.DEFAULT_DURATION, + this.padding = EdgeInsets.zero, + this.groupValue, + this.onChanged, + this.isEnabled = true, + }); + + bool get isSelected => this.value != null && this.value == this.groupValue; + + void _onClick() { + if (this.onChanged != null) { + if (this.value == this.groupValue) { + //unselect + this.onChanged(null); + } else { + this.onChanged(this.value); + } + } + } + + @override + Widget build(BuildContext context) { + final NeumorphicThemeData theme = NeumorphicTheme.currentTheme(context); + + final double selectedDepth = + -1 * (this.style.selectedDepth ?? theme.depth).abs(); + final double unselectedDepth = + (this.style.unselectedDepth ?? theme.depth).abs(); + + double depth = isSelected ? selectedDepth : unselectedDepth; + if (!this.isEnabled) { + depth = 0; + } + + final Color unselectedColor = this.style.unselectedColor ?? theme.baseColor; + final Color selectedColor = this.style.selectedColor ?? unselectedColor; + + final Color color = isSelected ? selectedColor : unselectedColor; + + return NeumorphicButton( + onPressed: () { + _onClick(); + }, + duration: this.duration, + curve: this.curve, + padding: this.padding, + pressed: isSelected, + minDistance: selectedDepth, + child: this.child, + style: NeumorphicStyle( + border: this.style.border, + color: color, + boxShape: this.style.boxShape, + lightSource: this.style.lightSource ?? theme.lightSource, + disableDepth: this.style.disableDepth, + intensity: this.style.intensity, + depth: depth, + shape: this.style.shape ?? NeumorphicShape.flat, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/range_slider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/range_slider.dart new file mode 100644 index 00000000..e9aa2a9f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/range_slider.dart @@ -0,0 +1,317 @@ +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; + +import 'container.dart'; +import 'progress.dart'; + +typedef void NeumorphicRangeSliderLowListener(double percent); +typedef void NeumorphicRangeSliderHighListener(double percent); + +/// A style to customize the [NeumorphicSlider] +/// +/// the gradient will use [accent] and [variant] +/// +/// the gradient shape will be a roundrect, using [borderRadius] +/// +/// you can define a custom [depth] for the roundrect +/// +@immutable +class RangeSliderStyle { + final double depth; + final bool disableDepth; + final BorderRadius borderRadius; + final Color accent; + final Color variant; + final LightSource lightSource; + + final NeumorphicBorder border; + final NeumorphicBorder thumbBorder; + + const RangeSliderStyle({ + this.depth = 0, + this.disableDepth = false, + this.borderRadius = const BorderRadius.all(Radius.circular(10)), + this.accent, + this.lightSource, + this.variant, + this.border = const NeumorphicBorder.none(), + this.thumbBorder = const NeumorphicBorder.none(), + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is RangeSliderStyle && + runtimeType == other.runtimeType && + depth == other.depth && + lightSource == other.lightSource && + disableDepth == other.disableDepth && + borderRadius == other.borderRadius && + thumbBorder == other.thumbBorder && + border == other.border && + accent == other.accent && + variant == other.variant; + + @override + int get hashCode => + depth.hashCode ^ + disableDepth.hashCode ^ + borderRadius.hashCode ^ + lightSource.hashCode ^ + accent.hashCode ^ + border.hashCode ^ + thumbBorder.hashCode ^ + variant.hashCode; +} + +/// A Neumorphic Design range slider. +/// +/// Used to select a range of values. +/// +/// +/// listeners : [onChangedLow], [onChangeHigh] +/// +/// ``` +/// //in a statefull widget +/// +/// double minPrice = 20; +/// double maxPrice = 90; +/// +/// Widget _buildSlider() { +/// return Row( +/// children: [ +/// +/// Flexible( +/// child: NeumorphicRangeSlider( +/// valueLow: minPrice, +/// valueHigh: maxPrice, +/// min: 18, +/// max: 99, +/// onChangedLow: (value) { +/// setState(() { +/// minPrice = value; +/// }); +/// }, +/// onChangeHigh: (value) { +/// setState(() { +/// maxPrice = value; +/// }); +/// }, +/// ), +/// ), +/// Text( +/// "${minPrice.round()} - ${maxPrice.round()}", +/// style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), +/// ), +/// +/// ], +/// ); +/// } +/// ``` +/// +@immutable +class NeumorphicRangeSlider extends StatefulWidget { + final RangeSliderStyle style; + final double min; + final double valueLow; + final double valueHigh; + final double max; + final double height; + final double sliderHeight; + final NeumorphicRangeSliderLowListener onChangedLow; + final NeumorphicRangeSliderHighListener onChangeHigh; + final Function(ActiveThumb) onPanStarted; + final Function(ActiveThumb) onPanEnded; + final Widget thumb; + + NeumorphicRangeSlider({ + Key key, + this.style = const RangeSliderStyle(), + this.min = 0, + this.max = 10, + this.valueLow = 0, + this.valueHigh = 10, + this.height = 15, + this.onChangedLow, + this.onChangeHigh, + this.onPanStarted, + this.onPanEnded, + this.sliderHeight, + this.thumb, + }); + + double get percentLow => (((valueLow.clamp(min, max)) - min) / ((max - min))); + + double get percentHigh => + (((valueHigh.clamp(min, max)) - min) / ((max - min))); + + @override + createState() => _NeumorphicRangeSliderState(); +} + +class _NeumorphicRangeSliderState extends State { + ActiveThumb _activeThumb; + bool _canChangeActiveThumb; + + @override + Widget build(BuildContext context) { + return LayoutBuilder(builder: (context, constraints) { + return _widget(context, constraints); + }); + } + + Widget _widget(BuildContext context, BoxConstraints constraints) { + double thumbSize = widget.height * 1.5; + + Function panUpdate = (DragUpdateDetails details) { + final tapPos = details.localPosition; + final newPercent = tapPos.dx / constraints.maxWidth; + final newValue = ((widget.min + (widget.max - widget.min) * newPercent)) + .clamp(widget.min, widget.max); + + switch (_activeThumb) { + case ActiveThumb.low: + if (newValue < widget.valueHigh) { + _canChangeActiveThumb = false; + if (widget.onChangedLow != null) { + widget.onChangedLow(newValue); + } + } else if (_canChangeActiveThumb && details.delta.dx > 0) { + _canChangeActiveThumb = false; + _activeThumb = ActiveThumb.high; + } + break; + case ActiveThumb.high: + if (newValue > widget.valueLow) { + _canChangeActiveThumb = false; + if (widget.onChangeHigh != null) { + widget.onChangeHigh(newValue); + } + } else if (_canChangeActiveThumb && details.delta.dx < 0) { + _canChangeActiveThumb = false; + _activeThumb = ActiveThumb.low; + } + break; + } + }; + + return Stack( + alignment: Alignment.center, + children: [ + Padding( + padding: EdgeInsets.only(left: thumbSize / 2, right: thumbSize / 2), + child: _generateSlider(context), + ), + Align( + alignment: Alignment( + //because left = -1 & right = 1, so the "width" = 2, and minValue = 1 + (widget.percentLow * 2) - 1, + 0), + child: GestureDetector( + onHorizontalDragStart: (DragStartDetails details) { + _canChangeActiveThumb = true; + _activeThumb = ActiveThumb.low; + if (widget.onPanStarted != null) { + widget.onPanStarted(_activeThumb); + } + }, + onHorizontalDragUpdate: (DragUpdateDetails details) { + panUpdate(details); + }, + onHorizontalDragEnd: (details) { + if (widget.onPanEnded != null) { + widget.onPanEnded(_activeThumb); + } + }, + child: widget.thumb ?? + _generateThumb(context, thumbSize, widget.style.variant)), + ), + Align( + alignment: Alignment( + //because left = -1 & right = 1, so the "width" = 2, and minValue = 1 + (widget.percentHigh * 2) - 1, + 0), + child: GestureDetector( + onHorizontalDragStart: (DragStartDetails details) { + _canChangeActiveThumb = true; + _activeThumb = ActiveThumb.high; + if (widget.onPanStarted != null) { + widget.onPanStarted(_activeThumb); + } + }, + onHorizontalDragUpdate: (DragUpdateDetails details) { + panUpdate(details); + }, + onHorizontalDragEnd: (details) { + if (widget.onPanEnded != null) { + widget.onPanEnded(_activeThumb); + } + }, + child: widget.thumb ?? + _generateThumb(context, thumbSize, widget.style.accent)), + ), + ], + ); + } + + Widget _generateSlider(BuildContext context) { + final theme = NeumorphicTheme.currentTheme(context); + return Stack(alignment: Alignment.center, children: [ + NeumorphicProgress( + duration: Duration.zero, + percent: 0, + height: widget.sliderHeight ?? widget.height, + style: ProgressStyle( + disableDepth: widget.style.disableDepth, + depth: widget.style.depth, + border: widget.style.border, + borderRadius: widget.style.borderRadius, + accent: widget.style.accent ?? theme.accentColor, + variant: widget.style.variant ?? theme.variantColor, + )), + new Positioned.fill( + child: new LayoutBuilder( + builder: (context, constraints) { + return new Padding( + padding: new EdgeInsets.only( + left: constraints.biggest.width * widget.percentLow, + right: constraints.biggest.width * (1 - widget.percentHigh)), + child: Container( + decoration: BoxDecoration( + borderRadius: widget.style.borderRadius, + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + widget.style.variant ?? theme.variantColor, + widget.style.accent ?? theme.accentColor, + ]), + ), + ), + ); + }, + ), + ), + ]); + } + + Widget _generateThumb(BuildContext context, double size, Color color) { + final theme = NeumorphicTheme.currentTheme(context); + return Neumorphic( + style: NeumorphicStyle( + disableDepth: widget.style.disableDepth, + shape: NeumorphicShape.concave, + color: color ?? theme.accentColor, + border: widget.style.thumbBorder, + boxShape: NeumorphicBoxShape.circle(), + lightSource: widget.style.lightSource ?? theme.lightSource, + ), + child: SizedBox( + height: size, + width: size, + ), + ); + } +} + +enum ActiveThumb { low, high } diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/slider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/slider.dart new file mode 100644 index 00000000..04e3251c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/slider.dart @@ -0,0 +1,221 @@ +import 'package:flutter/widgets.dart'; + +import 'container.dart'; +import 'progress.dart'; + +typedef void NeumorphicSliderListener(double percent); + +/// A style to customize the [NeumorphicSlider] +/// +/// the gradient will use [accent] and [variant] +/// +/// the gradient shape will be a roundrect, using [borderRadius] +/// +/// you can define a custom [depth] for the roundrect +/// +@immutable +class SliderStyle { + final double depth; + final bool disableDepth; + final BorderRadius borderRadius; + final Color accent; + final Color variant; + final LightSource lightSource; + + final NeumorphicBorder border; + final NeumorphicBorder thumbBorder; + + const SliderStyle({ + this.depth = 0, + this.disableDepth = false, + this.borderRadius = const BorderRadius.all(Radius.circular(10)), + this.accent, + this.lightSource, + this.variant, + this.border = const NeumorphicBorder.none(), + this.thumbBorder = const NeumorphicBorder.none(), + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is SliderStyle && + runtimeType == other.runtimeType && + depth == other.depth && + disableDepth == other.disableDepth && + lightSource == other.lightSource && + borderRadius == other.borderRadius && + thumbBorder == other.thumbBorder && + border == other.border && + accent == other.accent && + variant == other.variant; + + @override + int get hashCode => + depth.hashCode ^ + disableDepth.hashCode ^ + borderRadius.hashCode ^ + border.hashCode ^ + lightSource.hashCode ^ + thumbBorder.hashCode ^ + accent.hashCode ^ + variant.hashCode; +} + +/// A Neumorphic Design slider. +/// +/// Used to select from a range of values. +/// +/// The default is to use a continuous range of values from min to max. +/// +/// listeners : [onChanged], [onChangeStart], [onChangeEnd] +/// +/// ``` +/// //in a statefull widget +/// +/// double seekValue = 0; +/// +/// Widget _buildSlider() { +/// return Row( +/// children: [ +/// +/// Flexible( +/// child: NeumorphicSlider( +/// height: 15, +/// value: seekValue, +/// min: 0, +/// max: 10, +/// onChanged: (value) { +/// setState(() { +/// seekValue = value; +/// }); +/// }), +/// ), +/// +/// Text("value: ${seekValue.round()}"), +/// +/// ], +/// ); +/// } +/// ``` +/// +@immutable +class NeumorphicSlider extends StatefulWidget { + final SliderStyle style; + final double min; + final double value; + final double max; + final double height; + final NeumorphicSliderListener onChanged; + final NeumorphicSliderListener onChangeStart; + final NeumorphicSliderListener onChangeEnd; + + final Widget thumb; + final double sliderHeight; + + NeumorphicSlider({ + Key key, + this.style = const SliderStyle(), + this.min = 0, + this.value = 0, + this.max = 10, + this.height = 15, + this.onChanged, + this.onChangeStart, + this.onChangeEnd, + this.thumb, + this.sliderHeight, + }); + + double get percent => (((value.clamp(min, max)) - min) / ((max - min))); + + @override + createState() => _NeumorphicSliderState(); +} + +class _NeumorphicSliderState extends State { + @override + Widget build(BuildContext context) { + return LayoutBuilder(builder: (context, constraints) { + return GestureDetector( + onPanUpdate: (DragUpdateDetails details) { + final tapPos = details.localPosition; + final newPercent = tapPos.dx / constraints.maxWidth; + final newValue = + ((widget.min + (widget.max - widget.min) * newPercent)) + .clamp(widget.min, widget.max); + + if (widget.onChanged != null) { + widget.onChanged(newValue); + } + }, + onPanStart: (DragStartDetails details) { + if (widget.onChangeStart != null) { + widget.onChangeStart(widget.value); + } + }, + onPanEnd: (details) { + if (widget.onChangeEnd != null) { + widget.onChangeEnd(widget.value); + } + }, + child: _widget(context), + ); + }); + } + + Widget _widget(BuildContext context) { + double thumbSize = widget.height * 1.5; + return Stack( + alignment: Alignment.center, + children: [ + Padding( + padding: EdgeInsets.only(left: thumbSize / 2, right: thumbSize / 2), + child: _generateSlider(context), + ), + Align( + alignment: Alignment( + //because left = -1 & right = 1, so the "width" = 2, and minValue = 1 + (widget.percent * 2) - 1, + 0), + child: widget.thumb ?? _generateThumb(context, thumbSize)) + ], + ); + } + + Widget _generateSlider(BuildContext context) { + final theme = NeumorphicTheme.currentTheme(context); + return NeumorphicProgress( + duration: Duration.zero, + percent: widget.percent, + height: widget.height, + style: ProgressStyle( + disableDepth: widget.style.disableDepth, + depth: widget.style.depth, + border: widget.style.border, + lightSource: widget.style.lightSource ?? theme.lightSource, + borderRadius: widget.style.borderRadius, + accent: widget.style.accent ?? theme.accentColor, + variant: widget.style.variant ?? theme.variantColor, + ), + ); + } + + Widget _generateThumb(BuildContext context, double size) { + final theme = NeumorphicTheme.currentTheme(context); + return Neumorphic( + style: NeumorphicStyle( + disableDepth: widget.style.disableDepth, + shape: NeumorphicShape.concave, + border: widget.style.thumbBorder, + lightSource: widget.style.lightSource ?? theme.lightSource, + color: widget.style.accent ?? theme.accentColor, + boxShape: NeumorphicBoxShape.circle(), + ), + child: SizedBox( + height: size, + width: size, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/switch.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/switch.dart new file mode 100644 index 00000000..7ebab267 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/switch.dart @@ -0,0 +1,287 @@ +import 'package:flutter/widgets.dart'; + +import '../../flutter_neumorphic.dart'; +import '../neumorphic_box_shape.dart'; +import '../theme/neumorphic_theme.dart'; +import 'animation/animated_scale.dart'; +import 'container.dart'; + +/// A style to customize the [NeumorphicSwitch] +/// +/// you can define the track : [activeTrackColor], [inactiveTrackColor], [trackDepth] +/// +/// you can define the thumb : [activeTrackColor], [inactiveTrackColor], [thumbDepth] +/// and [thumbShape] @see [NeumorphicShape] +/// +class NeumorphicSwitchStyle { + final double trackDepth; + final Color activeTrackColor; + final Color inactiveTrackColor; + final Color activeThumbColor; + final Color inactiveThumbColor; + final NeumorphicShape thumbShape; + final double thumbDepth; + final LightSource lightSource; + final bool disableDepth; + + final NeumorphicBorder thumbBorder; + final NeumorphicBorder trackBorder; + + const NeumorphicSwitchStyle({ + this.trackDepth, + this.thumbShape = NeumorphicShape.concave, + this.activeTrackColor, + this.inactiveTrackColor, + this.activeThumbColor, + this.inactiveThumbColor, + this.thumbDepth, + this.lightSource, + this.disableDepth = false, + this.thumbBorder = const NeumorphicBorder.none(), + this.trackBorder = const NeumorphicBorder.none(), + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicSwitchStyle && + runtimeType == other.runtimeType && + trackDepth == other.trackDepth && + trackBorder == other.trackBorder && + thumbBorder == other.thumbBorder && + lightSource == other.lightSource && + activeTrackColor == other.activeTrackColor && + inactiveTrackColor == other.inactiveTrackColor && + activeThumbColor == other.activeThumbColor && + inactiveThumbColor == other.inactiveThumbColor && + thumbShape == other.thumbShape && + thumbDepth == other.thumbDepth && + disableDepth == other.disableDepth; + + @override + int get hashCode => + trackDepth.hashCode ^ + activeTrackColor.hashCode ^ + trackBorder.hashCode ^ + thumbBorder.hashCode ^ + lightSource.hashCode ^ + inactiveTrackColor.hashCode ^ + activeThumbColor.hashCode ^ + inactiveThumbColor.hashCode ^ + thumbShape.hashCode ^ + thumbDepth.hashCode ^ + disableDepth.hashCode; +} + +/// Used to toggle the on/off state of a single setting. +/// +/// The switch itself does not maintain any state. Instead, when the state of the switch changes, the widget calls the onChanged callback. +/// Most widgets that use a switch will listen for the onChanged callback and rebuild the switch with a new value to update the visual appearance of the switch. +/// +/// ``` +/// bool _switch1Value = false; +/// bool _switch2Value = false; +/// +/// Widget _buildSwitches() { +/// return Row(children: [ +/// +/// NeumorphicSwitch( +/// value: _switch1Value, +/// style: NeumorphicSwitchStyle( +/// thumbShape: NeumorphicShape.concave, +/// ), +/// onChanged: (value) { +/// setState(() { +/// _switch1Value = value; +/// }); +/// }, +/// ), +/// +/// NeumorphicSwitch( +/// value: _switch2Value, +/// style: NeumorphicSwitchStyle( +/// thumbShape: NeumorphicShape.flat, +/// ), +/// onChanged: (value) { +/// setState(() { +/// _switch2Value = value; +/// }); +/// }, +/// ), +/// +/// ]); +/// } +/// ``` +/// +@immutable +class NeumorphicSwitch extends StatelessWidget { + static const MIN_EMBOSS_DEPTH = -1.0; + + final bool value; + final ValueChanged onChanged; + final NeumorphicSwitchStyle style; + final double height; + final Duration duration; + final Curve curve; + final bool isEnabled; + + const NeumorphicSwitch({ + this.style = const NeumorphicSwitchStyle(), + Key key, + this.curve = Neumorphic.DEFAULT_CURVE, + this.duration = const Duration(milliseconds: 200), + this.value = false, + this.onChanged, + this.height = 40, + this.isEnabled = true, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final NeumorphicThemeData theme = NeumorphicTheme.currentTheme(context); + return SizedBox( + height: this.height, + child: AspectRatio( + aspectRatio: 2 / 1, + child: GestureDetector( + onTap: () { + // animation breaking prevention + if (!this.isEnabled) { + return; + } + if (this.onChanged != null) { + this.onChanged(!this.value); + } + }, + child: Neumorphic( + drawSurfaceAboveChild: false, + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.stadium(), + lightSource: this.style.lightSource ?? theme.lightSource, + border: this.style.trackBorder, + disableDepth: this.style.disableDepth, + depth: _getTrackDepth(theme.depth), + shape: NeumorphicShape.flat, + color: _getTrackColor(theme, this.isEnabled), + ), + child: AnimatedScale( + scale: this.isEnabled ? 1 : 0, + alignment: this.value ? Alignment(0.5, 0) : Alignment(-0.5, 0), + child: AnimatedThumb( + curve: this.curve, + disableDepth: this.style.disableDepth, + depth: this._thumbDepth, + duration: this.duration, + alignment: this._alignment, + shape: _getThumbShape, + lightSource: this.style.lightSource ?? theme.lightSource, + border: style.thumbBorder, + thumbColor: _getThumbColor(theme), + ), + ), + ), + ), + ), + ); + } + + Alignment get _alignment { + if (this.value) { + return Alignment.centerRight; + } else { + return Alignment.centerLeft; + } + } + + double get _thumbDepth { + if (!this.isEnabled) { + return 0; + } else + return this.style.thumbDepth ?? neumorphicDefaultTheme.depth; + } + + NeumorphicShape get _getThumbShape { + return this.style.thumbShape ?? NeumorphicShape.flat; + } + + double _getTrackDepth(double themeDepth) { + if (themeDepth == null) return themeDepth; + //force negative to have emboss + final double depth = -1 * (this.style.trackDepth ?? themeDepth).abs(); + return depth.clamp(Neumorphic.MIN_DEPTH, NeumorphicSwitch.MIN_EMBOSS_DEPTH); + } + + Color _getTrackColor(NeumorphicThemeData theme, bool enabled) { + if (!enabled) { + return this.style.inactiveTrackColor ?? theme.baseColor; + } + + return this.value == true + ? this.style.activeTrackColor ?? theme.accentColor + : this.style.inactiveTrackColor ?? theme.baseColor; + } + + Color _getThumbColor(NeumorphicThemeData theme) { + Color color = this.value == true + ? this.style.activeThumbColor + : this.style.inactiveThumbColor; + return color ?? theme.baseColor; + } +} + +class AnimatedThumb extends StatelessWidget { + final Color thumbColor; + final Alignment alignment; + final Duration duration; + final NeumorphicShape shape; + final double depth; + final Curve curve; + final bool disableDepth; + final NeumorphicBorder border; + final LightSource lightSource; + + AnimatedThumb({ + Key key, + this.thumbColor, + @required this.alignment, + @required this.duration, + @required this.shape, + this.depth, + this.curve = Curves.linear, + this.border = const NeumorphicBorder.none(), + this.lightSource = LightSource.topLeft, + this.disableDepth = false, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + // This Container is actually the inner track containing the thumb + return AnimatedAlign( + curve: this.curve, + alignment: this.alignment, + duration: this.duration, + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + disableDepth: this.disableDepth, + shape: shape, + depth: this.depth, + color: thumbColor, + border: this.border, + lightSource: this.lightSource, + ), + child: AspectRatio( + aspectRatio: 1, + child: FractionallySizedBox( + heightFactor: 1, + child: Container(), + //width: THUMB_WIDTH, + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/text.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/text.dart new file mode 100644 index 00000000..ecae6b6a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/text.dart @@ -0,0 +1,244 @@ +import 'dart:ui' as ui show FontFeature; + +import 'package:flutter/material.dart' as material; +import 'package:flutter/widgets.dart'; +import 'package:flutter_helper/samples/flutter_neumorphic/lib/src/decoration/neumorphic_text_decorations.dart'; + +import '../../flutter_neumorphic.dart'; +import '../theme/neumorphic_theme.dart'; + +export '../decoration/neumorphic_decorations.dart'; +export '../neumorphic_box_shape.dart'; +export '../theme/neumorphic_theme.dart'; + +class NeumorphicTextStyle { + final bool inherit; + final double fontSize; + final FontWeight fontWeight; + final FontStyle fontStyle; + final double letterSpacing; + final double wordSpacing; + final TextBaseline textBaseline; + final double height; + final Locale locale; + final List fontFeatures; + final TextDecoration decoration; + final String debugLabel; + final String fontFamily; + final List fontFamilyFallback; + final String package; + //final Color color; + //final Color backgroundColor; + //final Paint foreground, + //final Paint background, + //final TextDecoration decoration, + //final Color decorationColor; + //final TextDecorationStyle decorationStyle; + //final double decorationThickness; + + TextStyle get textStyle => TextStyle( + inherit: inherit, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + fontFeatures: fontFeatures, + decoration: decoration, + debugLabel: debugLabel, + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + package: package, + //color: color, + //backgroundColor: backgroundColor, + //foreground: foreground, + //background: background, + //decoration: decoration, + //decorationColor: decorationColor, + //decorationStyle: decorationStyle, + //decorationThickness: decorationThickness, + ); + + /// Creates a text style. + /// + /// The `package` argument must be non-null if the font family is defined in a + /// package. It is combined with the `fontFamily` argument to set the + /// [fontFamily] property. + NeumorphicTextStyle({ + this.inherit = true, + this.fontSize, + this.fontWeight, + this.fontStyle, + this.letterSpacing, + this.wordSpacing, + this.textBaseline, + this.height, + this.locale, + this.fontFeatures, + this.decoration, + this.debugLabel, + this.fontFamily, + //this.color, + //this.backgroundColor, + //this.foreground, + //this.background, + //this.decoration, + //this.decorationColor, + //this.decorationStyle, + //this.decorationThickness, + this.fontFamilyFallback, + this.package, + }); + + NeumorphicTextStyle copyWith({ + bool inherit, + String fontFamily, + List fontFamilyFallback, + double fontSize, + FontWeight fontWeight, + FontStyle fontStyle, + double letterSpacing, + double wordSpacing, + TextBaseline textBaseline, + double height, + Locale locale, + List fontFeatures, + String debugLabel, + //Color color, + //Color backgroundColor, + //Paint foreground, + //Paint background, + //TextDecoration decoration, + //Color decorationColor, + //TextDecorationStyle decorationStyle, + //double decorationThickness, + }) { + return NeumorphicTextStyle( + inherit: inherit ?? this.inherit, + fontFamily: fontFamily ?? this.fontFamily, + fontFamilyFallback: fontFamilyFallback ?? this.fontFamilyFallback, + fontSize: fontSize ?? this.fontSize, + fontWeight: fontWeight ?? this.fontWeight, + fontStyle: fontStyle ?? this.fontStyle, + letterSpacing: letterSpacing ?? this.letterSpacing, + wordSpacing: wordSpacing ?? this.wordSpacing, + textBaseline: textBaseline ?? this.textBaseline, + height: height ?? this.height, + locale: locale ?? this.locale, + fontFeatures: fontFeatures ?? this.fontFeatures, + debugLabel: debugLabel ?? this.debugLabel, + //color: this.foreground == null && foreground == null ? color ?? this.color : null, + //backgroundColor: this.background == null && background == null ? backgroundColor ?? this.backgroundColor : null, + //foreground: foreground ?? this.foreground, + //background: background ?? this.background, + //shadows: shadows ?? this.shadows, + //decoration: decoration ?? this.decoration, + //decorationColor: decorationColor ?? this.decorationColor, + //decorationStyle: decorationStyle ?? this.decorationStyle, + //decorationThickness: decorationThickness ?? this.decorationThickness, + ); + } +} + +@immutable +class NeumorphicText extends StatelessWidget { + final String text; + final NeumorphicStyle style; + final TextAlign textAlign; + final NeumorphicTextStyle textStyle; + final Curve curve; + final Duration duration; + + NeumorphicText( + this.text, { + Key key, + this.duration = Neumorphic.DEFAULT_DURATION, + this.curve = Neumorphic.DEFAULT_CURVE, + this.style, + this.textAlign = TextAlign.center, + this.textStyle, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = NeumorphicTheme.currentTheme(context); + final NeumorphicStyle style = (this.style ?? NeumorphicStyle()) + .copyWithThemeIfNull(theme) + .applyDisableDepth(); + + return _NeumorphicText( + textStyle: (this.textStyle ?? NeumorphicTextStyle()).textStyle, + textAlign: this.textAlign, + text: this.text, + duration: this.duration, + style: style, + curve: this.curve, + ); + } +} + +class _NeumorphicText extends material.StatefulWidget { + final String text; + + final NeumorphicStyle style; + final TextStyle textStyle; + final Duration duration; + final Curve curve; + + final TextAlign textAlign; + + _NeumorphicText({ + Key key, + @required this.duration, + @required this.curve, + @required this.textAlign, + @required this.style, + @required this.textStyle, + @required this.text, + }) : super(key: key); + + @override + __NeumorphicTextState createState() => __NeumorphicTextState(); +} + +class __NeumorphicTextState extends material.State<_NeumorphicText> { + @override + Widget build(BuildContext context) { + final TextPainter _textPainter = TextPainter( + textDirection: TextDirection.ltr, textAlign: this.widget.textAlign); + final textStyle = this.widget.textStyle; + _textPainter.text = TextSpan( + text: this.widget.text, + style: this.widget.textStyle, + ); + + return LayoutBuilder(builder: (context, constraints) { + _textPainter.layout(minWidth: 0, maxWidth: constraints.maxWidth); + final double width = _textPainter.width; + final double height = _textPainter.height; + + return DefaultTextStyle( + style: textStyle, + child: AnimatedContainer( + duration: this.widget.duration, + curve: this.widget.curve, + foregroundDecoration: NeumorphicTextDecoration( + isForeground: true, + textStyle: textStyle, + textAlign: widget.textAlign, + renderingByPath: true, + style: this.widget.style, + text: this.widget.text, + ), + child: SizedBox( + width: width, + height: height, + ), + ), + ); + }); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/toggle.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/toggle.dart new file mode 100644 index 00000000..788a831d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/src/widget/toggle.dart @@ -0,0 +1,315 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../neumorphic_box_shape.dart'; +import '../theme/neumorphic_theme.dart'; +import 'container.dart'; + +class NeumorphicToggleStyle { + final double depth; + final bool disableDepth; + final BorderRadius borderRadius; + final bool animateOpacity; + final Color backgroundColor; + final NeumorphicBorder border; + final LightSource lightSource; + + const NeumorphicToggleStyle({ + this.depth, + this.animateOpacity = true, + this.backgroundColor, + this.lightSource, + this.borderRadius = const BorderRadius.all(Radius.circular(12)), + this.disableDepth, + this.border = const NeumorphicBorder.none(), + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NeumorphicToggleStyle && + runtimeType == other.runtimeType && + depth == other.depth && + border == other.border && + backgroundColor == other.backgroundColor && + lightSource == other.lightSource && + disableDepth == other.disableDepth && + borderRadius == other.borderRadius && + animateOpacity == other.animateOpacity; + + @override + int get hashCode => + depth.hashCode ^ + backgroundColor.hashCode ^ + lightSource.hashCode ^ + border.hashCode ^ + disableDepth.hashCode ^ + borderRadius.hashCode ^ + animateOpacity.hashCode; +} + +/// Direct child of NeumorphicToggle +/// Contains two widgets : background & foreground +/// +/// The thumb is displayed between background & foreground +/// +/// Expanded( +/// child: NeumorphicToggle( +/// height: 50, +/// selectedIndex: _selectedIndex, +/// displayForegroundOnlyIfSelected: true, +/// children: [ +/// ToggleElement( +/// background: Center(child: Text("This week", style: TextStyle(fontWeight: FontWeight.w500),)), +/// foreground: Center(child: Text("This week", style: TextStyle(fontWeight: FontWeight.w700),)), +/// ), +/// ToggleElement( +/// background: Center(child: Text("This month", style: TextStyle(fontWeight: FontWeight.w500),)), +/// foreground: Center(child: Text("This month", style: TextStyle(fontWeight: FontWeight.w700),)), +/// ), +/// ToggleElement( +/// background: Center(child: Text("This year", style: TextStyle(fontWeight: FontWeight.w500),)), +/// foreground: Center(child: Text("This year", style: TextStyle(fontWeight: FontWeight.w700),)), +/// ) +/// ], +/// thumb: Neumorphic( +/// boxShape: NeumorphicBoxShape.roundRect(borderRadius: BorderRadius.all(Radius.circular(12))), +/// ), +/// onChanged: (value) { +/// setState(() { +/// _selectedIndex = value; +/// print("_firstSelected: $_selectedIndex"); +/// }); +/// }, +/// ), +///), +class ToggleElement { + final Widget background; + final Widget foreground; + + ToggleElement({ + this.background, + this.foreground, + }); +} + +/// +/// Switch with custom thumb (defined with list of ToggleElements) +/// +/// does not save the state +/// - notifies a `ValueChanged` : onChanged +/// - need a `selectedIndex` parameter +///oggle +/// Expanded( +/// child: NeumorphicToggle( +/// height: 50, +/// selectedIndex: _selectedIndex, +/// displayForegroundOnlyIfSelected: true, +/// children: [ +/// ToggleElement( +/// background: Center(child: Text("This week", style: TextStyle(fontWeight: FontWeight.w500),)), +/// foreground: Center(child: Text("This week", style: TextStyle(fontWeight: FontWeight.w700),)), +/// ), +/// ToggleElement( +/// background: Center(child: Text("This month", style: TextStyle(fontWeight: FontWeight.w500),)), +/// foreground: Center(child: Text("This month", style: TextStyle(fontWeight: FontWeight.w700),)), +/// ), +/// ToggleElement( +/// background: Center(child: Text("This year", style: TextStyle(fontWeight: FontWeight.w500),)), +/// foreground: Center(child: Text("This year", style: TextStyle(fontWeight: FontWeight.w700),)), +/// ) +/// ], +/// thumb: Neumorphic( +/// boxShape: NeumorphicBoxShape.roundRect(borderRadius: BorderRadius.all(Radius.circular(12))), +/// ), +/// onChanged: (value) { +/// setState(() { +/// _selectedIndex = value; +/// print("_firstSelected: $_selectedIndex"); +/// }); +/// }, +/// ), +///), +@immutable +class NeumorphicToggle extends StatelessWidget { + static const MIN_EMBOSS_DEPTH = -1.0; + + final EdgeInsets padding; + + final List children; + final Widget thumb; + + final int selectedIndex; + final ValueChanged onChanged; + final Function(int) onAnimationChangedFinished; + + final NeumorphicToggleStyle style; + final double height; + final double width; + final Duration duration; + final bool isEnabled; + + final Curve movingCurve; + + final Curve alphaAnimationCurve; + final bool displayForegroundOnlyIfSelected; + + const NeumorphicToggle({ + this.style = const NeumorphicToggleStyle(), + Key key, + @required this.children, + @required this.thumb, + this.padding = const EdgeInsets.all(2), + this.duration = const Duration(milliseconds: 200), + this.selectedIndex = 0, + this.alphaAnimationCurve = Curves.linear, + this.movingCurve = Curves.linear, + this.onAnimationChangedFinished, + this.onChanged, + this.height = 40, + this.width, + this.isEnabled = true, + this.displayForegroundOnlyIfSelected = true, + }) : super(key: key); + + Widget _buildStack(BuildContext context) { + return Stack( + children: [ + _background(context), + Row( + mainAxisSize: MainAxisSize.max, + children: _generateBackgrounds(), + ), + AnimatedAlign( + curve: this.movingCurve, + onEnd: () { + if (onAnimationChangedFinished != null) { + onAnimationChangedFinished(this.selectedIndex); + } + }, + alignment: _alignment(), + duration: this.duration, + child: FractionallySizedBox( + widthFactor: 1 / this.children.length, + heightFactor: 1, + child: Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect( + this.style?.borderRadius ?? + BorderRadius.all(Radius.circular(12))), + ), + margin: this.padding, + child: this.thumb, + ), + ), + ), + Row( + mainAxisSize: MainAxisSize.max, + children: _generateForegrounds(), + ), + ], + ); + } + + List _generateBackgrounds() { + final List widgets = []; + for (int i = 0; i < this.children.length; ++i) { + widgets.add(_backgroundAtIndex(i)); + } + return widgets; + } + + List _generateForegrounds() { + final List widgets = []; + for (int i = 0; i < this.children.length; ++i) { + widgets.add(_foregroundAtIndex(i)); + } + return widgets; + } + + Alignment _alignment() { + double percentX = selectedIndex / (this.children.length - 1); + double aligmentX = -1.0 + (2.0 * percentX); + return Alignment(aligmentX, 0.0); + } + + Widget _backgroundAtIndex(int index) { + return Expanded( + flex: 1, child: this.children[index].background ?? SizedBox.expand()); + } + + Widget _foregroundAtIndex(int index) { + Widget child = (!this.displayForegroundOnlyIfSelected) || + (this.displayForegroundOnlyIfSelected && + this.selectedIndex == index) + ? this.children[index].foreground + : SizedBox.expand(); + //wrap with opacity animation + if (style != null && style.animateOpacity) { + child = AnimatedOpacity( + curve: this.alphaAnimationCurve, + opacity: this.selectedIndex == index ? 1 : 0, + duration: this.duration, + child: child, + ); + } + return Expanded( + flex: 1, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + _notifyOnChange(index); + }, + child: child, + )); + } + + Widget _background(BuildContext context) { + return Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect(this.style?.borderRadius ?? + BorderRadius.all(Radius.circular(12))), + color: this.style?.backgroundColor, + disableDepth: this.style?.disableDepth, + depth: _getTrackDepth(context), + shape: NeumorphicShape.flat, + border: this.style?.border ?? NeumorphicBorder.none(), + lightSource: this.style?.lightSource ?? + NeumorphicTheme.currentTheme(context).lightSource), + child: SizedBox.expand(), + ); + } + + @override + Widget build(BuildContext context) { + if (this.width != null) { + return SizedBox( + height: this.height, + width: this.width, + child: _buildStack(context), + ); + } else { + return FractionallySizedBox( + widthFactor: 1.0, + child: SizedBox( + height: this.height, + child: _buildStack(context), + ), + ); + } + } + + double _getTrackDepth(BuildContext context) { + final NeumorphicThemeData theme = NeumorphicTheme.currentTheme(context); + + //force negative to have emboss + final double depth = -1 * (this.style?.depth ?? theme.depth).abs(); + return depth.clamp(Neumorphic.MIN_DEPTH, NeumorphicToggle.MIN_EMBOSS_DEPTH); + } + + void _notifyOnChange(int newValue) { + if (this.onChanged != null) { + this.onChanged(newValue); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/top_bar.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/top_bar.dart new file mode 100644 index 00000000..1f90a120 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/lib/top_bar.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'back_button.dart'; +import 'flutter_neumorphic.dart'; + +class TopBar extends StatelessWidget implements PreferredSizeWidget { + final String title; + final List actions; + + static const double kToolbarHeight = 110.0; + + const TopBar({this.title = "", this.actions}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: 18.0), + child: Stack( + alignment: Alignment.center, + children: [ + Align(alignment: Alignment.centerLeft, child: NeumorphicBack()), + Center( + child: Text( + this.title, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w800, + color: NeumorphicTheme.isUsingDark(context) + ? Colors.white70 + : Colors.black87, + ), + ), + ), + Align( + alignment: Alignment.centerRight, + child: Row( + mainAxisSize: MainAxisSize.min, + children: actions ?? [], + )), + ], + ), + ); + } + + @override + Size get preferredSize => Size.fromHeight(kToolbarHeight); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/main.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/main.dart new file mode 100644 index 00000000..eebb7568 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/main.dart @@ -0,0 +1,117 @@ +import 'lib/flutter_neumorphic.dart'; + +import 'main_home.dart'; + +void main() => runApp(FlutterNeumorphicApp()); + +class FlutterNeumorphicApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return NeumorphicApp( + debugShowCheckedModeBanner: false, + title: 'Flutter Demo', + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + baseColor: Color(0xFFFFFFFF), + lightSource: LightSource.topLeft, + depth: 10, + ), + darkTheme: NeumorphicThemeData( + baseColor: Color(0xFF3E3E3E), + lightSource: LightSource.topLeft, + depth: 6, + ), + home: MyHomePage(), + ); + } +} + +class MyHomePage extends StatelessWidget { + MyHomePage({Key key}) : super(key: key); + + Widget build(BuildContext context) { + return Scaffold( + floatingActionButton: NeumorphicFloatingActionButton( + child: Icon(Icons.add, size: 30), + onPressed: () {}, + ), + backgroundColor: NeumorphicTheme.baseColor(context), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + NeumorphicButton( + onPressed: () { + print("onClick"); + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + padding: const EdgeInsets.all(12.0), + child: Icon( + Icons.favorite_border, + color: _iconsColor(context), + ), + ), + NeumorphicButton( + margin: EdgeInsets.only(top: 12), + onPressed: () { + NeumorphicTheme.of(context).themeMode = + NeumorphicTheme.isUsingDark(context) + ? ThemeMode.light + : ThemeMode.dark; + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: + NeumorphicBoxShape.roundRect(BorderRadius.circular(8)), + ), + padding: const EdgeInsets.all(12.0), + child: Text( + "Toggle Theme", + style: TextStyle(color: _textColor(context)), + )), + NeumorphicButton( + margin: EdgeInsets.only(top: 12), + onPressed: () { + Navigator.of(context) + .pushReplacement(MaterialPageRoute(builder: (context) { + return FullSampleHomePage(); + })); + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: + NeumorphicBoxShape.roundRect(BorderRadius.circular(8)), + //border: NeumorphicBorder() + ), + padding: const EdgeInsets.all(12.0), + child: Text( + "Go to full sample", + style: TextStyle(color: _textColor(context)), + )), + ], + ), + ), + ); + } + + Color _iconsColor(BuildContext context) { + final theme = NeumorphicTheme.of(context); + if (theme.isUsingDark) { + return theme.current.accentColor; + } else { + return null; + } + } + + Color _textColor(BuildContext context) { + if (NeumorphicTheme.isUsingDark(context)) { + return Colors.white; + } else { + return Colors.black; + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/main_home.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/main_home.dart new file mode 100644 index 00000000..a2639795 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/main_home.dart @@ -0,0 +1,128 @@ +import 'tips/tips_home.dart'; +import 'widgets/widgets_home.dart'; +import 'package:flutter/material.dart'; +import 'lib/flutter_neumorphic.dart'; + +import 'accessibility/neumorphic_accessibility.dart'; +import 'playground/neumorphic_playground.dart'; +import 'playground/text_playground.dart'; +import 'samples/sample_home.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return NeumorphicApp( + debugShowCheckedModeBanner: false, + themeMode: ThemeMode.light, + title: 'Flutter Neumorphic', + home: FullSampleHomePage(), + ); + } +} + +class FullSampleHomePage extends StatelessWidget { + Widget _buildButton({String text, VoidCallback onClick}) { + return NeumorphicButton( + margin: EdgeInsets.only(bottom: 12), + padding: EdgeInsets.symmetric( + vertical: 18, + horizontal: 24, + ), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(12), + ), + //border: NeumorphicBorder( + // isEnabled: true, + // width: 0.3, + //), + shape: NeumorphicShape.flat, + ), + child: Center(child: Text(text)), + onPressed: onClick, + ); + } + + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData(depth: 8), + child: Scaffold( + backgroundColor: NeumorphicColors.background, + body: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(18.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _buildButton( + text: "Neumorphic Playground", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return NeumorphicPlayground(); + })); + }, + ), + SizedBox(height: 24), + _buildButton( + text: "Text Playground", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return NeumorphicTextPlayground(); + })); + }, + ), + SizedBox(height: 24), + _buildButton( + text: "Samples", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return SamplesHome(); + })); + }), + SizedBox(height: 24), + _buildButton( + text: "Widgets", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return WidgetsHome(); + })); + }), + SizedBox(height: 24), + _buildButton( + text: "Tips", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return TipsHome(); + })); + }), + SizedBox(height: 24), + _buildButton( + text: "Accessibility", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return NeumorphicAccessibility(); + })); + }), + SizedBox(height: 12), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/playground/neumorphic_playground.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/playground/neumorphic_playground.dart new file mode 100644 index 00000000..34f2acfd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/playground/neumorphic_playground.dart @@ -0,0 +1,873 @@ +import '../lib/color_selector.dart'; +import '../lib/flutter_neumorphic.dart'; + +class NeumorphicPlayground extends StatefulWidget { + @override + _NeumorphicPlaygroundState createState() => _NeumorphicPlaygroundState(); +} + +class _NeumorphicPlaygroundState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + baseColor: Color(0xffDDDDDD), + lightSource: LightSource.topLeft, + depth: 6, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + __PageState createState() => __PageState(); +} + +class __PageState extends State<_Page> { + LightSource lightSource = LightSource.topLeft; + NeumorphicShape shape = NeumorphicShape.flat; + NeumorphicBoxShape boxShape; + double depth = 5; + double intensity = 0.5; + double surfaceIntensity = 0.5; + double cornerRadius = 20; + double height = 150.0; + double width = 150.0; + + static final minWidth = 50.0; + static final maxWidth = 200.0; + static final minHeight = 50.0; + static final maxHeight = 200.0; + + bool haveNeumorphicChild = false; + bool childOppositeLightsourceChild = false; + bool drawAboveChild = false; + double childMargin = 5; + double childDepth = 5; + + @override + void initState() { + boxShape = NeumorphicBoxShape.path(NeumorphicFlutterLogoPathProvider()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: NeumorphicTheme.baseColor(context), + //appBar: NeumorphicAppBar( + // title: Text('Playground'), + //), + body: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + color: Theme.of(context).accentColor, + child: Text( + "back", + style: TextStyle(color: Colors.white), + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + Flexible( + flex: 1, + child: Stack( + fit: StackFit.expand, + children: [ + lightSourceWidgets(), + Center(child: neumorphic()), + ], + ), + ), + Flexible( + flex: 1, + child: _configurators(), + ) + ], + )); + } + + int selectedConfiguratorIndex = 0; + + Widget _configurators() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color textActiveColor = Colors.white; + final Color textInactiveColor = Colors.black.withOpacity(0.3); + + return Card( + margin: EdgeInsets.all(8), + elevation: 12, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + color: Colors.grey[300], + child: Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + color: selectedConfiguratorIndex == 0 + ? buttonActiveColor + : buttonInnactiveColor, + child: Text( + "Style", + style: TextStyle( + color: selectedConfiguratorIndex == 0 + ? textActiveColor + : textInactiveColor, + ), + ), + onPressed: () { + setState(() { + selectedConfiguratorIndex = 0; + }); + }, + ), + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + child: Text( + "Element", + style: TextStyle( + color: selectedConfiguratorIndex == 1 + ? textActiveColor + : textInactiveColor, + ), + ), + color: selectedConfiguratorIndex == 1 + ? buttonActiveColor + : buttonInnactiveColor, + onPressed: () { + setState(() { + selectedConfiguratorIndex = 1; + }); + }, + ), + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + child: Text( + "Child", + style: TextStyle( + color: selectedConfiguratorIndex == 2 + ? textActiveColor + : textInactiveColor, + ), + ), + color: selectedConfiguratorIndex == 2 + ? buttonActiveColor + : buttonInnactiveColor, + onPressed: () { + setState(() { + selectedConfiguratorIndex = 2; + }); + }, + ), + ), + ) + ], + ), + _configuratorsChild(), + ], + ), + ); + } + + Widget _configuratorsChild() { + switch (selectedConfiguratorIndex) { + case 0: + return styleCustomizer(); + break; + case 1: + return elementCustomizer(); + break; + case 2: + return childCustomizer(); + break; + } + return null; + } + + Widget styleCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + depthSelector(), + intensitySelector(), + surfaceIntensitySelector(), + colorPicker(), + ], + ); + } + + Widget elementCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + boxshapeWidget(), + cornerRadiusSelector(), + shapeWidget(), + sizeSelector(), + ], + ); + } + + Widget childCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + hasChildSelector(), + drawAboveChildSelector(), + childDepthSelector(), + childMarginSelector(), + childOppositeLightsourceSelector(), + ], + ); + } + + Widget colorPicker() { + return Row( + children: [ + SizedBox( + width: 12, + ), + Text("Color "), + SizedBox( + width: 4, + ), + ColorSelector( + onColorChanged: (color) { + setState(() { + NeumorphicTheme.of(context) + .updateCurrentTheme(NeumorphicThemeData(baseColor: color)); + }); + }, + color: NeumorphicTheme.baseColor(context), + ), + ], + ); + } + + Widget neumorphic() { + return NeumorphicButton( + padding: EdgeInsets.zero, + duration: Duration(milliseconds: 300), + onPressed: () { + setState(() {}); + }, + drawSurfaceAboveChild: this.drawAboveChild, + style: NeumorphicStyle( + boxShape: boxShape, + //border: NeumorphicBorder(), + shape: this.shape, + intensity: this.intensity, + /* + shadowLightColor: Colors.red, + shadowDarkColor: Colors.blue, + shadowLightColorEmboss: Colors.red, + shadowDarkColorEmboss: Colors.blue, + */ + surfaceIntensity: this.surfaceIntensity, + depth: depth, + lightSource: this.lightSource, + ), + child: SizedBox( + height: height, + width: width, + child: haveNeumorphicChild + ? neumorphicChild() + : Container( + //color: Colors.blue, + child: Center(child: Text("")), + ), + ), + ); + } + + Widget neumorphicChild() { + return Neumorphic( + padding: EdgeInsets.zero, + duration: Duration(milliseconds: 300), + margin: EdgeInsets.all(this.childMargin), + drawSurfaceAboveChild: true, + style: NeumorphicStyle( + boxShape: boxShape, + //shape: this.shape, + intensity: this.intensity, + surfaceIntensity: this.surfaceIntensity, + depth: childDepth, + lightSource: this.lightSource, + oppositeShadowLightSource: this.childOppositeLightsourceChild), + child: SizedBox.expand(), + ); + } + + Widget depthSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Depth"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_DEPTH, + max: Neumorphic.MAX_DEPTH, + value: depth, + onChanged: (value) { + setState(() { + depth = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(depth.floor().toString()), + ), + ], + ); + } + + Widget childDepthSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Child Depth"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_DEPTH, + max: Neumorphic.MAX_DEPTH, + value: childDepth, + onChanged: (value) { + setState(() { + childDepth = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(childDepth.floor().toString()), + ), + ], + ); + } + + Widget childMarginSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Child Margin"), + ), + Expanded( + child: Slider( + min: 0, + max: 40, + value: childMargin, + onChanged: (value) { + setState(() { + childMargin = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(childMargin.floor().toString()), + ), + ], + ); + } + + Widget hasChildSelector() { + return Stack( + alignment: Alignment.center, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Has Child"), + ), + ), + Align( + alignment: Alignment.centerRight, + child: Checkbox( + value: this.haveNeumorphicChild, + onChanged: (value) { + setState(() { + haveNeumorphicChild = value; + }); + }, + ), + ), + ], + ); + } + + Widget drawAboveChildSelector() { + return Stack( + alignment: Alignment.center, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Draw above child"), + ), + ), + Align( + alignment: Alignment.centerRight, + child: Checkbox( + value: this.drawAboveChild, + onChanged: (value) { + setState(() { + drawAboveChild = value; + }); + }, + ), + ), + ], + ); + } + + Widget childOppositeLightsourceSelector() { + return Stack( + alignment: Alignment.center, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.only(left: 12), + child: Text("OppositeLight"), + ), + ), + Align( + alignment: Alignment.centerRight, + child: Checkbox( + value: this.childOppositeLightsourceChild, + onChanged: (value) { + setState(() { + childOppositeLightsourceChild = value; + }); + }, + ), + ), + ], + ); + } + + Widget sizeSelector() { + return Row( + children: [ + SizedBox( + width: 12, + ), + Text("W: "), + Expanded( + child: Slider( + min: minWidth, + max: maxWidth, + value: width, + onChanged: (value) { + setState(() { + width = value; + }); + }, + ), + ), + Text("H: "), + Expanded( + child: Slider( + min: minHeight, + max: maxHeight, + value: height, + onChanged: (value) { + setState(() { + height = value; + }); + }, + ), + ), + ], + ); + } + + Widget cornerRadiusSelector() { + if (boxShape.isRoundRect || boxShape.isBeveled) { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Corner"), + ), + Expanded( + child: Slider( + min: 0, + max: 30, + value: cornerRadius, + onChanged: (value) { + setState(() { + cornerRadius = value; + if (boxShape.isRoundRect) { + boxShape = NeumorphicBoxShape.roundRect( + BorderRadius.circular(this.cornerRadius)); + } + if (boxShape.isBeveled) { + boxShape = NeumorphicBoxShape.beveled( + BorderRadius.circular(this.cornerRadius)); + } + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(cornerRadius.floor().toString()), + ), + ], + ); + } else { + return SizedBox(); + } + } + + Widget intensitySelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Intensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: intensity, + onChanged: (value) { + setState(() { + intensity = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((intensity * 100).floor() / 100).toString()), + ), + ], + ); + } + + Widget surfaceIntensitySelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("SurfaceIntensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: surfaceIntensity, + onChanged: (value) { + setState(() { + surfaceIntensity = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((surfaceIntensity * 100).floor() / 100).toString()), + ), + ], + ); + } + + Widget boxshapeWidget() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color textActiveColor = Colors.white; + final Color textInactiveColor = Colors.black.withOpacity(0.3); + + return Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + boxShape = NeumorphicBoxShape.roundRect( + BorderRadius.circular(this.cornerRadius)); + }); + }, + color: boxShape.isRoundRect + ? buttonActiveColor + : buttonInnactiveColor, + child: Text( + "Rect", + style: TextStyle( + color: boxShape.isRoundRect + ? textActiveColor + : textInactiveColor), + ), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + boxShape = NeumorphicBoxShape.beveled( + BorderRadius.circular(this.cornerRadius)); + }); + }, + color: + boxShape.isBeveled ? buttonActiveColor : buttonInnactiveColor, + child: Text( + "Beveled", + style: TextStyle( + color: boxShape.isBeveled + ? textActiveColor + : textInactiveColor), + ), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + boxShape = NeumorphicBoxShape.circle(); + }); + }, + color: + boxShape.isCircle ? buttonActiveColor : buttonInnactiveColor, + child: Text( + "Circle", + style: TextStyle( + color: boxShape.isCircle + ? textActiveColor + : textInactiveColor), + ), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + boxShape = NeumorphicBoxShape.stadium(); + }); + }, + color: + boxShape.isStadium ? buttonActiveColor : buttonInnactiveColor, + child: Text( + "Stadium", + style: TextStyle( + color: boxShape.isStadium + ? textActiveColor + : textInactiveColor), + ), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + boxShape = NeumorphicBoxShape.path( + NeumorphicFlutterLogoPathProvider()); + }); + }, + color: boxShape.isCustomPath + ? buttonActiveColor + : buttonInnactiveColor, + child: Text( + "Custom", + style: TextStyle( + color: boxShape.isCustomPath + ? textActiveColor + : textInactiveColor), + ), + ), + ), + ), + ], + ); + } + + Widget shapeWidget() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color iconActiveColor = Colors.white; + final Color iconInactiveColor = Colors.black.withOpacity(0.3); + + return Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.concave; + }); + }, + color: shape == NeumorphicShape.concave + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/concave.png", + color: shape == NeumorphicShape.concave + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.convex; + }); + }, + color: shape == NeumorphicShape.convex + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/convex.png", + color: shape == NeumorphicShape.convex + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.flat; + }); + }, + color: shape == NeumorphicShape.flat + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/flat.png", + color: shape == NeumorphicShape.flat + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + ], + ); + } + + Widget lightSourceWidgets() { + return Stack( + children: [ + Positioned( + left: 10, + right: 10, + child: Slider( + min: -1, + max: 1, + value: lightSource.dx, + onChanged: (value) { + setState(() { + lightSource = lightSource.copyWith(dx: value); + }); + }, + ), + ), + Positioned( + left: 0, + top: 10, + bottom: 10, + child: RotatedBox( + quarterTurns: 1, + child: Slider( + min: -1, + max: 1, + value: lightSource.dy, + onChanged: (value) { + setState(() { + lightSource = lightSource.copyWith(dy: value); + }); + }, + ), + ), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/playground/text_playground.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/playground/text_playground.dart new file mode 100644 index 00000000..bc312656 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/playground/text_playground.dart @@ -0,0 +1,562 @@ +import '../lib/color_selector.dart'; +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +class NeumorphicTextPlayground extends StatefulWidget { + @override + _NeumorphicPlaygroundState createState() => _NeumorphicPlaygroundState(); +} + +class _NeumorphicPlaygroundState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + baseColor: Color(0xffDDDDDD), + lightSource: LightSource.topLeft, + depth: 6, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + __PageState createState() => __PageState(); +} + +class __PageState extends State<_Page> { + LightSource lightSource = LightSource.topLeft; + NeumorphicShape shape = NeumorphicShape.flat; + double depth = 2; + double intensity = 0.8; + double surfaceIntensity = 0.5; + double cornerRadius = 20; + double height = 150.0; + double width = 150.0; + + double fontSize = 100; + int fontWeight = 800; + + final _textController = TextEditingController(text: "Flutter"); + + bool displayIcon = false; + + Widget neumorphicText() { + if (displayIcon) { + return NeumorphicIcon( + Icons.public, + size: this.fontSize, + style: NeumorphicStyle( + shape: this.shape, + intensity: this.intensity, + surfaceIntensity: this.surfaceIntensity, + depth: depth, + lightSource: this.lightSource, + ), + ); + } else { + return NeumorphicText( + this._textController.text, + textStyle: NeumorphicTextStyle( + fontSize: this.fontSize, + fontWeight: _fontWeight(), + ), + style: NeumorphicStyle( + shape: this.shape, + intensity: this.intensity, + surfaceIntensity: this.surfaceIntensity, + depth: depth, + lightSource: this.lightSource, + ), + ); + } + } + + @override + Widget build(BuildContext context) { + return SafeArea( + child: NeumorphicBackground( + child: Scaffold( + backgroundColor: Colors.transparent, + body: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: + const EdgeInsets.only(left: 8.0, right: 8.0, top: 8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + color: Theme.of(context).accentColor, + child: Text( + "back", + style: TextStyle(color: Colors.white), + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + Flexible( + flex: 1, + child: Stack( + fit: StackFit.expand, + children: [ + lightSourceWidgets(), + Center(child: neumorphicText()), + ], + ), + ), + Flexible( + flex: 1, + child: _configurators(), + ) + ], + )), + ), + ); + } + + int selectedConfiguratorIndex = 0; + + Widget _configurators() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color textActiveColor = Colors.white; + final Color textInactiveColor = Colors.black.withOpacity(0.3); + + return Card( + margin: EdgeInsets.all(8), + elevation: 12, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + color: Colors.grey[300], + child: Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + color: selectedConfiguratorIndex == 0 + ? buttonActiveColor + : buttonInnactiveColor, + child: Text( + "Style", + style: TextStyle( + color: selectedConfiguratorIndex == 0 + ? textActiveColor + : textInactiveColor, + ), + ), + onPressed: () { + setState(() { + selectedConfiguratorIndex = 0; + }); + }, + ), + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + child: Text( + "Element", + style: TextStyle( + color: selectedConfiguratorIndex == 1 + ? textActiveColor + : textInactiveColor, + ), + ), + color: selectedConfiguratorIndex == 1 + ? buttonActiveColor + : buttonInnactiveColor, + onPressed: () { + setState(() { + selectedConfiguratorIndex = 1; + }); + }, + ), + ), + ), + ], + ), + _configuratorsChild(), + ], + ), + ); + } + + Widget _configuratorsChild() { + switch (selectedConfiguratorIndex) { + case 0: + return styleCustomizer(); + break; + case 1: + return elementCustomizer(); + break; + } + return null; + } + + Widget styleCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + depthSelector(), + intensitySelector(), + surfaceIntensitySelector(), + colorPicker(), + ], + ); + } + + Widget elementCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + fontSizeSelector(), + fontWeightSelector(), + textSelector(), + shapeWidget(), + ], + ); + } + + Widget shapeWidget() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color iconActiveColor = Colors.white; + final Color iconInactiveColor = Colors.black.withOpacity(0.3); + + return Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.concave; + }); + }, + color: shape == NeumorphicShape.concave + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/concave.png", + color: shape == NeumorphicShape.concave + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.convex; + }); + }, + color: shape == NeumorphicShape.convex + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/convex.png", + color: shape == NeumorphicShape.convex + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.flat; + }); + }, + color: shape == NeumorphicShape.flat + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/flat.png", + color: shape == NeumorphicShape.flat + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + ], + ); + } + + Widget colorPicker() { + return Row( + children: [ + SizedBox( + width: 12, + ), + Text("Color "), + SizedBox( + width: 4, + ), + ColorSelector( + onColorChanged: (color) { + setState(() { + NeumorphicTheme.of(context) + .updateCurrentTheme(NeumorphicThemeData(baseColor: color)); + }); + }, + color: NeumorphicTheme.baseColor(context), + ), + ], + ); + } + + Widget depthSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Depth"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_DEPTH, + max: Neumorphic.MAX_DEPTH, + value: depth, + onChanged: (value) { + setState(() { + depth = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(depth.floor().toString()), + ), + ], + ); + } + + Widget fontSizeSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("FontSize"), + ), + Expanded( + child: Slider( + min: 40, + max: 200, + value: fontSize, + onChanged: (value) { + setState(() { + fontSize = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(fontSize.floor().toString()), + ), + ], + ); + } + + Widget textSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Text"), + ), + SizedBox( + width: 12, + ), + Expanded( + child: TextField( + controller: this._textController, + decoration: InputDecoration( + border: OutlineInputBorder(), + ), + onChanged: (s) { + setState(() {}); + }, + ), + ), + ], + ); + } + + Widget intensitySelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Intensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: intensity, + onChanged: (value) { + setState(() { + intensity = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((intensity * 100).floor() / 100).toString()), + ), + ], + ); + } + + FontWeight _fontWeight() { + switch ((this.fontWeight / 100).toInt()) { + case 1: + return FontWeight.w100; + case 2: + return FontWeight.w200; + case 3: + return FontWeight.w300; + case 4: + return FontWeight.w400; + case 5: + return FontWeight.w500; + case 6: + return FontWeight.w600; + case 7: + return FontWeight.w700; + case 8: + return FontWeight.w800; + case 9: + return FontWeight.w900; + } + return FontWeight.w500; + } + + Widget fontWeightSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("FontWeight"), + ), + Expanded( + child: Slider( + min: 100, + max: 900, + value: fontWeight.toDouble(), + onChanged: (value) { + setState(() { + fontWeight = value.toInt(); + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((fontWeight * 100).floor() / 100).toString()), + ), + ], + ); + } + + Widget surfaceIntensitySelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("SurfaceIntensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: surfaceIntensity, + onChanged: (value) { + setState(() { + surfaceIntensity = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((surfaceIntensity * 100).floor() / 100).toString()), + ), + ], + ); + } + + Widget lightSourceWidgets() { + return Stack( + children: [ + Positioned( + left: 10, + right: 10, + child: Slider( + min: -1, + max: 1, + value: lightSource.dx, + onChanged: (value) { + setState(() { + lightSource = lightSource.copyWith(dx: value); + }); + }, + ), + ), + Positioned( + left: 0, + top: 10, + bottom: 10, + child: RotatedBox( + quarterTurns: 1, + child: Slider( + min: -1, + max: 1, + value: lightSource.dy, + onChanged: (value) { + setState(() { + lightSource = lightSource.copyWith(dy: value); + }); + }, + ), + ), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/sample_neumorphic_playground.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/sample_neumorphic_playground.dart new file mode 100644 index 00000000..edb55413 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/sample_neumorphic_playground.dart @@ -0,0 +1,363 @@ +import 'lib/color_selector.dart'; +import 'package:flutter/cupertino.dart'; +import 'lib/flutter_neumorphic.dart'; + +void main() => runApp(NeumorphicPlayground()); + +class NeumorphicPlayground extends StatefulWidget { + @override + _NeumorphicPlaygroundState createState() => _NeumorphicPlaygroundState(); +} + +class _NeumorphicPlaygroundState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicApp( + debugShowCheckedModeBanner: false, + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + baseColor: Color(0xffDDDDDD), + lightSource: LightSource.topLeft, + depth: 6, + intensity: 0.5, + ), + home: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + __PageState createState() => __PageState(); +} + +class __PageState extends State<_Page> { + LightSource lightSource = LightSource.topLeft; + NeumorphicShape shape = NeumorphicShape.flat; + NeumorphicBoxShape boxShape = + NeumorphicBoxShape.roundRect(BorderRadius.circular(12)); + + double depth = 5; + double intensity = 0.5; + double surfaceIntensity = 0.5; + double cornerRadius = 40; + double height = 150.0; + double width = 150.0; + + bool haveNeumorphicChild = false; + bool childOppositeLightsourceChild = false; + bool drawAboveChild = false; + double childMargin = 5; + double childDepth = 5; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: NeumorphicTheme.baseColor(context), + //appBar: NeumorphicAppBar( + // title: Text('Playground'), + //), + body: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Flexible( + flex: 1, + child: Stack( + fit: StackFit.expand, + children: [ + lightSourceWidgets(), + Center(child: neumorphic()), + ], + ), + ), + Flexible( + flex: 1, + child: _configurators(), + ) + ], + )); + } + + Widget _configurators() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color textActiveColor = Colors.white; + final Color textInactiveColor = Colors.black.withOpacity(0.3); + + return Column( + children: [ + styleCustomizer(), + ], + ); + } + + Widget styleCustomizer() { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + //depthSelector(), + //intensitySelector(), + //surfaceIntensitySelector(), + //shapeWidget(), + ], + ); + } + + Widget neumorphic() { + return NeumorphicButton( + padding: EdgeInsets.zero, + duration: Duration(milliseconds: 300), + onPressed: () { + setState(() {}); + }, + drawSurfaceAboveChild: this.drawAboveChild, + style: NeumorphicStyle( + boxShape: boxShape, + //border: NeumorphicBorder(), + shape: this.shape, + intensity: this.intensity, + /* + shadowLightColor: Colors.red, + shadowDarkColor: Colors.blue, + shadowLightColorEmboss: Colors.red, + shadowDarkColorEmboss: Colors.blue, + */ + surfaceIntensity: this.surfaceIntensity, + depth: depth, + lightSource: this.lightSource, + ), + child: SizedBox( + height: height, + width: width, + child: haveNeumorphicChild + ? neumorphicChild() + : Container( + //color: Colors.blue, + child: Center(child: Text("")), + ), + ), + ); + } + + Widget neumorphicChild() { + return Neumorphic( + padding: EdgeInsets.zero, + duration: Duration(milliseconds: 300), + margin: EdgeInsets.all(this.childMargin), + drawSurfaceAboveChild: true, + style: NeumorphicStyle( + boxShape: boxShape, + //shape: this.shape, + intensity: this.intensity, + surfaceIntensity: this.surfaceIntensity, + depth: childDepth, + lightSource: this.lightSource, + oppositeShadowLightSource: this.childOppositeLightsourceChild), + child: SizedBox.expand(), + ); + } + + Widget depthSelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Depth"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_DEPTH, + max: Neumorphic.MAX_DEPTH, + value: depth, + onChanged: (value) { + setState(() { + depth = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(depth.floor().toString()), + ), + ], + ); + } + + Widget intensitySelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("Intensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: intensity, + onChanged: (value) { + setState(() { + intensity = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((intensity * 100).floor() / 100).toString()), + ), + ], + ); + } + + Widget surfaceIntensitySelector() { + return Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 12), + child: Text("SurfaceIntensity"), + ), + Expanded( + child: Slider( + min: Neumorphic.MIN_INTENSITY, //in case of != 0 + max: Neumorphic.MAX_INTENSITY, + value: surfaceIntensity, + onChanged: (value) { + setState(() { + surfaceIntensity = value; + }); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: 12), + child: Text(((surfaceIntensity * 100).floor() / 100).toString()), + ), + ], + ); + } + + Widget shapeWidget() { + final Color buttonActiveColor = Theme.of(context).accentColor; + final Color buttonInnactiveColor = Colors.white; + + final Color iconActiveColor = Colors.white; + final Color iconInactiveColor = Colors.black.withOpacity(0.3); + + return Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.concave; + }); + }, + color: shape == NeumorphicShape.concave + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/concave.png", + color: shape == NeumorphicShape.concave + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.convex; + }); + }, + color: shape == NeumorphicShape.convex + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/convex.png", + color: shape == NeumorphicShape.convex + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + onPressed: () { + setState(() { + shape = NeumorphicShape.flat; + }); + }, + color: shape == NeumorphicShape.flat + ? buttonActiveColor + : buttonInnactiveColor, + child: Image.asset("assets/images/flat.png", + color: shape == NeumorphicShape.flat + ? iconActiveColor + : iconInactiveColor), + ), + ), + ), + ], + ); + } + + Widget lightSourceWidgets() { + return Stack( + children: [ + Positioned( + left: 20, + right: 20, + child: Slider( + min: -1, + max: 1, + value: lightSource.dx, + onChanged: (value) { + setState(() { + lightSource = lightSource.copyWith(dx: value); + }); + }, + ), + ), + Positioned( + left: 0, + top: 20, + bottom: 20, + child: RotatedBox( + quarterTurns: 1, + child: Slider( + min: -1, + max: 1, + value: lightSource.dy, + onChanged: (value) { + setState(() { + lightSource = lightSource.copyWith(dy: value); + }); + }, + ), + ), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/audio_player_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/audio_player_sample.dart new file mode 100644 index 00000000..b52a6740 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/audio_player_sample.dart @@ -0,0 +1,246 @@ +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +class AudioPlayerSample extends StatefulWidget { + @override + _AudioPlayerSampleState createState() => _AudioPlayerSampleState(); +} + +class _AudioPlayerSampleState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + defaultTextColor: Color(0xFF3E3E3E), + baseColor: Color(0xFFDDE6E8), + intensity: 0.5, + lightSource: LightSource.topLeft, + depth: 10, + ), + darkTheme: neumorphicDefaultDarkTheme.copyWith( + defaultTextColor: Colors.white70), + child: _Page()); + } +} + +class _Page extends StatefulWidget { + @override + __PageState createState() => __PageState(); +} + +class __PageState extends State<_Page> { + bool _useDark = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: NeumorphicBackground( + child: Column( + children: [ + SizedBox(height: 14), + _buildTopBar(context), + SizedBox(height: 80), + _buildImage(context), + SizedBox(height: 30), + _buildTitle(context), + SizedBox(height: 30), + _buildSeekBar(context), + SizedBox(height: 30), + _buildControlsBar(context), + ], + ), + ), + ), + ); + } + + Widget _buildTopBar(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Stack( + alignment: Alignment.center, + children: [ + Align( + alignment: Alignment.centerLeft, + child: NeumorphicButton( + padding: const EdgeInsets.all(18.0), + onPressed: () { + Navigator.of(context).pop(); + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Icon( + Icons.navigate_before, + color: _iconsColor(), + ), + ), + ), + Align( + alignment: Alignment.center, + child: Text( + "Now Playing", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + Align( + alignment: Alignment.centerRight, + child: NeumorphicButton( + padding: const EdgeInsets.all(18.0), + onPressed: () { + setState(() { + _useDark = !_useDark; + NeumorphicTheme.of(context).themeMode = + _useDark ? ThemeMode.dark : ThemeMode.light; + }); + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Icon( + Icons.favorite_border, + color: _iconsColor(), + ), + ), + ), + ], + ), + ); + } + + Widget _buildImage(BuildContext context) { + return Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + child: Container( + height: 200, + width: 200, + child: Image.asset( + "assets/images/weeknd.jpg", + fit: BoxFit.cover, + )), + ); + } + + Widget _buildTitle(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text("Blinding Lights", + style: TextStyle( + fontWeight: FontWeight.w800, + fontSize: 34, + color: NeumorphicTheme.defaultTextColor(context))), + const SizedBox( + height: 4, + ), + Text("The Weeknd", + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 14, + color: NeumorphicTheme.defaultTextColor(context))), + ], + ); + } + + Widget _buildSeekBar(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 28.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Stack( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + "2.00", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + )), + Align( + alignment: Alignment.centerRight, + child: Text( + "3.14", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + )), + ], + ), + SizedBox( + height: 8, + ), + NeumorphicSlider( + height: 8, + min: 0, + max: 314, + value: 100, + onChanged: (value) {}, + ) + ], + ), + ); + } + + Widget _buildControlsBar(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + NeumorphicButton( + padding: const EdgeInsets.all(18.0), + onPressed: () {}, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Icon( + Icons.skip_previous, + color: _iconsColor(), + ), + ), + const SizedBox(width: 12), + NeumorphicButton( + padding: const EdgeInsets.all(24.0), + onPressed: () {}, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Icon( + Icons.play_arrow, + size: 42, + color: _iconsColor(), + ), + ), + const SizedBox(width: 12), + NeumorphicButton( + padding: const EdgeInsets.all(18.0), + onPressed: () {}, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Icon( + Icons.skip_next, + color: _iconsColor(), + ), + ), + ], + ); + } + + Color _iconsColor() { + final theme = NeumorphicTheme.of(context); + if (theme.isUsingDark) { + return theme.current.accentColor; + } else { + return null; + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/calculator_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/calculator_sample.dart new file mode 100644 index 00000000..9a957576 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/calculator_sample.dart @@ -0,0 +1,237 @@ +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +class CalculatorSample extends StatefulWidget { + @override + createState() => _CalculatorSampleState(); +} + +final Color _calcTextColor = Color(0xFF484848); + +class _CalculatorSampleState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData( + baseColor: Color(0xFFF4F5F5), + intensity: 0.3, + lightSource: LightSource.topLeft, + variantColor: Colors.red, + depth: 4, + ), + child: Scaffold( + body: SafeArea( + child: NeumorphicBackground(child: _PageContent()), + ), + ), + ); + } +} + +class _PageContent extends StatefulWidget { + @override + __PageContentState createState() => __PageContentState(); +} + +class CalcButton { + final String label; + final bool textAccent; + final bool textVariant; + final bool backgroundAccent; + + CalcButton( + this.label, { + this.textAccent = false, + this.backgroundAccent = false, + this.textVariant = false, + }); +} + +class WidgetCalcButton extends StatelessWidget { + final CalcButton button; + + WidgetCalcButton(this.button); + + Color _textColor(BuildContext context) { + if (button.backgroundAccent) { + return Colors.white; + } else if (button.textAccent) { + return NeumorphicTheme.accentColor(context); + } else if (button.textVariant) { + return NeumorphicTheme.variantColor(context); + } else { + return _calcTextColor; + } + } + + Color _backgroundColor(BuildContext context) { + return button.backgroundAccent + ? NeumorphicTheme.accentColor(context) + : null; + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(top: 14), + child: NeumorphicButton( + onPressed: () {}, + style: NeumorphicStyle( + surfaceIntensity: 0.15, + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.concave, + color: _backgroundColor(context), + ), + child: Center( + child: Text( + button.label, + style: TextStyle(fontSize: 24, color: _textColor(context)), + ), + ), + ), + ); + } +} + +class _TopScreenWidget extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(12)), + depth: -1 * NeumorphicTheme.of(context).current.depth, + ), + child: FractionallySizedBox( + widthFactor: 1, + child: Padding( + padding: const EdgeInsets.all(18.0), + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "3 x 7 =", + style: TextStyle(fontSize: 30, color: _calcTextColor), + ), + Text("21", style: TextStyle(fontSize: 56, color: _calcTextColor)), + ], + ), + ), + ), + ); + } +} + +class __PageContentState extends State<_PageContent> { + final buttons = [ + CalcButton("%", textAccent: true), + CalcButton("^", textAccent: true), + CalcButton("sqrt", textAccent: true), + CalcButton("C", textVariant: true), + //---- + CalcButton("7"), + CalcButton("8"), + CalcButton("9"), + CalcButton("/", textAccent: true), + //---- + CalcButton("4"), + CalcButton("5"), + CalcButton("6"), + CalcButton("X", textAccent: true), + //---- + CalcButton("1"), + CalcButton("2"), + CalcButton("3"), + CalcButton("-", textAccent: true), + //---- + CalcButton("0"), + CalcButton("."), + CalcButton("=", backgroundAccent: true), + CalcButton("+", textAccent: true), + ]; + + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.only(left: 18.0, top: 8), + child: NeumorphicButton( + onPressed: () { + Navigator.of(context).pop(); + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Icon(Icons.navigate_before), + ), + ), + ), + ), + Expanded( + flex: 1, + child: Padding( + padding: const EdgeInsets.all(18.0), + child: _TopScreenWidget(), + ), + ), + Expanded( + flex: 2, + child: GridView.count( + // Create a grid with 2 columns. If you change the scrollDirection to + // horizontal, this produces 2 rows. + crossAxisCount: 4, + padding: const EdgeInsets.only(left: 40, right: 40.0), + // Generate 100 widgets that display their index in the List. + children: List.generate(buttons.length, (index) { + return WidgetCalcButton(buttons[index]); + }), + ), + ), + Row( + children: [ + RaisedButton( + onPressed: () { + setState(() { + NeumorphicTheme.of(context) + .updateCurrentTheme(NeumorphicThemeData( + depth: 1, + intensity: 0.5, + accentColor: Colors.cyan, + )); + }); + }, + child: Text( + "style 1", + ), + ), + RaisedButton( + onPressed: () { + setState(() { + NeumorphicTheme.of(context) + .updateCurrentTheme(NeumorphicThemeData( + depth: 8, + intensity: 0.3, + accentColor: Colors.greenAccent, + )); + }); + }, + child: Text( + "style 2", + ), + ), + ], + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/clock/clock_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/clock/clock_sample.dart new file mode 100644 index 00000000..65226415 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/clock/clock_sample.dart @@ -0,0 +1,323 @@ +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +import 'clock_second_sample.dart'; + +class ClockSample extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData( + defaultTextColor: Color(0xFF303E57), + accentColor: Color(0xFF7B79FC), + variantColor: Colors.black38, + baseColor: Color(0xFFF8F9FC), + depth: 8, + intensity: 0.5, + lightSource: LightSource.topLeft), + themeMode: ThemeMode.light, + child: Material( + child: NeumorphicBackground( + child: _ClockFirstPage(), + ), + ), + ); + } +} + +class _ClockFirstPage extends StatefulWidget { + @override + createState() => _ClockFirstPageState(); +} + +class _ClockFirstPageState extends State<_ClockFirstPage> { + @override + Widget build(BuildContext context) { + return SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 9.0), + child: TopBar(), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 20.0), + child: Stack( + children: [ + Align( + alignment: Alignment.topLeft, + child: Text( + "Clock", + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 28, + shadows: [ + Shadow( + color: Colors.black38, + offset: Offset(1.0, 1.0), + blurRadius: 2) + ], + color: NeumorphicTheme.defaultTextColor(context), + ), + ), + ), + Align( + alignment: Alignment.topRight, + child: Neumorphic( + style: NeumorphicStyle( + depth: 20, + intensity: 0.4, + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(8)), + ), + child: NeumorphicButton( + padding: EdgeInsets.all(12.0), + child: Icon( + Icons.add, + color: Color(0xFFC1CDE5), + ), + onPressed: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return ClockAlarmPage(); + })); + }, + style: NeumorphicStyle( + depth: -1, + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(8))), + ), + ), + ), + ], + ), + ), + Flexible(child: NeumorphicClock()), + SizedBox(height: 30), + Text( + "6:21 PM", + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 36, + shadows: [ + Shadow( + color: Colors.black38, + offset: Offset(1.0, 1.0), + blurRadius: 2) + ], + color: NeumorphicTheme.defaultTextColor(context), + ), + ), + Text( + "London, Uk", + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 16, + color: NeumorphicTheme.variantColor(context), + ), + ), + SizedBox(height: 20), + NeumorphicSelector(), + SizedBox(height: 20), + ], + ), + ); + } +} + +class NeumorphicClock extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AspectRatio( + aspectRatio: 1, + child: Neumorphic( + margin: EdgeInsets.all(14), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + child: Neumorphic( + style: NeumorphicStyle( + depth: 14, + boxShape: NeumorphicBoxShape.circle(), + ), + margin: EdgeInsets.all(20), + child: Neumorphic( + style: NeumorphicStyle( + depth: -8, + boxShape: NeumorphicBoxShape.circle(), + ), + margin: EdgeInsets.all(10), + child: Stack( + fit: StackFit.expand, + alignment: Alignment.center, + children: [ + //the click center + Neumorphic( + style: NeumorphicStyle( + depth: -1, + boxShape: NeumorphicBoxShape.circle(), + ), + margin: EdgeInsets.all(65), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Stack( + children: [ + //those childs are not "good" for a real clock, but will fork for a sample + Align( + alignment: Alignment.topCenter, + child: _createDot(context), + ), + Align( + alignment: Alignment.centerLeft, + child: _createDot(context), + ), + Align( + alignment: Alignment(-0.7, -0.7), + child: _createDot(context), + ), + Align( + alignment: Alignment(0.7, -0.7), + child: _createDot(context), + ), + Align( + alignment: Alignment(-0.7, 0.7), + child: _createDot(context), + ), + Align( + alignment: Alignment(0.7, 0.7), + child: _createDot(context), + ), + Align( + alignment: Alignment.centerRight, + child: _createDot(context), + ), + Align( + alignment: Alignment.bottomCenter, + child: _createDot(context), + ), + _buildLine( + context: context, + angle: 0, + width: 70, + color: NeumorphicTheme.accentColor(context), + ), + _buildLine( + context: context, + angle: 0.9, + width: 100, + color: NeumorphicTheme.accentColor(context), + ), + _buildLine( + context: context, + angle: 2.2, + width: 120, + height: 1, + color: NeumorphicTheme.variantColor(context), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildLine( + {BuildContext context, + double angle, + double width, + double height = 6, + Color color}) { + return Transform.rotate( + angle: angle, + child: Center( + child: Padding( + padding: EdgeInsets.only(left: width), + child: Neumorphic( + style: NeumorphicStyle( + depth: 20, + ), + child: Container( + width: width, + height: height, + color: color, + ), + ), + ), + ), + ); + } + + Widget _createDot(BuildContext context) { + return Neumorphic( + style: NeumorphicStyle( + depth: -10, + boxShape: NeumorphicBoxShape.circle(), + ), + child: SizedBox( + height: 10, + width: 10, + ), + ); + } +} + +class NeumorphicSelector extends StatelessWidget { + final double _elementHeight = 14; + final double _spacing = 10; + + Widget _buildSimpleButton(BuildContext context) { + return Neumorphic( + style: NeumorphicStyle( + depth: -4, + boxShape: NeumorphicBoxShape.circle(), + ), + child: SizedBox( + height: _elementHeight, + width: _elementHeight, + ), + ); + } + + Widget _buildSelectedButton(BuildContext context) { + return Neumorphic( + style: NeumorphicStyle( + depth: -4, + boxShape: NeumorphicBoxShape.stadium(), + color: Color(0xffE1E8F5), + ), + child: SizedBox( + height: _elementHeight, + width: 30, + ), + ); + } + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _buildSimpleButton(context), + SizedBox( + width: _spacing, + ), + _buildSelectedButton(context), + SizedBox( + width: _spacing, + ), + _buildSimpleButton(context), + SizedBox( + width: _spacing, + ), + _buildSimpleButton(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/clock/clock_second_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/clock/clock_second_sample.dart new file mode 100644 index 00000000..a868fdbf --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/clock/clock_second_sample.dart @@ -0,0 +1,237 @@ +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class ClockAlarmPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData( + defaultTextColor: Color(0xFF303E57), + accentColor: Color(0xFF7B79FC), + variantColor: Colors.black38, + baseColor: Color(0xFFF8F9FC), + depth: 8, + intensity: 0.5, + lightSource: LightSource.topLeft), + themeMode: ThemeMode.light, + child: Material( + child: NeumorphicBackground( + child: _Page(), + ), + ), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _ClockPageState(); +} + +class _ClockPageState extends State<_Page> { + final List items = [ + Alarm( + enabled: true, + time: "8:30 AM", + label: "Awake !", + ), + Alarm( + enabled: false, + time: "8:45 AM", + label: "Wake up !", + ), + Alarm( + enabled: false, + time: "9:00 AM", + label: "Hurry up !", + ), + Alarm( + enabled: false, + time: "2:00 AM", + label: "Lunchtime", + ) + ]; + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 9.0), + child: TopBar(), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 20.0), + child: Stack( + children: [ + Align( + alignment: Alignment.topLeft, + child: Text( + "Alarm", + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 28, + shadows: [ + Shadow( + color: Colors.black38, + offset: Offset(1.0, 1.0), + blurRadius: 2) + ], + color: NeumorphicTheme.defaultTextColor(context), + ), + ), + ), + Align( + alignment: Alignment.topRight, + child: Neumorphic( + style: NeumorphicStyle( + depth: 20, + intensity: 0.4, + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(8)), + ), + child: NeumorphicButton( + padding: EdgeInsets.all(12.0), + child: Icon( + Icons.add, + color: Color(0xFFC1CDE5), + ), + style: NeumorphicStyle( + depth: -1, + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(8)), + ), + ), + ), + ), + ], + ), + ), + SizedBox( + height: 20, + ), + _Divider(), + Expanded( + child: ListView.builder( + itemBuilder: (context, index) { + return AlarmCell(this.items[index]); + }, + itemCount: items.length, + ), + ) + ], + ), + ); + } +} + +class AlarmCell extends StatelessWidget { + final Alarm alarm; + + AlarmCell(this.alarm); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + alarm.time, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 36, + shadows: [ + Shadow( + color: Colors.black38, + offset: Offset(1.0, 1.0), + blurRadius: 2) + ], + color: NeumorphicTheme.defaultTextColor(context), + ), + ), + SizedBox(height: 4), + Text( + alarm.label, + style: TextStyle( + fontWeight: FontWeight.w300, + fontSize: 14, + color: NeumorphicTheme.variantColor(context), + ), + ), + ], + ), + ), + Flexible( + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Padding( + padding: EdgeInsets.only(right: 20), + child: Neumorphic( + style: NeumorphicStyle( + depth: 8, + intensity: 0.5, + boxShape: NeumorphicBoxShape.stadium(), + ), + child: NeumorphicSwitch( + style: NeumorphicSwitchStyle( + inactiveTrackColor: Color(0xffC1CDE5)), + height: 30, + value: alarm.enabled, + ), + ), + ), + ], + ), + ), + ], + ), + ), + _Divider(), + ], + ); + } +} + +class _Divider extends StatelessWidget { + @override + Widget build(BuildContext context) { + return FractionallySizedBox( + widthFactor: 1, + child: Neumorphic( + margin: EdgeInsets.symmetric(horizontal: 10, vertical: 5), + style: NeumorphicStyle( + depth: -4, + boxShape: NeumorphicBoxShape.stadium(), + ), + child: SizedBox( + height: 6, + ), + ), + ); + } +} + +class Alarm { + final bool enabled; + final String time; + final String label; + + const Alarm({ + @required this.enabled, + @required this.time, + @required this.label, + }); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/credit_card_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/credit_card_sample.dart new file mode 100644 index 00000000..46f67578 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/credit_card_sample.dart @@ -0,0 +1,383 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import '../lib/flutter_neumorphic.dart'; + +class CreditCardSample extends StatefulWidget { + @override + createState() => _CreditCardSampleState(); +} + +class _CreditCardSampleState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData( + intensity: 0.6, lightSource: LightSource.topLeft, depth: 5), + child: Scaffold( + body: SafeArea( + child: NeumorphicBackground(child: _PageContent()), + ), + ), + ); + } +} + +class _PageContent extends StatefulWidget { + @override + __PageContentState createState() => __PageContentState(); +} + +class __PageContentState extends State<_PageContent> { + int _dotIndex = 1; + bool _useDark = false; + + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + borderRadius: BorderRadius.circular(12), + margin: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 14), + _buildTopBar(context), + SizedBox(height: 30), + Expanded(child: _buildCard(context)), + SizedBox(height: 30), + _buildDots(context), + SizedBox(height: 30), + _buildBalance(context), + SizedBox(height: 30), + _buildIndicator(context), + SizedBox(height: 30), + ], + ), + ); + } + + Widget _buildCard(BuildContext context) { + return Container( + child: Neumorphic( + style: NeumorphicStyle( + depth: 10, + boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(20)), + shape: NeumorphicShape.flat, + ), + child: Neumorphic( + margin: EdgeInsets.all(8), + style: NeumorphicStyle( + depth: 10, + boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(20)), + shape: NeumorphicShape.flat, + ), + child: SizedBox( + height: 200, + child: AspectRatio( + aspectRatio: 9 / 16, + child: Stack( + fit: StackFit.expand, + children: [ + //Image.asset("assets/images/map.jpg", fit: BoxFit.cover), + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 3, sigmaY: 3), + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [ + Colors.purple.withOpacity(0.5), + Colors.red.withOpacity(0.5) + ])), + ), + ), + Stack( + children: [ + Positioned( + top: 12, + left: 16, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "VISA", + style: TextStyle( + fontSize: 40, + color: Colors.white, + fontWeight: FontWeight.w800), + ), + SizedBox( + height: 30, + ), + Text( + "1234 5678", + style: TextStyle( + fontSize: 30, + color: Colors.black.withOpacity(0.7)), + ), + SizedBox( + height: 3, + ), + Text( + "1234 5678", + style: TextStyle( + fontSize: 30, + color: Colors.black.withOpacity(0.7)), + ), + ], + ), + ), + Positioned( + top: 12, + right: 16, + child: SizedBox( + height: 60, + child: Neumorphic( + style: NeumorphicStyle( + depth: 5, + intensity: 0.8, + lightSource: LightSource.topLeft, + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(12), + ), + ), + child: RotatedBox( + quarterTurns: 1, + child: Image.asset( + "assets/images/credit_card_chip.png")), + ), + ), + ), + Positioned( + bottom: 12, + right: 16, + child: Column( + children: [ + Text( + "09/24", + style: TextStyle( + fontSize: 20, + color: Colors.white.withOpacity(0.7)), + ), + SizedBox( + height: 8, + ), + Stack( + children: [ + Neumorphic( + style: NeumorphicStyle( + shape: NeumorphicShape.convex, + depth: -10, + boxShape: NeumorphicBoxShape.circle(), + color: Colors.grey[300]), + child: const SizedBox( + height: 30, + width: 30, + ), + ), + Padding( + padding: EdgeInsets.only(left: 18), + child: Neumorphic( + style: NeumorphicStyle( + shape: NeumorphicShape.convex, + boxShape: NeumorphicBoxShape.circle(), + depth: 10), + child: const SizedBox( + height: 30, + width: 30, + ), + ), + ), + ], + ), + ], + ), + ) + ], + ), + ], + ), + ), + ), + ), + ), + ); + } + + Widget _buildTopBar(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Stack( + alignment: Alignment.center, + children: [ + Align( + alignment: Alignment.centerLeft, + child: NeumorphicButton( + onPressed: () { + Navigator.of(context).pop(); + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Icon(Icons.navigate_before), + ), + ), + ), + Align(alignment: Alignment.center, child: Text("Card")), + Align( + alignment: Alignment.centerRight, + child: NeumorphicButton( + onPressed: () { + setState(() { + _useDark = !_useDark; + + NeumorphicTheme.of(context).themeMode = + _useDark ? ThemeMode.dark : ThemeMode.light; + }); + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Icon(Icons.loop), + ), + ), + ), + ], + ), + ); + } + + Widget _buildBalance(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 28.0), + child: Stack( + alignment: Alignment.center, + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text("Balance", + style: TextStyle( + fontWeight: FontWeight.w800, + fontSize: 30, + color: Color(0xFF3E3E3E)))), + Align( + alignment: Alignment.centerRight, + child: Text("\$ 14,020.44", + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF3E3E3E)))), + ], + ), + ); + } + + Widget _buildIndicator(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 28.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: 8, + ), + NeumorphicIndicator( + percent: 0.3, + padding: EdgeInsets.all(3), + orientation: NeumorphicIndicatorOrientation.horizontal, + height: 20, + style: IndicatorStyle( + accent: Colors.grey[100], + variant: Colors.grey[400], + ), + ), + SizedBox( + height: 8, + ), + Stack( + children: [ + Align( + alignment: Alignment.centerLeft, child: Text("Credit limit")), + Align( + alignment: Alignment.centerRight, + child: Text("\$ 220 / \$ 1000")), + ], + ), + ], + ), + ); + } + + Widget _buildDots(BuildContext context) { + final double dotsSize = 18; + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: dotsSize, + height: dotsSize, + child: NeumorphicRadio( + groupValue: _dotIndex, + value: 0, + onChanged: (value) { + setState(() { + _dotIndex = value; + }); + }, + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.convex, + ), + ), + ), + SizedBox( + width: 10, + ), + SizedBox( + width: dotsSize, + height: dotsSize, + child: NeumorphicRadio( + groupValue: _dotIndex, + value: 1, + onChanged: (value) { + setState(() { + _dotIndex = value; + }); + }, + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.convex, + ), + ), + ), + SizedBox( + width: 10, + ), + SizedBox( + width: dotsSize, + height: dotsSize, + child: NeumorphicRadio( + groupValue: _dotIndex, + value: 2, + onChanged: (value) { + setState(() { + _dotIndex = value; + }); + }, + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.convex, + ), + ), + ) + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/form_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/form_sample.dart new file mode 100644 index 00000000..1ecd3474 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/form_sample.dart @@ -0,0 +1,348 @@ +import '../lib/ThemeConfigurator.dart'; +import '../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +class FormSample extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData( + defaultTextColor: Color(0xFF3E3E3E), + accentColor: Colors.grey, + variantColor: Colors.black38, + depth: 8, + intensity: 0.65, + ), + themeMode: ThemeMode.light, + child: Material( + child: NeumorphicBackground( + child: _Page(), + ), + ), + ); + } +} + +class _Page extends StatefulWidget { + @override + __PageState createState() => __PageState(); +} + +enum Gender { MALE, FEMALE, NON_BINARY } + +class __PageState extends State<_Page> { + String firstName = ""; + String lastName = ""; + double age = 12; + Gender gender; + Set rides = Set(); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(left: 12, right: 12, top: 10), + child: TopBar( + actions: [ + ThemeConfigurator(), + ], + ), + ), + Neumorphic( + margin: EdgeInsets.symmetric(horizontal: 16, vertical: 12), + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), + style: NeumorphicStyle( + boxShape: + NeumorphicBoxShape.roundRect(BorderRadius.circular(12)), + ), + child: Column( + children: [ + SizedBox( + height: 8, + ), + Align( + alignment: Alignment.centerRight, + child: NeumorphicButton( + onPressed: _isButtonEnabled() ? () {} : null, + padding: + EdgeInsets.symmetric(horizontal: 20, vertical: 20), + child: Text( + "Sign Up", + style: TextStyle(fontWeight: FontWeight.w800), + ), + ), + ), + _AvatarField(), + SizedBox( + height: 8, + ), + _TextField( + label: "First name", + hint: "", + onChanged: (firstName) { + setState(() { + this.firstName = firstName; + }); + }, + ), + SizedBox( + height: 8, + ), + _TextField( + label: "Last name", + hint: "", + onChanged: (lastName) { + setState(() { + this.lastName = lastName; + }); + }, + ), + SizedBox( + height: 8, + ), + _AgeField( + age: this.age, + onChanged: (age) { + setState(() { + this.age = age; + }); + }, + ), + SizedBox( + height: 8, + ), + _GenderField( + gender: gender, + onChanged: (gender) { + setState(() { + this.gender = gender; + }); + }, + ), + SizedBox( + height: 8, + ), + /* + _RideField( + rides: this.rides, + onChanged: (rides) { + setState(() { + this.rides = rides; + }); + }, + ), + SizedBox( + height: 28, + ), + */ + SizedBox( + height: 20, + ), + ], + ), + ) + ], + ), + ), + ); + } + + bool _isButtonEnabled() { + return this.firstName.isNotEmpty && this.lastName.isNotEmpty; + } +} + +class _AvatarField extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Center( + child: Neumorphic( + padding: EdgeInsets.all(10), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + depth: NeumorphicTheme.embossDepth(context), + ), + child: Icon( + Icons.insert_emoticon, + size: 120, + color: Colors.black.withOpacity(0.2), + ), + ), + ); + } +} + +class _AgeField extends StatelessWidget { + final double age; + final ValueChanged onChanged; + + _AgeField({@required this.age, this.onChanged}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 8), + child: Text( + "Age", + style: TextStyle( + fontWeight: FontWeight.w700, + color: NeumorphicTheme.defaultTextColor(context), + ), + ), + ), + Row( + children: [ + Flexible( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 18.0), + child: NeumorphicSlider( + min: 8, + max: 75, + value: this.age, + onChanged: (value) { + this.onChanged(value); + }, + ), + ), + ), + Text("${this.age.floor()}"), + SizedBox( + width: 18, + ) + ], + ), + ], + ); + } +} + +class _TextField extends StatefulWidget { + final String label; + final String hint; + + final ValueChanged onChanged; + + _TextField({@required this.label, @required this.hint, this.onChanged}); + + @override + __TextFieldState createState() => __TextFieldState(); +} + +class __TextFieldState extends State<_TextField> { + TextEditingController _controller; + + @override + void initState() { + _controller = TextEditingController(text: widget.hint); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 8), + child: Text( + this.widget.label, + style: TextStyle( + fontWeight: FontWeight.w700, + color: NeumorphicTheme.defaultTextColor(context), + ), + ), + ), + Neumorphic( + margin: EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 4), + style: NeumorphicStyle( + depth: NeumorphicTheme.embossDepth(context), + boxShape: NeumorphicBoxShape.stadium(), + ), + padding: EdgeInsets.symmetric(vertical: 14, horizontal: 18), + child: TextField( + onChanged: this.widget.onChanged, + controller: _controller, + decoration: InputDecoration.collapsed(hintText: this.widget.hint), + ), + ) + ], + ); + } +} + +class _GenderField extends StatelessWidget { + final Gender gender; + final ValueChanged onChanged; + + const _GenderField({ + @required this.gender, + @required this.onChanged, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 8), + child: Text( + "Gender", + style: TextStyle( + fontWeight: FontWeight.w700, + color: NeumorphicTheme.defaultTextColor(context), + ), + ), + ), + Row( + children: [ + SizedBox(width: 12), + NeumorphicRadio( + groupValue: this.gender, + padding: EdgeInsets.all(20), + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + value: Gender.MALE, + child: Icon(Icons.account_box), + onChanged: (value) => this.onChanged(value), + ), + SizedBox(width: 12), + NeumorphicRadio( + groupValue: this.gender, + padding: EdgeInsets.all(20), + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + value: Gender.FEMALE, + child: Icon(Icons.pregnant_woman), + onChanged: (value) => this.onChanged(value), + ), + SizedBox(width: 12), + NeumorphicRadio( + groupValue: this.gender, + padding: EdgeInsets.all(20), + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + value: Gender.NON_BINARY, + child: Icon(Icons.supervised_user_circle), + onChanged: (value) => this.onChanged(value), + ), + SizedBox( + width: 18, + ) + ], + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/galaxy_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/galaxy_sample.dart new file mode 100644 index 00000000..3e39a44e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/galaxy_sample.dart @@ -0,0 +1,133 @@ +import '../lib/ThemeConfigurator.dart'; +import '../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +class GalaxySample extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData( + baseColor: Color(0xFFE5E5E5), + depth: 20, + intensity: 1, + lightSource: LightSource.top, + ), + themeMode: ThemeMode.light, + child: Material( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Color(0xFFF1F1F1), + Color(0xFFCFCFCF), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + )), + child: _Page()), + ), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + Widget _letter(String letter) { + return Text(letter, + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w700, + fontFamily: 'Samsung', + fontSize: 80)); + } + + Widget _firstBox() { + return Neumorphic( + margin: EdgeInsets.symmetric(horizontal: 4), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(8)), + ), + child: Neumorphic( + style: NeumorphicStyle( + depth: -1, + oppositeShadowLightSource: true, + ), + padding: EdgeInsets.all(2), + child: SizedBox( + width: 40, + height: 60, + ), + ), + ); + } + + Widget _secondBox() { + return Padding( + padding: const EdgeInsets.only(left: 8.0, right: 4), + child: Transform.rotate( + angle: 0.79, + child: Neumorphic( + style: NeumorphicStyle( + lightSource: LightSource.topLeft, + boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(8)), + ), + child: Neumorphic( + style: NeumorphicStyle( + depth: -1, + oppositeShadowLightSource: true, + lightSource: LightSource.topLeft, + ), + child: SizedBox( + width: 50, + height: 50, + ), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Stack( + fit: StackFit.expand, + children: [ + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + margin: EdgeInsets.only(left: 12, right: 12, top: 10), + child: TopBar( + actions: [ + ThemeConfigurator(), + ], + ), + ), + ), + Center( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _letter("G"), + _firstBox(), + _letter("l"), + _secondBox(), + _letter("x"), + _letter("y"), + ], + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/sample_home.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/sample_home.dart new file mode 100644 index 00000000..d43265e9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/sample_home.dart @@ -0,0 +1,122 @@ +import '../lib/top_bar.dart'; +import '../samples/audio_player_sample.dart'; +import '../samples/calculator_sample.dart'; +import '../samples/clock/clock_sample.dart'; +import '../samples/credit_card_sample.dart'; +import '../samples/form_sample.dart'; +import '../samples/testla_sample.dart'; +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +import 'galaxy_sample.dart'; +import 'widgets_sample.dart'; + +class SamplesHome extends StatelessWidget { + Widget _buildButton({String text, VoidCallback onClick}) { + return NeumorphicButton( + margin: EdgeInsets.only(bottom: 12), + padding: EdgeInsets.symmetric( + vertical: 18, + horizontal: 24, + ), + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(12), + ), + ), + child: Center(child: Text(text)), + onPressed: onClick, + ); + } + + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData(depth: 8), + darkTheme: NeumorphicThemeData(depth: 8), + child: Scaffold( + backgroundColor: NeumorphicColors.background, + body: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(18.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + TopBar(), + _buildButton( + text: "Tesla", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return TeslaSample(); + })); + }), + _buildButton( + text: "Audio Player", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return AudioPlayerSample(); + })); + }), + _buildButton( + text: "Clock", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return ClockSample(); + })); + }), + _buildButton( + text: "Galaxy", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return GalaxySample(); + })); + }), + _buildButton( + text: "Calculator", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return CalculatorSample(); + })); + }), + _buildButton( + text: "Form", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return FormSample(); + })); + }), + _buildButton( + text: "CreditCard", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return CreditCardSample(); + })); + }), + _buildButton( + text: "Widgets", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return WidgetsSample(); + })); + }), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/testla_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/testla_sample.dart new file mode 100644 index 00000000..5ee12bbc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/testla_sample.dart @@ -0,0 +1,228 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import '../lib/flutter_neumorphic.dart'; + +class TeslaSample extends StatefulWidget { + @override + createState() => _TeslaSampleState(); +} + +class _TeslaSampleState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData( + baseColor: Color(0xFF30353B), + intensity: 0.3, + accentColor: Color(0xFF0F95E6), + lightSource: LightSource.topLeft, + depth: 2, + ), + child: Scaffold( + body: SafeArea( + child: NeumorphicBackground(child: _PageContent()), + ), + ), + ); + } +} + +class _PageContent extends StatefulWidget { + @override + __PageContentState createState() => __PageContentState(); +} + +class __PageContentState extends State<_PageContent> { + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Color(0xFF373C43), + Color(0xFF17181C), + ], begin: Alignment.topCenter, end: Alignment.bottomCenter)), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + _buildTopBar(context), + Expanded(flex: 2, child: _buildTitle(context)), + Expanded(flex: 5, child: _buildCenterContent(context)), + _buildBottomAction(context), + ], + ), + ); + } + + Widget _buildTopBar(BuildContext context) { + return Stack( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 24), + child: _bumpButton( + Icon( + Icons.arrow_back, + color: Colors.grey, + ), + ), + ), + ), + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 24), + child: _bumpButton( + Icon( + Icons.settings, + color: Colors.grey, + ), + ), + ), + ) + ], + ); + } + + Widget _bumpButton(Widget child) { + return Neumorphic( + drawSurfaceAboveChild: false, + style: NeumorphicStyle( + color: Color(0xFF2D3238), + depth: 8, + boxShape: NeumorphicBoxShape.circle(), + intensity: 0.3, + shape: NeumorphicShape.concave, + ), + child: NeumorphicButton( + onPressed: () {}, + margin: EdgeInsets.all(3), + padding: EdgeInsets.all(14.0), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + color: Color(0xFF212528), + depth: 0, + shape: NeumorphicShape.convex, + ), + child: child), + ); + } + + Widget _buildTitle(BuildContext context) { + return Column( + children: [ + Text( + "Tesla", + style: TextStyle( + color: Colors.white30, + ), + ), + Text( + "CyberTruck", + style: TextStyle( + fontSize: 30, + fontWeight: FontWeight.w800, + color: Colors.white, + ), + ), + ], + ); + } + + Widget _buildCenterContent(BuildContext context) { + return Stack( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "297", + style: TextStyle( + color: Colors.white, + fontSize: 120, + fontWeight: FontWeight.w200), + ), + Text( + "km", + style: TextStyle(color: Colors.white, fontSize: 10), + ), + ], + ), + Positioned( + right: 0, + child: SizedBox( + height: 280, + child: Padding( + padding: EdgeInsets.only(top: 35), + child: Image.asset( + "assets/images/tesla_cropped.png", + fit: BoxFit.contain, + ), + ), + ), + ), + ], + ); + } + + Widget _buildBottomAction(BuildContext context) { + return Padding( + padding: EdgeInsets.only(bottom: 18), + child: Column( + children: [ + Text( + "A/C is turned on", + style: TextStyle( + color: Colors.white30, + ), + ), + SizedBox( + height: 20, + ), + NeumorphicButton( + drawSurfaceAboveChild: false, + onPressed: () {}, + padding: EdgeInsets.all(4), + style: NeumorphicStyle( + depth: 10, + boxShape: NeumorphicBoxShape.circle(), + color: NeumorphicTheme.accentColor(context), + shape: NeumorphicShape.flat, + ), + child: Neumorphic( + style: NeumorphicStyle( + surfaceIntensity: 0.7, + depth: 0, + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.concave, + color: NeumorphicTheme.accentColor(context), + ), + child: SizedBox( + height: 80, + width: 80, + child: Icon( + Icons.lock, + size: 30, + color: Colors.white, + ), + ), + ), + ), + SizedBox( + height: 20, + ), + Text( + "Tap to open the car", + style: TextStyle( + color: Colors.white, + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/widgets_sample.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/widgets_sample.dart new file mode 100644 index 00000000..7b7de690 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/samples/widgets_sample.dart @@ -0,0 +1,442 @@ +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +class WidgetsSample extends StatefulWidget { + WidgetsSample({Key key}) : super(key: key); + + @override + createState() => _ContainersListPageState(); +} + +class _ContainersListPageState extends State { + int _groupValue; + bool _switchConcaveEnabled = false; + bool _switchConvexEnabled = false; + bool _switchFlatEnabled = false; + + bool useDark = false; + + Color _textColor() { + if (useDark) + return Colors.white70; + else { + return Colors.black; + } + } + + Widget _buildProgress() { + return Row( + children: [ + Text( + "Progress", + style: TextStyle(color: _textColor()), + ), + SizedBox(width: 12), + Flexible( + child: NeumorphicProgress( + height: 15, + percent: 0.55, + ), + ), + SizedBox(width: 12), + ], + ); + } + + Widget _buildIndeterminateProgress() { + return Row( + children: [ + Text( + "Progress", + style: TextStyle(color: _textColor()), + ), + SizedBox(width: 12), + Flexible( + child: NeumorphicProgressIndeterminate( + height: 10, + ), + ), + SizedBox(width: 12), + ], + ); + } + + Widget _buildButtons() { + return Row( + children: [ + Text( + "Buttons", + style: TextStyle(color: _textColor()), + ), + SizedBox(width: 4), + NeumorphicButton( + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.stadium(), + ), + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 18), + child: Text( + "button 1", + style: TextStyle(color: _textColor()), + ), + onPressed: () { + setState(() { + useDark = !useDark; + }); + }, + ), + SizedBox(width: 10), + NeumorphicButton( + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.stadium(), + ), + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 18), + child: Text( + "button 2", + style: TextStyle(color: _textColor()), + ), + onPressed: () {}, + ), + ], + ); + } + + Widget _buildRadios() { + return Row( + children: [ + Text( + "Radio", + style: TextStyle(color: _textColor()), + ), + SizedBox(width: 12), + NeumorphicRadio( + child: SizedBox( + height: 50, + width: 50, + child: Center( + child: Text( + "1", + style: TextStyle(color: _textColor()), + ), + ), + ), + value: 1, + groupValue: _groupValue, + onChanged: (value) { + setState(() { + _groupValue = value; + }); + }, + ), + SizedBox(width: 12), + NeumorphicRadio( + child: SizedBox( + height: 50, + width: 50, + child: Center( + child: Text( + "2", + style: TextStyle(color: _textColor()), + ), + ), + ), + value: 2, + groupValue: _groupValue, + onChanged: (value) { + setState(() { + _groupValue = value; + }); + }, + ), + SizedBox(width: 12), + NeumorphicRadio( + child: SizedBox( + height: 50, + width: 50, + child: Center( + child: Text( + "3", + style: TextStyle(color: _textColor()), + ), + ), + ), + value: 3, + groupValue: _groupValue, + onChanged: (value) { + setState(() { + _groupValue = value; + }); + }, + ), + ], + ); + } + + bool check1 = false; + bool check2 = false; + bool check3 = false; + + Widget _buildChecks() { + return Row( + children: [ + Text( + "Checkbox", + style: TextStyle(color: _textColor()), + ), + SizedBox(width: 12), + NeumorphicCheckbox( + value: check1, + onChanged: (value) { + setState(() { + check1 = value; + }); + }, + ), + SizedBox(width: 12), + NeumorphicCheckbox( + value: check2, + onChanged: (value) { + setState(() { + check2 = value; + }); + }, + ), + SizedBox(width: 12), + NeumorphicCheckbox( + value: check3, + onChanged: (value) { + setState(() { + check3 = value; + }); + }, + ), + ], + ); + } + + Widget _buildIndicators() { + final width = 14.0; + return SizedBox( + height: 130, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + NeumorphicIndicator( + width: width, + percent: 0.4, + ), + SizedBox(width: 10), + NeumorphicIndicator( + width: width, + percent: 0.2, + ), + SizedBox(width: 10), + NeumorphicIndicator( + width: width, + percent: 0.5, + ), + SizedBox(width: 10), + NeumorphicIndicator( + width: width, + percent: 1, + ), + SizedBox(width: 10), + NeumorphicIndicator( + width: width, + percent: 0.4, + ), + SizedBox(width: 10), + NeumorphicIndicator( + width: width, + percent: 0.2, + ), + SizedBox(width: 10), + NeumorphicIndicator( + width: width, + percent: 0.5, + ), + SizedBox(width: 10), + NeumorphicIndicator( + width: width, + percent: 1, + ), + ], + ), + ); + } + + double seekValue = 0; + + Widget _buildSlider() { + return Row( + children: [ + Text( + "Slider", + style: TextStyle(color: _textColor()), + ), + SizedBox(width: 12), + Flexible( + child: NeumorphicSlider( + height: 15, + value: seekValue, + min: 0, + max: 10, + onChanged: (value) { + setState(() { + seekValue = value; + }); + }), + ), + SizedBox(width: 12), + Text( + "value: ${seekValue.round()}", + style: TextStyle(color: _textColor()), + ), + SizedBox(width: 12), + ], + ); + } + + Widget _buildSwitches() { + return Row(children: [ + Text( + "Switch", + style: TextStyle(color: _textColor()), + ), + SizedBox(width: 15), + NeumorphicSwitch( + value: _switchConcaveEnabled, + style: NeumorphicSwitchStyle( + thumbShape: NeumorphicShape.concave, // concave or flat with elevation + ), + onChanged: (value) { + setState(() { + _switchConcaveEnabled = value; + }); + }, + ), + SizedBox(width: 15), + NeumorphicSwitch( + value: _switchFlatEnabled, + style: NeumorphicSwitchStyle( + thumbShape: NeumorphicShape.flat, // concave or flat with elevation + ), + onChanged: (value) { + setState(() { + _switchFlatEnabled = value; + }); + }, + ), + SizedBox(width: 15), + NeumorphicSwitch( + value: _switchConvexEnabled, + style: NeumorphicSwitchStyle( + thumbShape: NeumorphicShape.convex, + ), + onChanged: (value) { + setState(() { + _switchConvexEnabled = value; + }); + }, + ), + ]); + } + + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: useDark ? ThemeMode.dark : ThemeMode.light, + darkTheme: NeumorphicThemeData( + baseColor: NeumorphicColors.darkBackground, + accentColor: NeumorphicColors.darkAccent, + lightSource: LightSource.topLeft, + depth: 6, + intensity: 0.3, + ), + theme: NeumorphicThemeData( + baseColor: NeumorphicColors.background, + lightSource: LightSource.topLeft, + depth: 10, + intensity: 0.5, + ), + child: Scaffold( + body: FractionallySizedBox( + //match parent height + heightFactor: 1, + child: NeumorphicBackground( + //margin: EdgeInsets.all(10), + //borderRadius: BorderRadius.circular(40), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Stack( + children: [ + Neumorphic( + child: AppBar( + iconTheme: IconThemeData.fallback(), + backgroundColor: Colors.transparent, + elevation: 0, + title: Text( + "Widgets", + style: TextStyle(color: Colors.black), + ), + ), + style: NeumorphicStyle(depth: -8), + ), + /* + Positioned( + right: 0, + bottom: 0, + child: NeumorphicButton( + onClick: (){ + setState(() { + useDark = !useDark; + }); + }, + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8), + child: Text(useDark ? "Dark" : "Light"), + ), + ) + */ + ], + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 18.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + SizedBox(height: 30), + _buildProgress(), + SizedBox(height: 12), + _buildIndeterminateProgress(), + SizedBox(height: 30), + _buildButtons(), + SizedBox(height: 30), + _buildRadios(), + SizedBox(height: 30), + _buildIndicators(), + SizedBox(height: 30), + _buildChecks(), + SizedBox(height: 30), + _buildSlider(), + SizedBox(height: 30), + _buildSwitches(), + SizedBox(height: 30), + ], + ), + ) + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/border/tips_border.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/border/tips_border.dart new file mode 100644 index 00000000..306bce6a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/border/tips_border.dart @@ -0,0 +1,263 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class TipsBorderPage extends StatefulWidget { + TipsBorderPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.6, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Border", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _CustomWidget( + title: "Emboss Inside Flat", + firstStyle: NeumorphicStyle( + shape: NeumorphicShape.flat, + depth: 8, + ), + secondStyle: NeumorphicStyle( + depth: -8, + ), + ), + _CustomWidget( + title: "Emboss Inside Convex", + firstStyle: NeumorphicStyle( + shape: NeumorphicShape.convex, + depth: 8, + ), + secondStyle: NeumorphicStyle( + depth: -8, + ), + ), + _CustomWidget( + title: "Emboss Inside Concave", + firstStyle: NeumorphicStyle( + shape: NeumorphicShape.concave, + depth: 8, + ), + secondStyle: NeumorphicStyle( + depth: -8, + ), + ), + _CustomWidget( + title: "Flat Inside Emboss", + firstStyle: NeumorphicStyle( + depth: -8, + ), + secondStyle: NeumorphicStyle( + depth: 8, + shape: NeumorphicShape.flat, + ), + ), + _CustomWidget( + title: "Convex Inside Emboss", + firstStyle: NeumorphicStyle( + depth: -8, + ), + secondStyle: NeumorphicStyle( + depth: 8, + shape: NeumorphicShape.convex, + ), + ), + _CustomWidget( + title: "Concave Inside Emboss", + firstStyle: NeumorphicStyle( + depth: -8, + ), + secondStyle: NeumorphicStyle( + depth: 8, + shape: NeumorphicShape.concave, + ), + ), + _CustomWidget( + title: "Concave Inside Convex", + firstStyle: NeumorphicStyle( + depth: 8, + shape: NeumorphicShape.convex, + ), + secondStyle: NeumorphicStyle( + depth: 8, + shape: NeumorphicShape.concave, + ), + ), + _CustomWidget( + title: "Convex Inside Concave", + firstStyle: NeumorphicStyle( + depth: 8, + shape: NeumorphicShape.concave, + ), + secondStyle: NeumorphicStyle( + depth: 8, + shape: NeumorphicShape.convex, + ), + ), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _CustomWidget extends StatefulWidget { + final String title; + + final NeumorphicStyle firstStyle; + final NeumorphicStyle secondStyle; + + _CustomWidget( + {@required this.title, + @required this.firstStyle, + @required this.secondStyle}); + + @override + createState() => _CustomWidgetState(); +} + +class _CustomWidgetState extends State<_CustomWidget> { + String _describe(NeumorphicStyle style) { + return "NeumorphicStyle(depth: ${style.depth}, oppositeShadowLightSource: ${style.oppositeShadowLightSource}, ...)"; + } + + Widget _buildCode(BuildContext context) { + return Code(""" +Neumorphic( + padding: EdgeInsets.all(20), + boxShape: NeumorphicBoxShape.circle(), + style: ${_describe(widget.firstStyle)}, + child: Neumorphic( + boxShape: NeumorphicBoxShape.circle(), + style: ${_describe(widget.secondStyle)}, + child: SizedBox( + height: 100, + width: 100, + ), + ), + ), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + children: [ + Container( + margin: EdgeInsets.only(left: 12, right: 12), + width: 100, + child: Text( + widget.title, + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + Neumorphic( + padding: EdgeInsets.all(20), + style: widget.firstStyle.copyWith( + boxShape: NeumorphicBoxShape.circle(), + ), + child: Neumorphic( + style: widget.secondStyle.copyWith( + boxShape: NeumorphicBoxShape.circle(), + ), + child: SizedBox( + height: 100, + width: 100, + ), + ), + ), + SizedBox(width: 12), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Container( + margin: EdgeInsets.only(left: 12, right: 12), + width: 100, + child: Text( + "opposite\nchild\nlightsource", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + Neumorphic( + padding: EdgeInsets.all(20), + style: widget.firstStyle.copyWith( + boxShape: NeumorphicBoxShape.circle(), + ), + child: Neumorphic( + style: widget.secondStyle.copyWith( + boxShape: NeumorphicBoxShape.circle(), + oppositeShadowLightSource: true, + ), + child: SizedBox( + height: 100, + width: 100, + ), + ), + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/border/tips_emboss_inside_emboss.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/border/tips_emboss_inside_emboss.dart new file mode 100644 index 00000000..1378a425 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/border/tips_emboss_inside_emboss.dart @@ -0,0 +1,219 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class TipsRecursiveeEmbossPage extends StatefulWidget { + TipsRecursiveeEmbossPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.6, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Emboss Recursive", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _EmbossmbossWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _EmbossmbossWidget extends StatefulWidget { + @override + createState() => _EmbossmbossWidgetState(); +} + +class _EmbossmbossWidgetState extends State<_EmbossmbossWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" + Widget _generateEmbosss({int number, Widget child, bool reverseEachPair = false}) { + Widget element = child; + for (int i = 0; i < number; ++i) { + element = Neumorphic( + padding: EdgeInsets.all(20), + boxShape: NeumorphicBoxShape.circle(), + style: NeumorphicStyle( + depth: -(NeumorphicTheme.depth(context).abs()), //force negative + oppositeShadowLightSource: (reverseEachPair && i % 2 == 0), + ), + child: element, + ); + } + return element; + } +"""); + } + + Widget _generateEmbosss( + {int number, Widget child, bool reverseEachPair = false}) { + Widget element = child; + for (int i = 0; i < number; ++i) { + element = Neumorphic( + padding: EdgeInsets.all(20), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + depth: -(NeumorphicTheme.depth(context).abs()), //force negative + oppositeShadowLightSource: (reverseEachPair && i % 2 == 0), + ), + child: element, + ); + } + return element; + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + Column( + children: [ + Row( + children: [ + Container( + width: 100, + margin: EdgeInsets.only(left: 12, right: 12), + child: Text( + "Recursive Emboss", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + _generateEmbosss( + number: 5, + child: SizedBox( + height: 10, + width: 10, + ), + ), + ], + ), + SizedBox(height: 20), + Row( + children: [ + Container( + width: 100, + margin: EdgeInsets.only(left: 12, right: 12), + child: Text( + "Each pair number\nLightsource is reversed", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + _generateEmbosss( + number: 5, + reverseEachPair: true, + child: SizedBox( + height: 10, + width: 10, + ), + ), + ], + ), + ], + ), + SizedBox(height: 20), + Column( + children: [ + Row( + children: [ + Container( + width: 100, + margin: EdgeInsets.only(left: 12, right: 12), + child: Text( + "Recursive Emboss", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + _generateEmbosss( + number: 4, + child: SizedBox( + height: 10, + width: 10, + ), + ), + ], + ), + SizedBox(height: 20), + Row( + children: [ + Container( + width: 100, + margin: EdgeInsets.only(left: 12, right: 12), + child: Text( + "Each pair number\nLightsource is reversed", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + _generateEmbosss( + number: 4, + reverseEachPair: true, + child: SizedBox( + height: 10, + width: 10, + ), + ), + ], + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/tips_home.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/tips_home.dart new file mode 100644 index 00000000..3c40c786 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/tips/tips_home.dart @@ -0,0 +1,67 @@ +import '../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../lib/flutter_neumorphic.dart'; + +import 'border/tips_border.dart'; +import 'border/tips_emboss_inside_emboss.dart'; + +class TipsHome extends StatelessWidget { + Widget _buildButton({String text, VoidCallback onClick}) { + return NeumorphicButton( + margin: EdgeInsets.only(bottom: 12), + padding: EdgeInsets.symmetric( + vertical: 18, + horizontal: 24, + ), + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(12), + ), + ), + child: Center(child: Text(text)), + onPressed: onClick, + ); + } + + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData(depth: 8), + child: Scaffold( + backgroundColor: NeumorphicColors.background, + body: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(18.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + TopBar(title: "Tips"), + _buildButton( + text: "Border", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return TipsBorderPage(); + })); + }), + _buildButton( + text: "Recursive Emboss", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return TipsRecursiveeEmbossPage(); + })); + }), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/appbar/widget_app_bar.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/appbar/widget_app_bar.dart new file mode 100644 index 00000000..5435bc73 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/appbar/widget_app_bar.dart @@ -0,0 +1,226 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class AppBarWidgetPage extends StatelessWidget { + AppBarWidgetPage({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + _FirstThemeWidgetPage(), + _SecondThemeWidgetPage(), + _ThirdThemeWidgetPage(), + _CustomIcon(), + ], + ); + } +} + +class _FirstThemeWidgetPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + appBarTheme: NeumorphicAppBarThemeData( + buttonStyle: NeumorphicStyle(boxShape: NeumorphicBoxShape.circle()), + textStyle: TextStyle(color: Colors.black54), + iconTheme: IconThemeData(color: Colors.black54, size: 30), + ), + depth: 4, + intensity: 0.9, + ), + child: AppBarPageUsingTheme(), + ); + } +} + +class _SecondThemeWidgetPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + appBarTheme: NeumorphicAppBarThemeData( + buttonStyle: NeumorphicStyle( + boxShape: NeumorphicBoxShape.beveled(BorderRadius.circular(12))), + textStyle: TextStyle(color: Colors.black54), + iconTheme: IconThemeData(color: Colors.black54, size: 30), + ), + depth: 4, + intensity: 0.9, + ), + child: AppBarPageUsingTheme(), + ); + } +} + +class _ThirdThemeWidgetPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + appBarTheme: NeumorphicAppBarThemeData( + buttonStyle: NeumorphicStyle( + color: Colors.black54, + boxShape: + NeumorphicBoxShape.roundRect(BorderRadius.circular(12))), + textStyle: TextStyle(color: Colors.black54, fontSize: 20), + iconTheme: IconThemeData(color: Colors.white, size: 20), + ), + depth: 4, + intensity: 0.9, + ), + child: SizedAppBarPageUsingTheme(), + ); + } +} + +class AppBarPageUsingTheme extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SizedBox( + height: 100, + child: Scaffold( + appBar: NeumorphicAppBar( + title: Text("App bar"), + actions: [ + NeumorphicButton( + child: Icon(Icons.add), + onPressed: () {}, + ), + ], + ), + body: Container()), + ); + } +} + +class SizedAppBarPageUsingTheme extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SizedBox( + height: 100, + child: Scaffold( + appBar: PreferredSize( + preferredSize: Size.fromHeight(60.0), + child: NeumorphicAppBar( + title: Text("App bar custom size"), + actions: [ + NeumorphicButton( + child: Icon(Icons.add), + onPressed: () {}, + ), + ], + ), + ), + body: Container()), + ); + } +} + +class FirstThemeContent extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SizedBox( + height: 100, + child: Scaffold( + appBar: NeumorphicAppBar( + title: Text("App bar"), + actions: [ + NeumorphicButton( + child: Icon(Icons.add), + onPressed: () {}, + ), + ], + ), + body: Container()), + ); + } +} + +class _MyDrawer extends StatelessWidget { + final bool isLead; + + const _MyDrawer({Key key, this.isLead = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Drawer( + child: Container( + color: NeumorphicTheme.baseColor(context), + child: Column( + children: [ + ConstrainedBox( + constraints: BoxConstraints.tightFor( + height: NeumorphicAppBar.toolbarHeight), + child: NeumorphicAppBar( + title: Text('Menu'), + leading: + isLead ? NeumorphicBackButton() : NeumorphicCloseButton(), + actions: [ + NeumorphicButton( + child: Icon(Icons.style), + onPressed: () {}, + ), + isLead + ? NeumorphicCloseButton() + : NeumorphicBackButton(forward: true), + ], + ), + ), + Spacer(), + ], + ), + ), + ); + } +} + +class _CustomIcon extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SizedBox( + height: 300, + child: NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + appBarTheme: NeumorphicAppBarThemeData( + buttonStyle: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.concave, + depth: 10, + intensity: 1, + ), + textStyle: TextStyle(color: Colors.black, fontSize: 20), + iconTheme: IconThemeData(color: Colors.green, size: 25), + icons: NeumorphicAppBarIcons( + menuIcon: Icon(Icons.list, color: Colors.pink), + closeIcon: Icon(Icons.delete), + backIcon: Icon(Icons.reply))), + depth: 2, + intensity: 0.5, + ), + child: Scaffold( + appBar: NeumorphicAppBar( + title: Text("Custom icons + drawer"), + ), + endDrawer: _MyDrawer(isLead: false), + body: Container(), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/background/widget_background.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/background/widget_background.dart new file mode 100644 index 00000000..c42989ce --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/background/widget_background.dart @@ -0,0 +1,118 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class BackgroundWidgetPage extends StatefulWidget { + BackgroundWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Background", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +//takes the themee baseColor as background +Expanded( + child: NeumorphicBackground( + child: ... + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default\n(inside black)", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: Container( + padding: EdgeInsets.all(8), + color: Colors.black, + child: NeumorphicBackground( + child: const SizedBox( + width: 100, + height: 100, + ), + ), + ), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/button/button.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/button/button.dart new file mode 100644 index 00000000..d1b15e9b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/button/button.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class ButtonSample extends StatefulWidget { + @override + createState() => _ButtonSampleState(); +} + +class _ButtonSampleState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + baseColor: Color(0xFFFFFFFF), + intensity: 0.5, + lightSource: LightSource.topLeft, + depth: 10, + ), + darkTheme: NeumorphicThemeData( + baseColor: Color(0xFF000000), + intensity: 0.5, + lightSource: LightSource.topLeft, + depth: 10, + ), + child: _Page()); + } +} + +class _Page extends StatefulWidget { + @override + createState() => __PageState(); +} + +class __PageState extends State<_Page> { + bool _useDark = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text("back"), + ), + RaisedButton( + onPressed: () { + setState(() { + _useDark = !_useDark; + NeumorphicTheme.of(context).themeMode = + _useDark ? ThemeMode.dark : ThemeMode.light; + }); + }, + child: Text("toggle theme"), + ), + SizedBox(height: 34), + _buildTopBar(context), + ], + ), + ), + ); + } + + Widget _buildTopBar(BuildContext context) { + return Center( + child: NeumorphicButton( + onPressed: () { + print("click"); + }, + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Icon( + Icons.favorite_border, + color: _iconsColor(), + ), + ), + ), + ); + } + + Color _iconsColor() { + final theme = NeumorphicTheme.of(context); + if (theme.isUsingDark) { + return theme.current.accentColor; + } else { + return null; + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/button/widget_button.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/button/widget_button.dart new file mode 100644 index 00000000..3a3f90d7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/button/widget_button.dart @@ -0,0 +1,530 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class ButtonWidgetPage extends StatefulWidget { + ButtonWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Button", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _CircleWidget(), + _ColorizableWidget(), + _MinDistanceWidget(), + _EnabledDisabledWidget(), + _FlatConcaveConvexWidget(), + _DurationWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicButton( + onPressed: () { + + }, + child: Text("Click me"), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicButton( + onPressed: () { + setState(() {}); + }, + child: Text("Click me"), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _CircleWidget extends StatefulWidget { + @override + createState() => _CircleWidgetState(); +} + +class _CircleWidgetState extends State<_CircleWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicButton( + boxShape: NeumorphicBoxShape.circle(), + onPressed: () { + + }, + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Circle", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicButton( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + onPressed: () { + setState(() {}); + }, + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _MinDistanceWidget extends StatefulWidget { + @override + createState() => _MinDistanceWidgetState(); +} + +class _MinDistanceWidgetState extends State<_MinDistanceWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicButton( + boxShape: NeumorphicBoxShape.circle(), + minDistance: -5.0, + onPressed: () { + + }, + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "MinDistance -5", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicButton( + minDistance: -5.0, + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + onPressed: () { + setState(() {}); + }, + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ColorizableWidget extends StatefulWidget { + @override + createState() => _ColorizableWidgetState(); +} + +class _ColorizableWidgetState extends State<_ColorizableWidget> { + Color currentColor = Colors.green; + + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicButton( + onPressed: (){ + + }, + style: NeumorphicStyle( + color: Colors.green + ), + child: Text("Click me"), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Color", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + ColorSelector( + color: currentColor, + onColorChanged: (color) { + setState(() { + currentColor = color; + }); + }, + ), + SizedBox(width: 12), + NeumorphicButton( + onPressed: () {}, + style: NeumorphicStyle(color: currentColor), + child: Text("Click me"), + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _EnabledDisabledWidget extends StatefulWidget { + @override + createState() => _EnabledDisabledWidgetState(); +} + +class _EnabledDisabledWidgetState extends State<_EnabledDisabledWidget> { + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Enabled :", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicButton( + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 18), + child: Text("First"), + onPressed: () { + setState(() {}); + }, + ), + SizedBox(width: 24), + Text( + "Disabled :", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicButton( + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 18), + child: Text("Second"), + ), + ], + ), + ); + } + + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicButton( + isEnabled: false, + child: Text("Second"), + onPressed: () { + + }, +), +"""); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _DurationWidget extends StatefulWidget { + @override + createState() => _DurationWidgetState(); +} + +class _DurationWidgetState extends State<_DurationWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicButton( + onPressed: (){ + + }, + child: Text("Press me all night long"), + duration: Duration(seconds: 1), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Text( + "Duration", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicButton( + onPressed: () {}, + child: Text("Press me all night long"), + duration: Duration(seconds: 1), + ), + SizedBox(width: 12), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _FlatConcaveConvexWidget extends StatefulWidget { + @override + createState() => _FlatConcaveConvexWidgetState(); +} + +class _FlatConcaveConvexWidgetState extends State<_FlatConcaveConvexWidget> { + bool isChecked = false; + + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicButton( + style: NeumorphicStyle( + shape: NeumorphicShape.flat + //or convex, concave + ), + onPressed: () { + + }, + child: ... +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Flat", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicButton( + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + onPressed: () { + setState(() {}); + }, + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Concave", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicButton( + style: NeumorphicStyle( + shape: NeumorphicShape.concave, + boxShape: NeumorphicBoxShape.circle(), + ), + onPressed: () { + setState(() {}); + }, + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Convex", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicButton( + style: NeumorphicStyle( + shape: NeumorphicShape.convex, + boxShape: NeumorphicBoxShape.circle()), + onPressed: () { + setState(() {}); + }, + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/checkbox/widget_checkbox.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/checkbox/widget_checkbox.dart new file mode 100644 index 00000000..788c3149 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/checkbox/widget_checkbox.dart @@ -0,0 +1,313 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class CheckboxWidgetPage extends StatefulWidget { + CheckboxWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Checkbox", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _ColorWidget(), + _EnabledDisabledWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + bool check1 = false; + bool check2 = false; + bool check3 = false; + + Widget _buildCode(BuildContext context) { + return Code(""" + +bool isChecked = false; + +NeumorphicCheckbox( + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicCheckbox( + value: check1, + onChanged: (value) { + setState(() { + check1 = value; + }); + }, + ), + SizedBox(width: 12), + NeumorphicCheckbox( + value: check2, + onChanged: (value) { + setState(() { + check2 = value; + }); + }, + ), + SizedBox(width: 12), + NeumorphicCheckbox( + value: check3, + onChanged: (value) { + setState(() { + check3 = value; + }); + }, + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ColorWidget extends StatefulWidget { + @override + createState() => _ColorWidgetState(); +} + +class _ColorWidgetState extends State<_ColorWidget> { + Color customColor = Colors.green; + + bool checkColor1 = false; + bool checkColor2 = false; + bool checkColor3 = false; + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Colorizable", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + ColorSelector( + color: customColor, + onColorChanged: (color) { + setState(() { + customColor = color; + }); + }, + ), + SizedBox(width: 12), + NeumorphicCheckbox( + style: NeumorphicCheckboxStyle(selectedColor: customColor), + value: checkColor1, + onChanged: (value) { + setState(() { + checkColor1 = value; + }); + }, + ), + SizedBox(width: 12), + NeumorphicCheckbox( + style: NeumorphicCheckboxStyle(selectedColor: customColor), + value: checkColor2, + onChanged: (value) { + setState(() { + checkColor2 = value; + }); + }, + ), + SizedBox(width: 12), + NeumorphicCheckbox( + value: checkColor3, + style: NeumorphicCheckboxStyle(selectedColor: customColor), + onChanged: (value) { + setState(() { + checkColor3 = value; + }); + }, + ), + ], + ), + ); + } + + Widget _buildCode(BuildContext context) { + return Code(""" + +bool isChecked = false; + +NeumorphicCheckbox( + value: isChecked, + style: NeumorphicCheckboxStyle( + selectedColor: Colors.green, + ), + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, +), +"""); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _EnabledDisabledWidget extends StatefulWidget { + @override + createState() => _EnabledDisabledWidgetState(); +} + +class _EnabledDisabledWidgetState extends State<_EnabledDisabledWidget> { + bool check1 = false; + bool check2 = false; + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Enabled", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicCheckbox( + value: check1, + onChanged: (value) { + setState(() { + check1 = value; + }); + }, + ), + SizedBox(width: 24), + Text( + "Disabled", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicCheckbox( + isEnabled: false, + value: check2, + onChanged: (value) { + setState(() { + check2 = value; + }); + }, + ), + ], + ), + ); + } + + Widget _buildCode(BuildContext context) { + return Code(""" + +bool isChecked = false; + +NeumorphicCheckbox( + isEnabled: false, + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, +), +"""); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/container/widget_container.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/container/widget_container.dart new file mode 100644 index 00000000..b1980634 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/container/widget_container.dart @@ -0,0 +1,623 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class ContainerWidgetPage extends StatefulWidget { + ContainerWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 8, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Container", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _CircleWidget(), + _RoundRectWidget(), + _ColorizableWidget(), + _FlatConcaveConvexWidget(), + _EmbossWidget(), + _DrawAboveWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Neumorphic( + child: SizedBox( + height: 100, + width: 100, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Neumorphic( + child: SizedBox( + height: 100, + width: 100, + ), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _CircleWidget extends StatefulWidget { + @override + createState() => _CircleWidgetState(); +} + +class _CircleWidgetState extends State<_CircleWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Neumorphic( + boxShape: NeumorphicBoxShape.circle(), + padding: EdgeInsets.all(18.0), + child: Icon(Icons.map), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Circle", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + padding: EdgeInsets.all(18.0), + child: Icon(Icons.map), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _RoundRectWidget extends StatefulWidget { + @override + createState() => _RoundRectWidgetState(); +} + +class _RoundRectWidgetState extends State<_RoundRectWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(8)), + ), + padding: EdgeInsets.all(18.0), + child: Icon(Icons.map), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "RoundRect", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect(BorderRadius.circular(8)), + ), + padding: EdgeInsets.all(18.0), + child: Icon(Icons.map), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ColorizableWidget extends StatefulWidget { + @override + createState() => _ColorizableWidgetState(); +} + +class _ColorizableWidgetState extends State<_ColorizableWidget> { + Color currentColor = Colors.white; + + Widget _buildCode(BuildContext context) { + return Code(""" +Neumorphic( + style: NeumorphicStyle( + color: Colors.white, + boxShape: NeumorphicBoxShape.circle() + ), + child: SizedBox( + height: 100, + width: 100, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Color", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + ColorSelector( + color: currentColor, + onColorChanged: (color) { + setState(() { + currentColor = color; + }); + }, + ), + SizedBox(width: 12), + Neumorphic( + style: NeumorphicStyle( + color: currentColor, boxShape: NeumorphicBoxShape.circle()), + child: SizedBox( + height: 100, + width: 100, + ), + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _FlatConcaveConvexWidget extends StatefulWidget { + @override + createState() => _FlatConcaveConvexWidgetState(); +} + +class _FlatConcaveConvexWidgetState extends State<_FlatConcaveConvexWidget> { + bool isChecked = false; + + Widget _buildCode(BuildContext context) { + return Code(""" +Neumorphic( + style: NeumorphicStyle( + shape: NeumorphicShape.flat + //or convex, concave + ), + + child: ... +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Flat", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + Neumorphic( + style: NeumorphicStyle( + shape: NeumorphicShape.flat, + boxShape: NeumorphicBoxShape.circle(), + ), + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Concave", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + Neumorphic( + style: NeumorphicStyle( + shape: NeumorphicShape.concave, + boxShape: NeumorphicBoxShape.circle(), + ), + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Convex", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicButton( + style: NeumorphicStyle( + shape: NeumorphicShape.convex, + boxShape: NeumorphicBoxShape.circle()), + padding: EdgeInsets.all(18.0), + child: Icon(Icons.play_arrow), + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _EmbossWidget extends StatefulWidget { + @override + createState() => _EmbossWidgetState(); +} + +class _EmbossWidgetState extends State<_EmbossWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Neumorphic( + child: Icon(Icons.play_arrow), + style: NeumorphicStyle( + depth: -10.0, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Text( + "Emboss", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Neumorphic( + padding: EdgeInsets.all(18), + child: Icon(Icons.play_arrow), + style: NeumorphicStyle( + depth: -10.0, + ), + ), + SizedBox(width: 12), + Neumorphic( + padding: EdgeInsets.all(18), + child: Icon(Icons.play_arrow), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + depth: -10.0, + ), + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _DrawAboveWidget extends StatefulWidget { + @override + createState() => _DrawAboveWidgetState(); +} + +class _DrawAboveWidgetState extends State<_DrawAboveWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Neumorphic( + child: ..., + drawSurfaceAboveChild: true, + style: NeumorphicStyle( + surfaceIntensity: 1, + shape: NeumorphicShape.concave, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Text( + "DrawAbove", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(height: 12), + Row(children: [ + Container( + margin: EdgeInsets.all(8), + width: 100, + child: Center(child: Text("false")), + ), + SizedBox(width: 12), + Container( + margin: EdgeInsets.all(8), + width: 100, + child: Center(child: Text("true\n(concave)")), + ), + SizedBox(width: 12), + Container( + margin: EdgeInsets.all(8), + width: 100, + child: Center(child: Text("true\n(convex)")), + ), + ]), + Row( + children: [ + Neumorphic( + drawSurfaceAboveChild: false, + margin: EdgeInsets.all(8), + child: Image.asset( + "assets/images/weeknd.jpg", + height: 100, + width: 100, + fit: BoxFit.cover, + ), + style: NeumorphicStyle( + surfaceIntensity: 1, + shape: NeumorphicShape.concave, + ), + ), + SizedBox(width: 12), + Neumorphic( + child: Image.asset( + "assets/images/weeknd.jpg", + height: 100, + width: 100, + fit: BoxFit.cover, + ), + drawSurfaceAboveChild: true, + margin: EdgeInsets.all(8), + style: NeumorphicStyle( + surfaceIntensity: 1, + shape: NeumorphicShape.concave, + ), + ), + SizedBox(width: 12), + Neumorphic( + child: Image.asset( + "assets/images/weeknd.jpg", + height: 100, + width: 100, + fit: BoxFit.cover, + ), + drawSurfaceAboveChild: true, + margin: EdgeInsets.all(8), + style: NeumorphicStyle( + intensity: 1, + shape: NeumorphicShape.convex, + ), + ), + ], + ), + Row( + children: [ + Neumorphic( + drawSurfaceAboveChild: false, + child: Image.asset( + "assets/images/weeknd.jpg", + height: 100, + width: 100, + fit: BoxFit.cover, + ), + margin: EdgeInsets.all(8), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.circle(), + surfaceIntensity: 1, + shape: NeumorphicShape.concave, + ), + ), + SizedBox(width: 12), + Neumorphic( + child: Image.asset( + "assets/images/weeknd.jpg", + height: 100, + width: 100, + fit: BoxFit.cover, + ), + drawSurfaceAboveChild: true, + margin: EdgeInsets.all(8), + style: NeumorphicStyle( + surfaceIntensity: 1, + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.concave, + ), + ), + SizedBox(width: 12), + Neumorphic( + child: Image.asset( + "assets/images/weeknd.jpg", + height: 100, + width: 100, + fit: BoxFit.cover, + ), + drawSurfaceAboveChild: true, + margin: EdgeInsets.all(8), + style: NeumorphicStyle( + surfaceIntensity: 1, + boxShape: NeumorphicBoxShape.circle(), + shape: NeumorphicShape.convex, + ), + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/icon/widget_icon.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/icon/widget_icon.dart new file mode 100644 index 00000000..d5d0a9d4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/icon/widget_icon.dart @@ -0,0 +1,1055 @@ +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/top_bar.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class IconWidgetPage extends StatefulWidget { + IconWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 1.0, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Icons", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: GridView.builder( + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4), + itemCount: icons.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.all(18.0), + child: NeumorphicIcon( + icons[index], + size: 80, + style: NeumorphicStyle( + //shape: NeumorphicShape.convex, + //surfaceIntensity: 1.0 + ), + ), + ); + }, + ), + ), + ); + } + + final icons = [ + Icons.threesixty, + Icons.threed_rotation, + Icons.four_k, + Icons.ac_unit, + Icons.access_alarm, + Icons.access_alarms, + Icons.access_time, + Icons.accessibility, + Icons.accessibility_new, + Icons.accessible, + Icons.accessible_forward, + Icons.account_balance, + Icons.account_balance_wallet, + Icons.account_box, + Icons.account_circle, + Icons.adb, + Icons.add, + Icons.add_a_photo, + Icons.add_alarm, + Icons.add_alert, + Icons.add_box, + Icons.add_call, + Icons.add_circle, + Icons.add_circle_outline, + Icons.add_comment, + Icons.add_location, + Icons.add_photo_alternate, + Icons.add_shopping_cart, + Icons.add_to_home_screen, + Icons.add_to_photos, + Icons.add_to_queue, + Icons.adjust, + Icons.airline_seat_flat, + Icons.airline_seat_flat_angled, + Icons.airline_seat_individual_suite, + Icons.airline_seat_legroom_extra, + Icons.airline_seat_legroom_normal, + Icons.airline_seat_legroom_reduced, + Icons.airline_seat_recline_extra, + Icons.airline_seat_recline_normal, + Icons.airplanemode_active, + Icons.airplanemode_inactive, + Icons.airplay, + Icons.airport_shuttle, + Icons.alarm, + Icons.alarm_add, + Icons.alarm_off, + Icons.alarm_on, + Icons.album, + Icons.all_inclusive, + Icons.all_out, + Icons.alternate_email, + Icons.android, + Icons.announcement, + Icons.apps, + Icons.archive, + Icons.arrow_back, + Icons.arrow_back_ios, + Icons.arrow_downward, + Icons.arrow_drop_down, + Icons.arrow_drop_down_circle, + Icons.arrow_drop_up, + Icons.arrow_forward, + Icons.arrow_forward_ios, + Icons.arrow_left, + Icons.arrow_right, + Icons.arrow_upward, + Icons.art_track, + Icons.aspect_ratio, + Icons.assessment, + Icons.assignment, + Icons.assignment_ind, + Icons.assignment_late, + Icons.assignment_return, + Icons.assignment_returned, + Icons.assignment_turned_in, + Icons.assistant, + Icons.assistant_photo, + Icons.atm, + Icons.attach_file, + Icons.attach_money, + Icons.attachment, + Icons.audiotrack, + Icons.autorenew, + Icons.av_timer, + Icons.backspace, + Icons.backup, + Icons.battery_alert, + Icons.battery_charging_full, + Icons.battery_full, + Icons.battery_std, + Icons.battery_unknown, + Icons.beach_access, + Icons.beenhere, + Icons.block, + Icons.bluetooth, + Icons.bluetooth_audio, + Icons.bluetooth_connected, + Icons.bluetooth_disabled, + Icons.bluetooth_searching, + Icons.blur_circular, + Icons.blur_linear, + Icons.blur_off, + Icons.blur_on, + Icons.book, + Icons.bookmark, + Icons.bookmark_border, + Icons.border_all, + Icons.border_bottom, + Icons.border_clear, + Icons.border_color, + Icons.border_horizontal, + Icons.border_inner, + Icons.border_left, + Icons.border_outer, + Icons.border_right, + Icons.border_style, + Icons.border_top, + Icons.border_vertical, + Icons.branding_watermark, + Icons.brightness_1, + Icons.brightness_2, + Icons.brightness_3, + Icons.brightness_4, + Icons.brightness_5, + Icons.brightness_6, + Icons.brightness_7, + Icons.brightness_auto, + Icons.brightness_high, + Icons.brightness_low, + Icons.brightness_medium, + Icons.broken_image, + Icons.brush, + Icons.bubble_chart, + Icons.bug_report, + Icons.build, + Icons.burst_mode, + Icons.business, + Icons.business_center, + Icons.cached, + Icons.cake, + Icons.calendar_today, + Icons.calendar_view_day, + Icons.call, + Icons.call_end, + Icons.call_made, + Icons.call_merge, + Icons.call_missed, + Icons.call_missed_outgoing, + Icons.call_received, + Icons.call_split, + Icons.call_to_action, + Icons.camera, + Icons.camera_alt, + Icons.camera_enhance, + Icons.camera_front, + Icons.camera_rear, + Icons.camera_roll, + Icons.cancel, + Icons.card_giftcard, + Icons.card_membership, + Icons.card_travel, + Icons.casino, + Icons.cast, + Icons.cast_connected, + Icons.category, + Icons.center_focus_strong, + Icons.center_focus_weak, + Icons.change_history, + Icons.chat, + Icons.chat_bubble, + Icons.chat_bubble_outline, + Icons.check, + Icons.check_box, + Icons.check_box_outline_blank, + Icons.check_circle, + Icons.check_circle_outline, + Icons.chevron_left, + Icons.chevron_right, + Icons.child_care, + Icons.child_friendly, + Icons.chrome_reader_mode, + Icons.class_, + Icons.clear, + Icons.clear_all, + Icons.close, + Icons.closed_caption, + Icons.cloud, + Icons.cloud_circle, + Icons.cloud_done, + Icons.cloud_download, + Icons.cloud_off, + Icons.cloud_queue, + Icons.cloud_upload, + Icons.code, + Icons.collections, + Icons.collections_bookmark, + Icons.color_lens, + Icons.colorize, + Icons.comment, + Icons.compare, + Icons.compare_arrows, + Icons.computer, + Icons.confirmation_number, + Icons.contact_mail, + Icons.contact_phone, + Icons.contacts, + Icons.content_copy, + Icons.content_cut, + Icons.content_paste, + Icons.control_point, + Icons.control_point_duplicate, + Icons.copyright, + Icons.create, + Icons.create_new_folder, + Icons.credit_card, + Icons.crop, + Icons.crop_16_9, + Icons.crop_3_2, + Icons.crop_5_4, + Icons.crop_7_5, + Icons.crop_din, + Icons.crop_free, + Icons.crop_landscape, + Icons.crop_original, + Icons.crop_portrait, + Icons.crop_rotate, + Icons.crop_square, + Icons.dashboard, + Icons.data_usage, + Icons.date_range, + Icons.dehaze, + Icons.delete, + Icons.delete_forever, + Icons.delete_outline, + Icons.delete_sweep, + Icons.departure_board, + Icons.description, + Icons.desktop_mac, + Icons.desktop_windows, + Icons.details, + Icons.developer_board, + Icons.developer_mode, + Icons.device_hub, + Icons.device_unknown, + Icons.devices, + Icons.devices_other, + Icons.dialer_sip, + Icons.dialpad, + Icons.directions, + Icons.directions_bike, + Icons.directions_boat, + Icons.directions_bus, + Icons.directions_car, + Icons.directions_railway, + Icons.directions_run, + Icons.directions_subway, + Icons.directions_transit, + Icons.directions_walk, + Icons.disc_full, + Icons.dns, + Icons.do_not_disturb, + Icons.do_not_disturb_alt, + Icons.do_not_disturb_off, + Icons.do_not_disturb_on, + Icons.dock, + Icons.domain, + Icons.done, + Icons.done_all, + Icons.done_outline, + Icons.donut_large, + Icons.donut_small, + Icons.drafts, + Icons.drag_handle, + Icons.drive_eta, + Icons.dvr, + Icons.edit, + Icons.edit_attributes, + Icons.edit_location, + Icons.eject, + Icons.email, + Icons.enhanced_encryption, + Icons.equalizer, + Icons.error, + Icons.error_outline, + Icons.euro_symbol, + Icons.ev_station, + Icons.event, + Icons.event_available, + Icons.event_busy, + Icons.event_note, + Icons.event_seat, + Icons.exit_to_app, + Icons.expand_less, + Icons.expand_more, + Icons.explicit, + Icons.explore, + Icons.exposure, + Icons.exposure_neg_1, + Icons.exposure_neg_2, + Icons.exposure_plus_1, + Icons.exposure_plus_2, + Icons.exposure_zero, + Icons.extension, + Icons.face, + Icons.fast_forward, + Icons.fast_rewind, + Icons.fastfood, + Icons.favorite, + Icons.favorite_border, + Icons.featured_play_list, + Icons.featured_video, + Icons.feedback, + Icons.fiber_dvr, + Icons.fiber_manual_record, + Icons.fiber_new, + Icons.fiber_pin, + Icons.fiber_smart_record, + Icons.file_download, + Icons.file_upload, + Icons.filter, + Icons.filter_1, + Icons.filter_2, + Icons.filter_3, + Icons.filter_4, + Icons.filter_5, + Icons.filter_6, + Icons.filter_7, + Icons.filter_8, + Icons.filter_9, + Icons.filter_9_plus, + Icons.filter_b_and_w, + Icons.filter_center_focus, + Icons.filter_drama, + Icons.filter_frames, + Icons.filter_hdr, + Icons.filter_list, + Icons.filter_none, + Icons.filter_tilt_shift, + Icons.filter_vintage, + Icons.find_in_page, + Icons.find_replace, + Icons.fingerprint, + Icons.first_page, + Icons.fitness_center, + Icons.flag, + Icons.flare, + Icons.flash_auto, + Icons.flash_off, + Icons.flash_on, + Icons.flight, + Icons.flight_land, + Icons.flight_takeoff, + Icons.flip, + Icons.flip_to_back, + Icons.flip_to_front, + Icons.folder, + Icons.folder_open, + Icons.folder_shared, + Icons.folder_special, + Icons.font_download, + Icons.format_align_center, + Icons.format_align_justify, + Icons.format_align_left, + Icons.format_align_right, + Icons.format_bold, + Icons.format_clear, + Icons.format_color_fill, + Icons.format_color_reset, + Icons.format_color_text, + Icons.format_indent_decrease, + Icons.format_indent_increase, + Icons.format_italic, + Icons.format_line_spacing, + Icons.format_list_bulleted, + Icons.format_list_numbered, + Icons.format_list_numbered_rtl, + Icons.format_paint, + Icons.format_quote, + Icons.format_shapes, + Icons.format_size, + Icons.format_strikethrough, + Icons.format_textdirection_l_to_r, + Icons.format_textdirection_r_to_l, + Icons.format_underlined, + Icons.forum, + Icons.forward, + Icons.forward_10, + Icons.forward_30, + Icons.forward_5, + Icons.free_breakfast, + Icons.fullscreen, + Icons.fullscreen_exit, + Icons.functions, + Icons.g_translate, + Icons.gamepad, + Icons.games, + Icons.gavel, + Icons.gesture, + Icons.get_app, + Icons.gif, + Icons.golf_course, + Icons.gps_fixed, + Icons.gps_not_fixed, + Icons.gps_off, + Icons.grade, + Icons.gradient, + Icons.grain, + Icons.graphic_eq, + Icons.grid_off, + Icons.grid_on, + Icons.group, + Icons.group_add, + Icons.group_work, + Icons.hd, + Icons.hdr_off, + Icons.hdr_on, + Icons.hdr_strong, + Icons.hdr_weak, + Icons.headset, + Icons.headset_mic, + Icons.headset_off, + Icons.healing, + Icons.hearing, + Icons.help, + Icons.help_outline, + Icons.high_quality, + Icons.highlight, + Icons.highlight_off, + Icons.history, + Icons.home, + Icons.hot_tub, + Icons.hotel, + Icons.hourglass_empty, + Icons.hourglass_full, + Icons.http, + Icons.https, + Icons.image, + Icons.image_aspect_ratio, + Icons.import_contacts, + Icons.import_export, + Icons.important_devices, + Icons.inbox, + Icons.indeterminate_check_box, + Icons.info, + Icons.info_outline, + Icons.input, + Icons.insert_chart, + Icons.insert_comment, + Icons.insert_drive_file, + Icons.insert_emoticon, + Icons.insert_invitation, + Icons.insert_link, + Icons.insert_photo, + Icons.invert_colors, + Icons.invert_colors_off, + Icons.iso, + Icons.keyboard, + Icons.keyboard_arrow_down, + Icons.keyboard_arrow_left, + Icons.keyboard_arrow_right, + Icons.keyboard_arrow_up, + Icons.keyboard_backspace, + Icons.keyboard_capslock, + Icons.keyboard_hide, + Icons.keyboard_return, + Icons.keyboard_tab, + Icons.keyboard_voice, + Icons.kitchen, + Icons.label, + Icons.label_important, + Icons.label_outline, + Icons.landscape, + Icons.language, + Icons.laptop, + Icons.laptop_chromebook, + Icons.laptop_mac, + Icons.laptop_windows, + Icons.last_page, + Icons.launch, + Icons.layers, + Icons.layers_clear, + Icons.leak_add, + Icons.leak_remove, + Icons.lens, + Icons.library_add, + Icons.library_books, + Icons.library_music, + Icons.lightbulb_outline, + Icons.line_style, + Icons.line_weight, + Icons.linear_scale, + Icons.link, + Icons.link_off, + Icons.linked_camera, + Icons.list, + Icons.live_help, + Icons.live_tv, + Icons.local_activity, + Icons.local_airport, + Icons.local_atm, + Icons.local_bar, + Icons.local_cafe, + Icons.local_car_wash, + Icons.local_convenience_store, + Icons.local_dining, + Icons.local_drink, + Icons.local_florist, + Icons.local_gas_station, + Icons.local_grocery_store, + Icons.local_hospital, + Icons.local_hotel, + Icons.local_laundry_service, + Icons.local_library, + Icons.local_mall, + Icons.local_movies, + Icons.local_offer, + Icons.local_parking, + Icons.local_pharmacy, + Icons.local_phone, + Icons.local_pizza, + Icons.local_play, + Icons.local_post_office, + Icons.local_printshop, + Icons.local_see, + Icons.local_shipping, + Icons.local_taxi, + Icons.location_city, + Icons.location_disabled, + Icons.location_off, + Icons.location_on, + Icons.location_searching, + Icons.lock, + Icons.lock_open, + Icons.lock_outline, + Icons.looks, + Icons.looks_3, + Icons.looks_4, + Icons.looks_5, + Icons.looks_6, + Icons.looks_one, + Icons.looks_two, + Icons.loop, + Icons.loupe, + Icons.low_priority, + Icons.loyalty, + Icons.mail, + Icons.mail_outline, + Icons.map, + Icons.markunread, + Icons.markunread_mailbox, + Icons.maximize, + Icons.memory, + Icons.menu, + Icons.merge_type, + Icons.message, + Icons.mic, + Icons.mic_none, + Icons.mic_off, + Icons.minimize, + Icons.missed_video_call, + Icons.mms, + Icons.mobile_screen_share, + Icons.mode_comment, + Icons.mode_edit, + Icons.monetization_on, + Icons.money_off, + Icons.monochrome_photos, + Icons.mood, + Icons.mood_bad, + Icons.more, + Icons.more_horiz, + Icons.more_vert, + Icons.motorcycle, + Icons.mouse, + Icons.move_to_inbox, + Icons.movie, + Icons.movie_creation, + Icons.movie_filter, + Icons.multiline_chart, + Icons.music_note, + Icons.music_video, + Icons.my_location, + Icons.nature, + Icons.nature_people, + Icons.navigate_before, + Icons.navigate_next, + Icons.navigation, + Icons.near_me, + Icons.network_cell, + Icons.network_check, + Icons.network_locked, + Icons.network_wifi, + Icons.new_releases, + Icons.next_week, + Icons.nfc, + Icons.no_encryption, + Icons.no_sim, + Icons.not_interested, + Icons.not_listed_location, + Icons.note, + Icons.note_add, + Icons.notification_important, + Icons.notifications, + Icons.notifications_active, + Icons.notifications_none, + Icons.notifications_off, + Icons.notifications_paused, + Icons.offline_bolt, + Icons.offline_pin, + Icons.ondemand_video, + Icons.opacity, + Icons.open_in_browser, + Icons.open_in_new, + Icons.open_with, + Icons.outlined_flag, + Icons.pages, + Icons.pageview, + Icons.palette, + Icons.pan_tool, + Icons.panorama, + Icons.panorama_fish_eye, + Icons.panorama_horizontal, + Icons.panorama_vertical, + Icons.panorama_wide_angle, + Icons.party_mode, + Icons.pause, + Icons.pause_circle_filled, + Icons.pause_circle_outline, + Icons.payment, + Icons.people, + Icons.people_outline, + Icons.perm_camera_mic, + Icons.perm_contact_calendar, + Icons.perm_data_setting, + Icons.perm_device_information, + Icons.perm_identity, + Icons.perm_media, + Icons.perm_phone_msg, + Icons.perm_scan_wifi, + Icons.person, + Icons.person_add, + Icons.person_outline, + Icons.person_pin, + Icons.person_pin_circle, + Icons.personal_video, + Icons.pets, + Icons.phone, + Icons.phone_android, + Icons.phone_bluetooth_speaker, + Icons.phone_forwarded, + Icons.phone_in_talk, + Icons.phone_iphone, + Icons.phone_locked, + Icons.phone_missed, + Icons.phone_paused, + Icons.phonelink, + Icons.phonelink_erase, + Icons.phonelink_lock, + Icons.phonelink_off, + Icons.phonelink_ring, + Icons.phonelink_setup, + Icons.photo, + Icons.photo_album, + Icons.photo_camera, + Icons.photo_filter, + Icons.photo_library, + Icons.photo_size_select_actual, + Icons.photo_size_select_large, + Icons.photo_size_select_small, + Icons.picture_as_pdf, + Icons.picture_in_picture, + Icons.picture_in_picture_alt, + Icons.pie_chart, + Icons.pie_chart_outlined, + Icons.pin_drop, + Icons.place, + Icons.play_arrow, + Icons.play_circle_filled, + Icons.play_circle_outline, + Icons.play_for_work, + Icons.playlist_add, + Icons.playlist_add_check, + Icons.playlist_play, + Icons.plus_one, + Icons.poll, + Icons.polymer, + Icons.pool, + Icons.portable_wifi_off, + Icons.portrait, + Icons.power, + Icons.power_input, + Icons.power_settings_new, + Icons.pregnant_woman, + Icons.present_to_all, + Icons.print, + Icons.priority_high, + Icons.public, + Icons.publish, + Icons.query_builder, + Icons.question_answer, + Icons.queue, + Icons.queue_music, + Icons.queue_play_next, + Icons.radio, + Icons.radio_button_checked, + Icons.radio_button_unchecked, + Icons.rate_review, + Icons.receipt, + Icons.recent_actors, + Icons.record_voice_over, + Icons.redeem, + Icons.redo, + Icons.refresh, + Icons.remove, + Icons.remove_circle, + Icons.remove_circle_outline, + Icons.remove_from_queue, + Icons.remove_red_eye, + Icons.remove_shopping_cart, + Icons.reorder, + Icons.repeat, + Icons.repeat_one, + Icons.replay, + Icons.replay_10, + Icons.replay_30, + Icons.replay_5, + Icons.reply, + Icons.reply_all, + Icons.report, + Icons.report_off, + Icons.report_problem, + Icons.restaurant, + Icons.restaurant_menu, + Icons.restore, + Icons.restore_from_trash, + Icons.restore_page, + Icons.ring_volume, + Icons.room, + Icons.room_service, + Icons.rotate_90_degrees_ccw, + Icons.rotate_left, + Icons.rotate_right, + Icons.rounded_corner, + Icons.router, + Icons.rowing, + Icons.rss_feed, + Icons.rv_hookup, + Icons.satellite, + Icons.save, + Icons.save_alt, + Icons.scanner, + Icons.scatter_plot, + Icons.schedule, + Icons.school, + Icons.score, + Icons.screen_lock_landscape, + Icons.screen_lock_portrait, + Icons.screen_lock_rotation, + Icons.screen_rotation, + Icons.screen_share, + Icons.sd_card, + Icons.sd_storage, + Icons.search, + Icons.security, + Icons.select_all, + Icons.send, + Icons.sentiment_dissatisfied, + Icons.sentiment_neutral, + Icons.sentiment_satisfied, + Icons.sentiment_very_dissatisfied, + Icons.sentiment_very_satisfied, + Icons.settings, + Icons.settings_applications, + Icons.settings_backup_restore, + Icons.settings_bluetooth, + Icons.settings_brightness, + Icons.settings_cell, + Icons.settings_ethernet, + Icons.settings_input_antenna, + Icons.settings_input_component, + Icons.settings_input_composite, + Icons.settings_input_hdmi, + Icons.settings_input_svideo, + Icons.settings_overscan, + Icons.settings_phone, + Icons.settings_power, + Icons.settings_remote, + Icons.settings_system_daydream, + Icons.settings_voice, + Icons.share, + Icons.shop, + Icons.shop_two, + Icons.shopping_basket, + Icons.shopping_cart, + Icons.short_text, + Icons.show_chart, + Icons.shuffle, + Icons.shutter_speed, + Icons.signal_cellular_4_bar, + Icons.signal_cellular_connected_no_internet_4_bar, + Icons.signal_cellular_no_sim, + Icons.signal_cellular_null, + Icons.signal_cellular_off, + Icons.signal_wifi_4_bar, + Icons.signal_wifi_4_bar_lock, + Icons.signal_wifi_off, + Icons.sim_card, + Icons.sim_card_alert, + Icons.skip_next, + Icons.skip_previous, + Icons.slideshow, + Icons.slow_motion_video, + Icons.smartphone, + Icons.smoke_free, + Icons.smoking_rooms, + Icons.sms, + Icons.sms_failed, + Icons.snooze, + Icons.sort, + Icons.sort_by_alpha, + Icons.spa, + Icons.space_bar, + Icons.speaker, + Icons.speaker_group, + Icons.speaker_notes, + Icons.speaker_notes_off, + Icons.speaker_phone, + Icons.spellcheck, + Icons.star, + Icons.star_border, + Icons.star_half, + Icons.stars, + Icons.stay_current_landscape, + Icons.stay_current_portrait, + Icons.stay_primary_landscape, + Icons.stay_primary_portrait, + Icons.stop, + Icons.stop_screen_share, + Icons.storage, + Icons.store, + Icons.store_mall_directory, + Icons.straighten, + Icons.streetview, + Icons.strikethrough_s, + Icons.style, + Icons.subdirectory_arrow_left, + Icons.subdirectory_arrow_right, + Icons.subject, + Icons.subscriptions, + Icons.subtitles, + Icons.subway, + Icons.supervised_user_circle, + Icons.supervisor_account, + Icons.surround_sound, + Icons.swap_calls, + Icons.swap_horiz, + Icons.swap_horizontal_circle, + Icons.swap_vert, + Icons.swap_vertical_circle, + Icons.switch_camera, + Icons.switch_video, + Icons.sync, + Icons.sync_disabled, + Icons.sync_problem, + Icons.system_update, + Icons.system_update_alt, + Icons.tab, + Icons.tab_unselected, + Icons.table_chart, + Icons.tablet, + Icons.tablet_android, + Icons.tablet_mac, + Icons.tag_faces, + Icons.tap_and_play, + Icons.terrain, + Icons.text_fields, + Icons.text_format, + Icons.text_rotate_up, + Icons.text_rotate_vertical, + Icons.text_rotation_angledown, + Icons.text_rotation_angleup, + Icons.text_rotation_down, + Icons.text_rotation_none, + Icons.textsms, + Icons.texture, + Icons.theaters, + Icons.thumb_down, + Icons.thumb_up, + Icons.thumbs_up_down, + Icons.time_to_leave, + Icons.timelapse, + Icons.timeline, + Icons.timer, + Icons.timer_10, + Icons.timer_3, + Icons.timer_off, + Icons.title, + Icons.toc, + Icons.today, + Icons.toll, + Icons.tonality, + Icons.touch_app, + Icons.toys, + Icons.track_changes, + Icons.traffic, + Icons.train, + Icons.tram, + Icons.transfer_within_a_station, + Icons.transform, + Icons.transit_enterexit, + Icons.translate, + Icons.trending_down, + Icons.trending_flat, + Icons.trending_up, + Icons.trip_origin, + Icons.tune, + Icons.turned_in, + Icons.turned_in_not, + Icons.tv, + Icons.unarchive, + Icons.undo, + Icons.unfold_less, + Icons.unfold_more, + Icons.update, + Icons.usb, + Icons.verified_user, + Icons.vertical_align_bottom, + Icons.vertical_align_center, + Icons.vertical_align_top, + Icons.vibration, + Icons.video_call, + Icons.video_label, + Icons.video_library, + Icons.videocam, + Icons.videocam_off, + Icons.videogame_asset, + Icons.view_agenda, + Icons.view_array, + Icons.view_carousel, + Icons.view_column, + Icons.view_comfy, + Icons.view_compact, + Icons.view_day, + Icons.view_headline, + Icons.view_list, + Icons.view_module, + Icons.view_quilt, + Icons.view_stream, + Icons.view_week, + Icons.vignette, + Icons.visibility, + Icons.visibility_off, + Icons.voice_chat, + Icons.voicemail, + Icons.volume_down, + Icons.volume_mute, + Icons.volume_off, + Icons.volume_up, + Icons.vpn_key, + Icons.vpn_lock, + Icons.wallpaper, + Icons.warning, + Icons.watch, + Icons.watch_later, + Icons.wb_auto, + Icons.wb_cloudy, + Icons.wb_incandescent, + Icons.wb_iridescent, + Icons.wb_sunny, + Icons.wc, + Icons.web, + Icons.web_asset, + Icons.weekend, + Icons.whatshot, + Icons.widgets, + Icons.wifi, + Icons.wifi_lock, + Icons.wifi_tethering, + Icons.work, + Icons.wrap_text, + Icons.youtube_searched_for, + Icons.zoom_in, + Icons.zoom_out, + Icons.zoom_out_map, + ]; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/indeterminate_progress/widget_indeterminate_progress.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/indeterminate_progress/widget_indeterminate_progress.dart new file mode 100644 index 00000000..fec0c2a2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/indeterminate_progress/widget_indeterminate_progress.dart @@ -0,0 +1,402 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class IndeterminateProgressWidgetPage extends StatefulWidget { + IndeterminateProgressWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "IndeterminateProgress", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _ColorWidget(), + _SizedWidget(), + _DurationWidget(), + _ReversedWidget(), + _CurveWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Expanded( + child: NeumorphicProgressIndeterminate(), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgressIndeterminate(), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ColorWidget extends StatefulWidget { + @override + createState() => _ColorWidgetState(); +} + +class _ColorWidgetState extends State<_ColorWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Expanded( + child: NeumorphicProgressIndeterminate( + style: ProgressStyle( + accent: Colors.green, + variant: Colors.purple, + ), + ), +), +"""); + } + + Color accent = Colors.green; + Color variant = Colors.purple; + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + Row( + children: [ + Text("Accent : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + accent = color; + }); + }, + color: accent, + ), + SizedBox(width: 12), + Text("Variant : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + variant = color; + }); + }, + color: variant, + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Text( + "Default", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgressIndeterminate( + style: ProgressStyle( + accent: accent, + variant: variant, + ), + ), + ), + SizedBox(width: 12), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _SizedWidget extends StatefulWidget { + @override + createState() => _SizedWidgetState(); +} + +class _SizedWidgetState extends State<_SizedWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Expanded( + child: NeumorphicProgressIndeterminate( + height: 30, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Text( + "Sized", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgressIndeterminate( + height: 30, + ), + ), + SizedBox(width: 12), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _DurationWidget extends StatefulWidget { + @override + createState() => _DurationWidgetState(); +} + +class _DurationWidgetState extends State<_DurationWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Expanded( + child: NeumorphicProgressIndeterminate( + duration: Duration(seconds: 10), + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Text( + "Duration", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgressIndeterminate( + duration: Duration(seconds: 10), + ), + ), + SizedBox(width: 12), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ReversedWidget extends StatefulWidget { + @override + createState() => _ReversedWidgetState(); +} + +class _ReversedWidgetState extends State<_ReversedWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Expanded( + child: NeumorphicProgressIndeterminate( + reverse: true, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Reversed", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgressIndeterminate( + reverse: true, + ), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _CurveWidget extends StatefulWidget { + @override + createState() => _CurveWidgetState(); +} + +class _CurveWidgetState extends State<_CurveWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +Expanded( + child: NeumorphicProgressIndeterminate( + curve: Curves.bounceOut, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Curve", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgressIndeterminate( + curve: Curves.bounceOut, + ), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/indicator/widget_indicator.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/indicator/widget_indicator.dart new file mode 100644 index 00000000..8735374d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/indicator/widget_indicator.dart @@ -0,0 +1,380 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +import 'dart:math' show Random; + +class IndicatorWidgetPage extends StatefulWidget { + IndicatorWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Indicator", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _DefaultOrientationWidget(), + _DurationWidget(), + _ColorWidget(), + _CurveWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + double percent = 0.6; + + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicIndicator( + height: 100, + width: 20, + percent: 0.6, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicIndicator( + height: 100, + width: 20, + percent: percent, + ), + SizedBox(width: 12), + FlatButton( + child: Text('Update'), + onPressed: () { + setState(() { + percent = Random().nextDouble(); + }); + }), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _DefaultOrientationWidget extends StatefulWidget { + @override + createState() => _DefaultOrientationWidgetState(); +} + +class _DefaultOrientationWidgetState extends State<_DefaultOrientationWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicIndicator( + width: 150, + height: 15, + orientation: NeumorphicIndicatorOrientation.horizontal, + percent: 0.7, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Orientation\nHorizontal", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicIndicator( + width: 150, + height: 15, + orientation: NeumorphicIndicatorOrientation.horizontal, + percent: 0.7, + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ColorWidget extends StatefulWidget { + @override + createState() => _ColorWidgetState(); +} + +class _ColorWidgetState extends State<_ColorWidget> { + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicIndicator( + width: 150, + height: 15, + orientation: NeumorphicIndicatorOrientation.horizontal, + percent: 0.7, + style: IndicatorStyle( + variant: variant, + accent: accent + ), +), +"""); + } + + Color accent = Colors.green; + Color variant = Colors.purple; + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + Row( + children: [ + Text("Accent : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + accent = color; + }); + }, + color: accent, + ), + SizedBox(width: 12), + Text("Variant : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + variant = color; + }); + }, + color: variant, + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Text( + "Colorized", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicIndicator( + width: 150, + height: 15, + orientation: NeumorphicIndicatorOrientation.horizontal, + percent: 0.7, + style: IndicatorStyle(variant: variant, accent: accent), + ), + SizedBox(width: 12), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _DurationWidget extends StatefulWidget { + @override + createState() => _DurationWidgetState(); +} + +class _DurationWidgetState extends State<_DurationWidget> { + double percent = 0.3; + + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicIndicator( + height: 100, + width: 20, + percent: 0.3, + duration: Duration(seconds: 1), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Duration", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicIndicator( + height: 100, + width: 20, + percent: percent, + duration: Duration(seconds: 1), + ), + SizedBox(width: 12), + FlatButton( + child: Text('Update'), + onPressed: () { + setState(() { + percent = Random().nextDouble(); + }); + }), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _CurveWidget extends StatefulWidget { + @override + createState() => _CurveWidgetState(); +} + +class _CurveWidgetState extends State<_CurveWidget> { + double percent = 0.3; + + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicIndicator( + height: 100, + width: 20, + percent: 0.3, + curve: Curves.bounceOut, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Curve", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicIndicator( + height: 100, + width: 20, + percent: percent, + curve: Curves.bounceOut), + SizedBox(width: 12), + FlatButton( + child: Text('Update'), + onPressed: () { + setState(() { + percent = Random().nextDouble(); + }); + }), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/progress/widget_progress.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/progress/widget_progress.dart new file mode 100644 index 00000000..2e947a98 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/progress/widget_progress.dart @@ -0,0 +1,398 @@ +import '../../lib/Code.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +import 'dart:math' show Random; + +class ProgressWidgetPage extends StatefulWidget { + ProgressWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Progress", + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _ColorWidget(), + _SizedWidget(), + _DurationWidget(), + _CurveWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + double percent = 0.2; + + Widget _buildCode(BuildContext context) { + return Code(""" +double percent = 0.2; + +Expanded( + child: NeumorphicProgress( + percent: percent, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgress( + percent: percent, + ), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + FlatButton( + child: Text('Update'), + onPressed: () { + setState(() { + percent = Random().nextDouble(); + }); + }), + _buildCode(context), + ], + ); + } +} + +class _ColorWidget extends StatefulWidget { + @override + createState() => _ColorWidgetState(); +} + +class _ColorWidgetState extends State<_ColorWidget> { + double percent = 0.5; + + Widget _buildCode(BuildContext context) { + return Code(""" +double percent = 0.5; + +Expanded( + child: NeumorphicProgress( + style: ProgressStyle( + accent: Colors.green, + variant: Colors.purple, + ), + percent: percent, + ), +), +"""); + } + + Color accent = Colors.green; + Color variant = Colors.purple; + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + Row( + children: [ + Text("Accent : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + accent = color; + }); + }, + color: accent, + ), + SizedBox(width: 12), + Text("Variant : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + variant = color; + }); + }, + color: variant, + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Text( + "Default", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgress( + style: ProgressStyle( + accent: accent, + variant: variant, + ), + percent: percent, + ), + ), + SizedBox(width: 12), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _SizedWidget extends StatefulWidget { + @override + createState() => _SizedWidgetState(); +} + +class _SizedWidgetState extends State<_SizedWidget> { + double percent = 0.5; + + Widget _buildCode(BuildContext context) { + return Code(""" +double percent = 0.5; + +Expanded( + child: NeumorphicProgress( + height: 30, + percent: percent, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Text( + "Sized", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgress( + height: 30, + percent: percent, + ), + ), + SizedBox(width: 12), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _DurationWidget extends StatefulWidget { + @override + createState() => _DurationWidgetState(); +} + +class _DurationWidgetState extends State<_DurationWidget> { + double percent = 0.2; + + Widget _buildCode(BuildContext context) { + return Code(""" +double percent = 0.2; + +Expanded( + child: NeumorphicProgress( + percent: percent, + duration: Duration(seconds: 1), + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Duration", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgress( + percent: percent, + duration: Duration(seconds: 1), + ), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + FlatButton( + child: Text('Update'), + onPressed: () { + setState(() { + percent = Random().nextDouble(); + }); + }), + _buildCode(context), + ], + ); + } +} + +class _CurveWidget extends StatefulWidget { + @override + createState() => _CurveWidgetState(); +} + +class _CurveWidgetState extends State<_CurveWidget> { + double percent = 0.2; + + Widget _buildCode(BuildContext context) { + return Code(""" +double percent = 0.2; + +Expanded( + child: NeumorphicProgress( + percent: percent, + curve: Curves.bounceOut, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Curve", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicProgress( + percent: percent, + curve: Curves.bounceOut, + ), + ), + SizedBox(width: 12), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + FlatButton( + child: Text('Update'), + onPressed: () { + setState(() { + percent = Random().nextDouble(); + }); + }), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/radiobutton/widget_radio_button.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/radiobutton/widget_radio_button.dart new file mode 100644 index 00000000..137a2a36 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/radiobutton/widget_radio_button.dart @@ -0,0 +1,332 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class RadioButtonWidgetPage extends StatefulWidget { + RadioButtonWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Radios", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + CircleRadios(), + _EnabledDisabledWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + int groupValue; + + Widget _buildCode(BuildContext context) { + return Code(""" +int groupValue; + +NeumorphicRadio( + groupValue: groupValue + value: 1991, + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + child: Text("2012"), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicRadio( + //uncomment to test colors + //style: NeumorphicRadioStyle( + // selectedColor: Colors.black, + // unselectedColor: Colors.blue + //), + groupValue: groupValue, + value: 1991, + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + padding: EdgeInsets.all(8.0), + child: Text("1991"), + ), + SizedBox(width: 12), + NeumorphicRadio( + value: 2000, + groupValue: groupValue, + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + padding: EdgeInsets.all(8.0), + child: Text("2000"), + ), + SizedBox(width: 12), + NeumorphicRadio( + groupValue: groupValue, + value: 2012, + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + padding: EdgeInsets.all(8.0), + child: Text("2012"), + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class CircleRadios extends StatefulWidget { + @override + createState() => _CircleRadiosState(); +} + +class _CircleRadiosState extends State { + String groupValue; + + Widget _buildCode(BuildContext context) { + return Code(""" +String groupValue; + +NeumorphicRadio( + groupValue: groupValue + style: NeumorphicRadioStyle(boxShape: NeumorphicBoxShape.circle()), + value: "A", + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + child: Text("A"), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Circle", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicRadio( + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + groupValue: groupValue, + value: "A", + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + padding: EdgeInsets.all(18.0), + child: Text("A"), + ), + SizedBox(width: 12), + NeumorphicRadio( + value: "B", + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + groupValue: groupValue, + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + padding: EdgeInsets.all(18.0), + child: Text("B"), + ), + SizedBox(width: 12), + NeumorphicRadio( + style: NeumorphicRadioStyle( + boxShape: NeumorphicBoxShape.circle(), + ), + groupValue: groupValue, + value: "C", + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + padding: EdgeInsets.all(18.0), + child: Text("C"), + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _EnabledDisabledWidget extends StatefulWidget { + @override + createState() => _EnabledDisabledWidgetState(); +} + +class _EnabledDisabledWidgetState extends State<_EnabledDisabledWidget> { + int groupValue; + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Enabled :", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicRadio( + groupValue: groupValue, + value: 1, + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 18), + child: Text("First"), + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + ), + SizedBox(width: 24), + Text( + "Disabled :", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicRadio( + isEnabled: false, + groupValue: groupValue, + value: 2, + padding: EdgeInsets.symmetric(vertical: 10, horizontal: 18), + child: Text("Second"), + onChanged: (value) { + setState(() { + groupValue = value; + }); + }, + ), + ], + ), + ); + } + + Widget _buildCode(BuildContext context) { + return Code(""" +int groupValue; + +NeumorphicRadio( + isEnabled: false, + groupValue: groupValue, + value: 2, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, + child: Text("Second"), +), +"""); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/range_slider/widget_range_slider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/range_slider/widget_range_slider.dart new file mode 100644 index 00000000..9f14ac21 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/range_slider/widget_range_slider.dart @@ -0,0 +1,274 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class RangeSliderWidgetPage extends StatefulWidget { + RangeSliderWidgetPage({Key key}) : super(key: key); + + @override + createState() => _RangeWidgetPageState(); +} + +class _RangeWidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Range Slider", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _ColorWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + double lowVal = 30; + double highVal = 70; + + Widget _buildCode(BuildContext context) { + return Code(""" + double lowVal = 30; + double highVal = 70; + + Expanded( + child: NeumorphicRangeSlider( + valueLow: lowVal, + valueHigh: highVal, + min: 18, + max: 90, + onChangedLow: (value) { + setState(() { + lowVal = value; + }); + }, + onChangeHigh: (value) { + setState(() { + highVal = value; + }); + }, + ), + ), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicRangeSlider( + valueLow: lowVal, + valueHigh: highVal, + min: 18, + max: 90, + onChangedLow: (value) { + setState(() { + lowVal = value; + }); + }, + onChangeHigh: (value) { + setState(() { + highVal = value; + }); + }, + ), + ), + SizedBox(width: 12), + Text( + "${lowVal.round()} - ${highVal.round()}", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ColorWidget extends StatefulWidget { + @override + createState() => _ColorWidgetState(); +} + +class _ColorWidgetState extends State<_ColorWidget> { + double lowVal = 30; + double highVal = 80; + + Widget _buildCode(BuildContext context) { + return Code(""" +double lowVal = 30; +double highVal = 80; + + Expanded( + child: NeumorphicRangeSlider( + style: RangeSliderStyle( + accent: accent, + variant: variant, + ), + valueLow: lowVal, + valueHigh: highVal, + min: 18, + max: 90, + onChangedLow: (value) { + setState(() { + lowVal = value; + }); + }, + onChangeHigh: (value) { + setState(() { + highVal = value; + }); + }, + ), + ), +), +"""); + } + + Color accent = Colors.green; + Color variant = Colors.purple; + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + Row( + children: [ + Text("Accent : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + accent = color; + }); + }, + color: accent, + ), + SizedBox(width: 12), + Text("Variant : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + variant = color; + }); + }, + color: variant, + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Text( + "Default", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicRangeSlider( + style: RangeSliderStyle( + accent: accent, + variant: variant, + ), + valueLow: lowVal, + valueHigh: highVal, + min: 18, + max: 90, + onChangedLow: (value) { + setState(() { + lowVal = value; + }); + }, + onChangeHigh: (value) { + setState(() { + highVal = value; + }); + }, + ), + ), + SizedBox(width: 12), + Text( + "${lowVal.round()} - ${highVal.round()}", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/slider/widget_slider.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/slider/widget_slider.dart new file mode 100644 index 00000000..68c50c02 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/slider/widget_slider.dart @@ -0,0 +1,245 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class SliderWidgetPage extends StatefulWidget { + SliderWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Slider", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _ColorWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + double age = 20; + + Widget _buildCode(BuildContext context) { + return Code(""" +double age = 20; + +Expanded( + child: NeumorphicSlider( + value: age, + min: 18, + max: 90, + onChanged: (value) { + setState(() { + age = value; + }); + }, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicSlider( + value: age, + min: 18, + max: 90, + onChanged: (value) { + setState(() { + age = value; + }); + }, + ), + ), + SizedBox(width: 12), + Text( + "${age.round()}", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ColorWidget extends StatefulWidget { + @override + createState() => _ColorWidgetState(); +} + +class _ColorWidgetState extends State<_ColorWidget> { + double age = 50; + + Widget _buildCode(BuildContext context) { + return Code(""" +double age = 50; + +Expanded( + child: NeumorphicSlider( + style: SliderStyle( + accent: Colors.green, + variant: Colors.purple, + ), + value: age, + min: 18, + max: 90, + onChanged: (value) { + setState(() { + age = value; + }); + }, + ), +), +"""); + } + + Color accent = Colors.green; + Color variant = Colors.purple; + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + Row( + children: [ + Text("Accent : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + accent = color; + }); + }, + color: accent, + ), + SizedBox(width: 12), + Text("Variant : "), + ColorSelector( + onColorChanged: (color) { + setState(() { + variant = color; + }); + }, + color: variant, + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Text( + "Default", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicSlider( + style: SliderStyle( + accent: accent, + variant: variant, + ), + value: age, + min: 18, + max: 90, + onChanged: (value) { + setState(() { + age = value; + }); + }, + ), + ), + SizedBox(width: 12), + Text( + "${age.round()}", + style: + TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/switch/widget_switch.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/switch/widget_switch.dart new file mode 100644 index 00000000..691c4a7e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/switch/widget_switch.dart @@ -0,0 +1,507 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/color_selector.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class SwitchWidgetPage extends StatefulWidget { + SwitchWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Switch", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _ColorizableWidget(), + ColorizableThumbSwitch(), + _FlatConcaveConvexWidget(), + _EnabledDisabledWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + bool isChecked = false; + bool isEnabled = true; + + Widget _buildCode(BuildContext context) { + return Code(""" +bool isChecked; + +NeumorphicSwitch( + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicSwitch( + isEnabled: isEnabled, + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, + ), + SizedBox(width: 12), + FlatButton( + onPressed: () { + setState(() { + isEnabled = !isEnabled; + }); + }, + child: Text(isEnabled ? 'Disable' : 'Enable')) + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _FlatConcaveConvexWidget extends StatefulWidget { + @override + createState() => _FlatConcaveConvexWidgetState(); +} + +class _FlatConcaveConvexWidgetState extends State<_FlatConcaveConvexWidget> { + bool isChecked = false; + + Widget _buildCode(BuildContext context) { + return Code(""" +bool isChecked; + +NeumorphicSwitch( + value: isChecked, + style: NeumorphicSwitchStyle( + thumbShape: NeumorphicShape.flat + //or convex, concave + ), + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Flat", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicSwitch( + style: NeumorphicSwitchStyle(thumbShape: NeumorphicShape.flat), + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, + ) + ], + ), + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Concave", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicSwitch( + style: + NeumorphicSwitchStyle(thumbShape: NeumorphicShape.concave), + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Convex", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicSwitch( + style: + NeumorphicSwitchStyle(thumbShape: NeumorphicShape.convex), + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _ColorizableWidget extends StatefulWidget { + @override + createState() => _ColorizableWidgetState(); +} + +class _ColorizableWidgetState extends State<_ColorizableWidget> { + bool isChecked = false; + Color currentColor = Colors.green; + + Widget _buildCode(BuildContext context) { + return Code(""" +bool isChecked; + +NeumorphicSwitch( + value: isChecked, + style: NeumorphicSwitchStyle( + activeTrackColor: Colors.green + ), + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Color", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + ColorSelector( + color: currentColor, + onColorChanged: (color) { + setState(() { + currentColor = color; + }); + }, + ), + SizedBox(width: 12), + NeumorphicSwitch( + value: isChecked, + style: NeumorphicSwitchStyle(activeTrackColor: currentColor), + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class ColorizableThumbSwitch extends StatefulWidget { + @override + createState() => _ColorizableThumbSwitchState(); +} + +class _ColorizableThumbSwitchState extends State { + bool isChecked = false; + Color thumbColor = Colors.purple; + Color trackColor = Colors.lightGreen; + + Widget _buildCode(BuildContext context) { + return Code(""" +bool isChecked; + +NeumorphicSwitch( + value: isChecked, + style: NeumorphicSwitchStyle( + activeTrackColor: Colors.lightGreen, + activeThumbColor: Colors.purple + ), + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + children: [ + Text( + "Track", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + ColorSelector( + color: trackColor, + onColorChanged: (color) { + setState(() { + trackColor = color; + }); + }, + ), + SizedBox(width: 12), + Text( + "Thumb", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + ColorSelector( + color: thumbColor, + onColorChanged: (color) { + setState(() { + thumbColor = color; + }); + }, + ), + SizedBox(width: 12), + NeumorphicSwitch( + value: isChecked, + style: NeumorphicSwitchStyle( + activeTrackColor: trackColor, activeThumbColor: thumbColor), + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _EnabledDisabledWidget extends StatefulWidget { + @override + createState() => _EnabledDisabledWidgetState(); +} + +class _EnabledDisabledWidgetState extends State<_EnabledDisabledWidget> { + bool isChecked1 = false; + bool isChecked2 = false; + + Widget _buildCode(BuildContext context) { + return Code(""" +bool isChecked; + +NeumorphicSwitch( + value: isChecked, + isEnabled: false, + onChanged: (value) { + setState(() { + isChecked = value; + }); + }, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Column( + children: [ + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Enabled", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicSwitch( + style: + NeumorphicSwitchStyle(thumbShape: NeumorphicShape.concave), + value: isChecked1, + onChanged: (value) { + setState(() { + isChecked1 = value; + }); + }, + ), + ], + ), + SizedBox(height: 12), + Row( + children: [ + Container( + width: 100, + child: Text( + "Disabled", + style: TextStyle( + color: NeumorphicTheme.defaultTextColor(context)), + ), + ), + SizedBox(width: 12), + NeumorphicSwitch( + isEnabled: false, + style: + NeumorphicSwitchStyle(thumbShape: NeumorphicShape.convex), + value: isChecked2, + onChanged: (value) { + setState(() { + isChecked2 = value; + }); + }, + ), + ], + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/toggle/widget_toggle.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/toggle/widget_toggle.dart new file mode 100644 index 00000000..517bdbcc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/toggle/widget_toggle.dart @@ -0,0 +1,301 @@ +import '../../lib/Code.dart'; +import '../../lib/ThemeConfigurator.dart'; +import '../../lib/top_bar.dart'; +import 'package:flutter/material.dart'; +import '../../lib/flutter_neumorphic.dart'; + +class ToggleWidgetPage extends StatefulWidget { + ToggleWidgetPage({Key key}) : super(key: key); + + @override + createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + themeMode: ThemeMode.light, + theme: NeumorphicThemeData( + lightSource: LightSource.topLeft, + accentColor: NeumorphicColors.accent, + depth: 4, + intensity: 0.5, + ), + child: _Page(), + ); + } +} + +class _Page extends StatefulWidget { + @override + createState() => _PageState(); +} + +class _PageState extends State<_Page> { + @override + Widget build(BuildContext context) { + return NeumorphicBackground( + padding: EdgeInsets.all(8), + child: Scaffold( + appBar: TopBar( + title: "Toggle", + actions: [ + ThemeConfigurator(), + ], + ), + backgroundColor: Colors.transparent, + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + _DefaultWidget(), + _SmallWidget(), + SizedBox(height: 30), + ], + ), + ), + ), + ); + } +} + +class _DefaultWidget extends StatefulWidget { + @override + createState() => _DefaultWidgetState(); +} + +class _DefaultWidgetState extends State<_DefaultWidget> { + int _selectedIndex = 0; + + Widget _buildCode(BuildContext context) { + return Code(""" +Expanded( + child: NeumorphicToggle( + height: 50, + selectedIndex: _selectedIndex, + displayForegroundOnlyIfSelected: true, + children: [ + ToggleElement( + background: Center(child: Text("This week", style: TextStyle(fontWeight: FontWeight.w500),)), + foreground: Center(child: Text("This week", style: TextStyle(fontWeight: FontWeight.w700),)), + ), + ToggleElement( + background: Center(child: Text("This month", style: TextStyle(fontWeight: FontWeight.w500),)), + foreground: Center(child: Text("This month", style: TextStyle(fontWeight: FontWeight.w700),)), + ), + ToggleElement( + background: Center(child: Text("This year", style: TextStyle(fontWeight: FontWeight.w500),)), + foreground: Center(child: Text("This year", style: TextStyle(fontWeight: FontWeight.w700),)), + ) + ], + thumb: Neumorphic( + boxShape: NeumorphicBoxShape.roundRect(borderRadius: BorderRadius.all(Radius.circular(12))), + ), + onChanged: (value) { + setState(() { + _selectedIndex = value; + print("_firstSelected: $_selectedIndex"); + }); + }, + ), +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Text( + "Default", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + Expanded( + child: NeumorphicToggle( + height: 50, + style: NeumorphicToggleStyle( + //backgroundColor: Colors.red, + ), + selectedIndex: _selectedIndex, + displayForegroundOnlyIfSelected: true, + children: [ + ToggleElement( + background: Center( + child: Text( + "This week", + style: TextStyle(fontWeight: FontWeight.w500), + )), + foreground: Center( + child: Text( + "This week", + style: TextStyle(fontWeight: FontWeight.w700), + )), + ), + ToggleElement( + background: Center( + child: Text( + "This month", + style: TextStyle(fontWeight: FontWeight.w500), + )), + foreground: Center( + child: Text( + "This month", + style: TextStyle(fontWeight: FontWeight.w700), + )), + ), + ToggleElement( + background: Center( + child: Text( + "This year", + style: TextStyle(fontWeight: FontWeight.w500), + )), + foreground: Center( + child: Text( + "This year", + style: TextStyle(fontWeight: FontWeight.w700), + )), + ) + ], + thumb: Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.all(Radius.circular(12))), + ), + ), + onChanged: (value) { + setState(() { + _selectedIndex = value; + print("_firstSelected: $_selectedIndex"); + }); + }, + ), + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} + +class _SmallWidget extends StatefulWidget { + @override + createState() => _SmallWidgetState(); +} + +class _SmallWidgetState extends State<_SmallWidget> { + int _selectedIndex = 1; + + Widget _buildCode(BuildContext context) { + return Code(""" +NeumorphicToggle( + height: 45, + width: 100, + selectedIndex: _selectedIndex, + children: [ + ToggleElement( + background: Center(child: Icon(Icons.arrow_back, color: Colors.grey[800],)), + ), + ToggleElement(), + ], + thumb: Neumorphic( + boxShape: NeumorphicBoxShape.roundRect( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + child: Icon(Icons.blur_on, color: Colors.grey,), + ), + onAnimationChangedFinished: (value){ + if(value == 0) { + Scaffold.of(context).showSnackBar(SnackBar(content: Text('on back !'))); + print("onAnimationChangedFinished: $_selectedIndex"); + } + }, + onChanged: (value) { + setState(() { + _selectedIndex = value; + print("_firstSelected: $_selectedIndex"); + }); + }, +), +"""); + } + + Widget _buildWidget(BuildContext context) { + return Padding( + padding: EdgeInsets.all(12), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Text( + "Small", + style: TextStyle(color: NeumorphicTheme.defaultTextColor(context)), + ), + SizedBox(width: 12), + NeumorphicToggle( + height: 45, + width: 100, + selectedIndex: _selectedIndex, + children: [ + ToggleElement( + background: Center( + child: Icon( + Icons.arrow_back, + color: Colors.grey[800], + )), + ), + ToggleElement(), + ], + thumb: Neumorphic( + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.all(Radius.circular(12)), + ), + ), + child: Icon( + Icons.blur_on, + color: Colors.grey, + ), + ), + onAnimationChangedFinished: (value) { + if (value == 0) { + Scaffold.of(context) + .showSnackBar(SnackBar(content: Text('on back !'))); + print("onAnimationChangedFinished: $_selectedIndex"); + } + }, + onChanged: (value) { + setState(() { + _selectedIndex = value; + print("_firstSelected: $_selectedIndex"); + }); + }, + ), + ], + ), + ); + } + + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildWidget(context), + _buildCode(context), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/widgets_home.dart b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/widgets_home.dart new file mode 100644 index 00000000..f3e73908 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/flutter_neumorphic/widgets/widgets_home.dart @@ -0,0 +1,175 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; +import 'package:flutter_helper/samples/flutter_neumorphic/lib/top_bar.dart'; + +import 'appbar/widget_app_bar.dart'; +import 'background/widget_background.dart'; +import 'button/widget_button.dart'; +import 'checkbox/widget_checkbox.dart'; +import 'container/widget_container.dart'; +import 'icon/widget_icon.dart'; +import 'indeterminate_progress/widget_indeterminate_progress.dart'; +import 'indicator/widget_indicator.dart'; +import 'progress/widget_progress.dart'; +import 'radiobutton/widget_radio_button.dart'; +import 'range_slider/widget_range_slider.dart'; +import 'slider/widget_slider.dart'; +import 'switch/widget_switch.dart'; +import 'toggle/widget_toggle.dart'; + +class WidgetsHome extends StatelessWidget { + Widget _buildButton({String text, VoidCallback onClick}) { + return NeumorphicButton( + margin: EdgeInsets.only(bottom: 12), + padding: EdgeInsets.symmetric( + vertical: 18, + horizontal: 24, + ), + style: NeumorphicStyle( + boxShape: NeumorphicBoxShape.roundRect( + BorderRadius.circular(12), + ), + shape: NeumorphicShape.flat, + ), + child: Center(child: Text(text)), + onPressed: onClick, + ); + } + + @override + Widget build(BuildContext context) { + return NeumorphicTheme( + theme: NeumorphicThemeData(depth: 8), + child: Scaffold( + backgroundColor: NeumorphicColors.background, + body: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(18.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + TopBar(title: "Widgets"), + _buildButton( + text: "Container", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return ContainerWidgetPage(); + })); + }), + _buildButton( + text: "App bar", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return AppBarWidgetPage(); + })); + }), + _buildButton( + text: "Button", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return ButtonWidgetPage(); + })); + }), + _buildButton( + text: "Icon", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return IconWidgetPage(); + })); + }), + _buildButton( + text: "RadioButton", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return RadioButtonWidgetPage(); + })); + }), + _buildButton( + text: "Checkbox", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return CheckboxWidgetPage(); + })); + }), + _buildButton( + text: "Switch", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return SwitchWidgetPage(); + })); + }), + _buildButton( + text: "Toggle", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return ToggleWidgetPage(); + })); + }), + _buildButton( + text: "Slider", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return SliderWidgetPage(); + })); + }), + _buildButton( + text: "Range slider", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return RangeSliderWidgetPage(); + })); + }), + _buildButton( + text: "Indicator", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return IndicatorWidgetPage(); + })); + }), + _buildButton( + text: "Progress", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return ProgressWidgetPage(); + })); + }), + _buildButton( + text: "IndeterminateProgress", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return IndeterminateProgressWidgetPage(); + })); + }), + _buildButton( + text: "Background", + onClick: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) { + return BackgroundWidgetPage(); + })); + }), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/folding_cell/demos/demos_new.dart b/FlutterHelper/flutter_helper/lib/samples/folding_cell/demos/demos_new.dart new file mode 100644 index 00000000..2137a567 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/folding_cell/demos/demos_new.dart @@ -0,0 +1,354 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/folding_cell/lib/folding_cell/widget.dart'; +import 'package:google_fonts/google_fonts.dart'; + +/// Example 1 folding cell inside [Container] +class FoldingCellSimpleDemo extends StatelessWidget { + final _foldingCellKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Container( + color: Color(0xFF2e282a), + alignment: Alignment.topCenter, + child: SimpleFoldingCell.create( + key: _foldingCellKey, + frontWidget: _buildFrontWidget(), + innerWidget: _buildInnerWidget(), + cellSize: Size(MediaQuery.of(context).size.width, 140), + padding: EdgeInsets.all(15), + animationDuration: Duration(milliseconds: 300), + borderRadius: 10, + onOpen: () => print('cell opened'), + onClose: () => print('cell closed'), + ), + ); + } + + Widget _buildFrontWidget() { + return Container( + color: Color(0xFFffcd3c), + alignment: Alignment.center, + child: Stack( + children: [ + Align( + alignment: Alignment.center, + child: Text( + "CARD TITLE", + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), + ), + ), + Positioned( + right: 10, + bottom: 10, + child: TextButton( + onPressed: () => _foldingCellKey?.currentState?.toggleFold(), + child: Text( + "OPEN", + ), + style: TextButton.styleFrom( + backgroundColor: Colors.white, + minimumSize: Size(80, 40), + ), + ), + ) + ], + ), + ); + } + + Widget _buildInnerWidget() { + return Container( + color: Color(0xFFecf2f9), + padding: EdgeInsets.only(top: 10), + child: Stack( + children: [ + Align( + alignment: Alignment.topCenter, + child: Text( + "CARD TITLE", + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 22.0, + fontWeight: FontWeight.bold, + ), + ), + ), + Align( + alignment: Alignment.center, + child: Text( + "CARD DETAIL", + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 40.0, + ), + ), + ), + Positioned( + right: 10, + bottom: 10, + child: TextButton( + onPressed: () => _foldingCellKey?.currentState?.toggleFold(), + child: Text( + "Close", + ), + style: TextButton.styleFrom( + backgroundColor: Colors.white, + minimumSize: Size(80, 40), + ), + ), + ), + ], + ), + ); + } +} + +/// Example 2 Multiple folding cells inside [Column] +class FoldingCellMultipleCardsDemo extends StatelessWidget { + final _foldingCellKey1 = GlobalKey(); + final _foldingCellKey2 = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Container( + color: Color(0xFF2e282a), + child: Column( + children: [ + SimpleFoldingCell.create( + key: _foldingCellKey1, + frontWidget: _buildFrontWidget(_foldingCellKey1, "CARD 1"), + innerWidget: _buildInnerWidget(_foldingCellKey1), + cellSize: Size(MediaQuery.of(context).size.width, 140), + padding: EdgeInsets.all(15), + animationDuration: Duration(milliseconds: 300), + borderRadius: 10, + onOpen: () => print('cell 1 opened'), + onClose: () => print('cell 1 closed'), + ), + SimpleFoldingCell.create( + key: _foldingCellKey2, + frontWidget: _buildFrontWidget(_foldingCellKey2, "CARD 2"), + innerWidget: _buildInnerWidget(_foldingCellKey2), + cellSize: Size(MediaQuery.of(context).size.width, 125), + padding: EdgeInsets.all(15), + animationDuration: Duration(milliseconds: 300), + borderRadius: 10, + onOpen: () => print('cell 2 opened'), + onClose: () => print('cell 2 closed'), + ), + ], + ), + ); + } + + Widget _buildFrontWidget( + GlobalKey key, String title) { + return Container( + color: Color(0xFFffcd3c), + alignment: Alignment.center, + child: Stack( + children: [ + Align( + alignment: Alignment.center, + child: Text( + title, + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), + ), + ), + Positioned( + right: 10, + bottom: 10, + child: TextButton( + onPressed: () => key?.currentState?.toggleFold(), + child: Text( + "OPEN", + ), + style: TextButton.styleFrom( + backgroundColor: Colors.white, + minimumSize: Size(80, 40), + ), + ), + ) + ], + ), + ); + } + + Widget _buildInnerWidget(GlobalKey key) { + return Container( + color: Color(0xFFecf2f9), + padding: EdgeInsets.only(top: 10), + child: Stack( + children: [ + Align( + alignment: Alignment.topCenter, + child: Text( + "CARD TITLE", + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 22.0, + fontWeight: FontWeight.bold, + ), + ), + ), + Align( + alignment: Alignment.center, + child: Text( + "CARD DETAIL", + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 40.0, + ), + ), + ), + Positioned( + right: 10, + bottom: 10, + child: TextButton( + onPressed: () => key?.currentState?.toggleFold(), + child: Text( + "Close", + ), + style: TextButton.styleFrom( + backgroundColor: Colors.white, + minimumSize: Size(80, 40), + ), + ), + ), + ], + ), + ); + } +} + +/// Example 3 folding cell inside [ListView] +class FoldingCellListViewDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + color: Color(0xFF2e282a), + child: ListView.builder( + itemCount: 100, + itemBuilder: (context, index) { + return SimpleFoldingCell.create( + frontWidget: _buildFrontWidget(index), + innerWidget: _buildInnerWidget(index), + cellSize: Size(MediaQuery.of(context).size.width, 125), + padding: EdgeInsets.all(15), + animationDuration: Duration(milliseconds: 300), + borderRadius: 10, + onOpen: () => print('$index cell opened'), + onClose: () => print('$index cell closed'), + ); + }, + ), + ); + } + + Widget _buildFrontWidget(int index) { + return Builder( + builder: (BuildContext context) { + return Container( + color: Color(0xFFffcd3c), + alignment: Alignment.center, + child: Stack( + children: [ + Align( + alignment: Alignment.center, + child: Text( + "CARD - $index", + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), + ), + ), + Positioned( + right: 10, + bottom: 10, + child: TextButton( + onPressed: () { + final foldingCellState = context + .findAncestorStateOfType(); + foldingCellState?.toggleFold(); + }, + child: Text( + "OPEN", + ), + style: TextButton.styleFrom( + backgroundColor: Colors.white, + minimumSize: Size(80, 40), + ), + ), + ) + ], + ), + ); + }, + ); + } + + Widget _buildInnerWidget(int index) { + return Builder( + builder: (context) { + return Container( + color: Color(0xFFecf2f9), + padding: EdgeInsets.only(top: 10), + child: Stack( + children: [ + Align( + alignment: Alignment.topCenter, + child: Text( + "CARD TITLE - $index", + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 20.0, + fontWeight: FontWeight.bold, + ), + ), + ), + Align( + alignment: Alignment.center, + child: Text( + "CARD DETAIL - $index", + style: GoogleFonts.aldrich( + color: Color(0xFF2e282a), + fontSize: 32.0, + ), + ), + ), + Positioned( + right: 10, + bottom: 10, + child: TextButton( + onPressed: () { + final foldingCellState = context + .findAncestorStateOfType(); + foldingCellState?.toggleFold(); + }, + child: Text( + "Close", + ), + style: TextButton.styleFrom( + backgroundColor: Colors.white, + minimumSize: Size(80, 40), + ), + ), + ), + ], + ), + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/folding_cell/lib/folding_cell.dart b/FlutterHelper/flutter_helper/lib/samples/folding_cell/lib/folding_cell.dart new file mode 100644 index 00000000..b67befa8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/folding_cell/lib/folding_cell.dart @@ -0,0 +1,3 @@ +library folding_cell; + +export 'folding_cell/widget.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/folding_cell/lib/folding_cell/widget.dart b/FlutterHelper/flutter_helper/lib/samples/folding_cell/lib/folding_cell/widget.dart new file mode 100644 index 00000000..733f57e7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/folding_cell/lib/folding_cell/widget.dart @@ -0,0 +1,206 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +/// Folding Cell Widget +class SimpleFoldingCell extends StatefulWidget { + SimpleFoldingCell.create( + {Key key, + @required this.frontWidget, + @required this.innerWidget, + this.cellSize = const Size(100.0, 100.0), + this.unfoldCell = false, + this.skipAnimation = false, + this.padding = + const EdgeInsets.only(left: 20, right: 20, bottom: 5, top: 10), + this.animationDuration = const Duration(milliseconds: 500), + this.borderRadius = 0.0, + this.onOpen, + this.onClose}) + : assert(frontWidget != null), + assert(innerWidget != null), + assert(cellSize != null), + assert(unfoldCell != null), + assert(skipAnimation != null), + assert(padding != null), + assert(animationDuration != null), + assert(borderRadius != null && borderRadius >= 0.0), + super(key: key); + + // Front widget in folded cell + final Widget frontWidget; + + /// Inner widget in unfolded cell + final Widget innerWidget; + + /// Size of cell + final Size cellSize; + + /// If true cell will be unfolded when created, if false cell will be folded when created + final bool unfoldCell; + + /// If true cell will fold and unfold without animation, if false cell folding and unfolding will be animated + final bool skipAnimation; + + /// Padding around cell + final EdgeInsetsGeometry padding; + + /// Animation duration + final Duration animationDuration; + + /// Rounded border radius + final double borderRadius; + + /// Called when cell fold animations completes + final VoidCallback onOpen; + + /// Called when cell unfold animations completes + final VoidCallback onClose; + + @override + SimpleFoldingCellState createState() => SimpleFoldingCellState(); +} + +class SimpleFoldingCellState extends State + with SingleTickerProviderStateMixin { + bool _isExpanded = false; + AnimationController _animationController; + + @override + void initState() { + super.initState(); + + _animationController = + AnimationController(vsync: this, duration: widget.animationDuration); + _animationController.addStatusListener((status) { + if (status == AnimationStatus.completed) { + if (widget.onOpen != null) widget.onOpen(); + } else if (status == AnimationStatus.dismissed) { + if (widget.onClose != null) widget.onClose(); + } + }); + + if (widget.unfoldCell == true) { + _animationController.value = 1; + _isExpanded = true; + } + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _animationController, + builder: (context, child) { + final angle = _animationController.value * pi; + final cellWidth = widget.cellSize.width; + final cellHeight = widget.cellSize.height; + + return Padding( + padding: widget.padding, + child: Container( + color: Colors.transparent, + width: cellWidth, + height: cellHeight + (cellHeight * _animationController.value), + child: Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(widget.borderRadius), + topRight: Radius.circular(widget.borderRadius)), + child: Container( + width: cellWidth, + height: cellHeight, + child: OverflowBox( + minHeight: cellHeight, + maxHeight: cellHeight * 2, + alignment: Alignment.topCenter, + child: ClipRect( + child: Align( + heightFactor: 0.5, + alignment: Alignment.topCenter, + child: widget.innerWidget, + ), + ), + ), + ), + ), + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, 0.001) + ..rotateX(angle), + child: Transform( + alignment: Alignment.center, + transform: Matrix4.rotationX(pi), + child: ClipRRect( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(widget.borderRadius), + bottomRight: Radius.circular(widget.borderRadius)), + child: Container( + width: cellWidth, + height: cellHeight, + child: OverflowBox( + minHeight: cellHeight, + maxHeight: cellHeight * 2, + alignment: Alignment.topCenter, + child: ClipRect( + child: Align( + heightFactor: 0.5, + alignment: Alignment.bottomCenter, + child: widget.innerWidget, + ), + ), + ), + ), + ), + ), + ), + Transform( + alignment: Alignment.bottomCenter, + transform: Matrix4.identity() + ..setEntry(3, 2, 0.001) + ..rotateX(angle), + child: Opacity( + opacity: angle >= 1.5708 ? 0.0 : 1.0, + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(widget.borderRadius), + topRight: Radius.circular(widget.borderRadius)), + child: Container( + width: angle >= 1.5708 ? 0.0 : cellWidth, + height: angle >= 1.5708 ? 0.0 : cellHeight, + child: widget.frontWidget, + ), + ), + ), + ), + ], + ), + ), + ); + }); + } + + void toggleFold() { + if (_isExpanded) { + if (widget.skipAnimation == true) { + _animationController.value = 0; + } else { + _animationController.reverse(); + } + } else { + if (widget.skipAnimation == true) { + _animationController.value = 1; + } else { + _animationController.forward(); + } + } + _isExpanded = !_isExpanded; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/folding_cell/main.dart b/FlutterHelper/flutter_helper/lib/samples/folding_cell/main.dart new file mode 100644 index 00000000..c90acf17 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/folding_cell/main.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +import 'demos/demos_new.dart'; + +/* + Old examples are in `demos_old.dart`; + */ + +void main() => runApp( + MaterialApp( + home: SafeArea( + child: Scaffold( + body: Material( + child: FoldingCellSimpleDemo(), + ), + ), + ), + ), + ); diff --git a/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/liquid_pull_to_refresh.dart b/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/liquid_pull_to_refresh.dart new file mode 100644 index 00000000..1bc5693f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/liquid_pull_to_refresh.dart @@ -0,0 +1,748 @@ +library liquid_pull_to_refresh; + +import 'dart:async'; +import 'dart:math'; +import 'dart:math' as math; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/liquid_pull_to_refresh/lib/src/circular_progress.dart'; +import 'package:flutter_helper/samples/liquid_pull_to_refresh/lib/src/clipper.dart'; + +// The over-scroll distance that moves the indicator to its maximum +// displacement, as a percentage of the scrollable's container extent. +const double _kDragContainerExtentPercentage = 0.25; + +// How much the scroll's drag gesture can overshoot the LiquidPullToRefresh's +// displacement; max displacement = _kDragSizeFactorLimit * displacement. +const double _kDragSizeFactorLimit = 1.5; + +// When the scroll ends, the duration of the progress indicator's animation +// to the LiquidPullToRefresh's displacement. +// const Duration _kIndicatorSnapDuration = Duration(milliseconds: 150); + +// The duration of the ScaleTransitionIn of box that starts when the +// refresh action has completed. +const Duration _kIndicatorScaleDuration = Duration(milliseconds: 200); + +/// The signature for a function that's called when the user has dragged a +/// [LiquidPullToRefresh] far enough to demonstrate that they want the app to +/// refresh. The returned [Future] must complete when the refresh operation is +/// finished. +/// +/// Used by [LiquidPullToRefresh.onRefresh]. +typedef RefreshCallback = Future Function(); + +// The state machine moves through these modes only when the scrollable +// identified by scrollableKey has been scrolled to its min or max limit. +enum _LiquidPullToRefreshMode { + drag, // Pointer is down. + armed, // Dragged far enough that an up event will run the onRefresh callback. + snap, // Animating to the indicator's final "displacement". + refresh, // Running the refresh callback. + done, // Animating the indicator's fade-out after refreshing. + canceled, // Animating the indicator's fade-out after not arming. +} + +class LiquidPullToRefresh extends StatefulWidget { + const LiquidPullToRefresh({ + Key key, + this.animSpeedFactor = 1.0, + @required this.child, + @required this.onRefresh, + this.color, + this.backgroundColor, + this.height, + this.springAnimationDurationInMilliseconds = 1000, + this.borderWidth = 2.0, + this.showChildOpacityTransition = true, + }) : assert(child != null), + assert(onRefresh != null), + assert(animSpeedFactor >= 1.0), + super(key: key); + + /// The widget below this widget in the tree. + /// + /// The progress indicator will be stacked on top of this child. The indicator + /// will appear when child's Scrollable descendant is over-scrolled. + /// + /// Typically a [ListView] or [CustomScrollView]. + final Widget child; + + /// The distance from the child's top or bottom edge to where the box + /// will settle after the spring effect. + /// + /// default is set to 100.0 + final double height; + + /// Duration in milliseconds of springy effect that occurs when + /// we leave dragging after full drag. + /// + /// default to 1000 + final int springAnimationDurationInMilliseconds; + + /// To regulate the "speed of the animation" towards the end. + /// To hasten it give a value > 1.0 and vice versa. + /// + /// default to 1.0 + final double animSpeedFactor; + + /// Border width of progressing circle in Progressing Indicator + /// + /// default to 2.0 + final double borderWidth; + + /// Whether to show child opacity transition or not. + /// + /// default to true + final bool showChildOpacityTransition; + + /// A function that's called when the user has dragged the progress indicator + /// far enough to demonstrate that they want the app to refresh. The returned + /// [Future] must complete when the refresh operation is finished. + final RefreshCallback onRefresh; + + /// The progress indicator's foreground color. The current theme's + /// [ThemeData.accentColor] by default. + final Color color; + + /// The progress indicator's background color. The current theme's + /// [ThemeData.canvasColor] by default. + final Color backgroundColor; + + @override + LiquidPullToRefreshState createState() => LiquidPullToRefreshState(); +} + +class LiquidPullToRefreshState extends State + with TickerProviderStateMixin { + AnimationController _springController; + Animation _springAnimation; + + AnimationController _progressingController; + Animation _progressingRotateAnimation; + Animation _progressingPercentAnimation; + Animation _progressingStartAngleAnimation; + + AnimationController _ringDisappearController; + Animation _ringRadiusAnimation; + Animation _ringOpacityAnimation; + + AnimationController _showPeakController; + Animation _peakHeightUpAnimation; + Animation _peakHeightDownAnimation; + + AnimationController _indicatorMoveWithPeakController; + Animation _indicatorTranslateWithPeakAnimation; + Animation _indicatorRadiusWithPeakAnimation; + + AnimationController _indicatorTranslateInOutController; + Animation _indicatorTranslateAnimation; + + AnimationController _radiusController; + Animation _radiusAnimation; + + Animation _childOpacityAnimation; + + AnimationController _positionController; + Animation _value; + Animation _valueColor; + + _LiquidPullToRefreshMode _mode; + Future _pendingRefreshFuture; + bool _isIndicatorAtTop; + double _dragOffset; + + static final Animatable _threeQuarterTween = + Tween(begin: 0.0, end: 0.75); + static final Animatable _oneToZeroTween = + Tween(begin: 1.0, end: 0.0); + + @override + void initState() { + super.initState(); + _springController = AnimationController(vsync: this); + _springAnimation = + _springController.drive(Tween(begin: 1.0, end: -1.0)); + + _progressingController = AnimationController( + vsync: this, duration: Duration(milliseconds: 1000)); + _progressingRotateAnimation = + Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( + parent: _progressingController, + curve: Interval(0.0, 1.0), + )); + _progressingPercentAnimation = + Tween(begin: 0.25, end: 5 / 6).animate(CurvedAnimation( + parent: _progressingController, + curve: Interval(0.0, 1.0, curve: ProgressRingCurve()), + )); + _progressingStartAngleAnimation = + Tween(begin: -2 / 3, end: 1 / 2).animate(CurvedAnimation( + parent: _progressingController, + curve: Interval(0.5, 1.0), + )); + + _ringDisappearController = AnimationController(vsync: this); + _ringRadiusAnimation = Tween(begin: 1.0, end: 1.25).animate( + CurvedAnimation( + parent: _ringDisappearController, + curve: Interval(0.0, 0.2, curve: Curves.easeOut))); + _ringOpacityAnimation = Tween(begin: 1.0, end: 0.0).animate( + CurvedAnimation( + parent: _ringDisappearController, + curve: Interval(0.0, 0.2, curve: Curves.easeIn))); + + _showPeakController = AnimationController(vsync: this); + _peakHeightUpAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _showPeakController, + curve: Interval(0.1, 0.2, curve: Curves.easeOut))); + _peakHeightDownAnimation = Tween(begin: 1.0, end: 0.0).animate( + CurvedAnimation( + parent: _showPeakController, + curve: Interval(0.2, 0.3, curve: Curves.easeIn))); + + _indicatorMoveWithPeakController = AnimationController(vsync: this); + _indicatorTranslateWithPeakAnimation = Tween(begin: 0.0, end: 1.0) + .animate(CurvedAnimation( + parent: _indicatorMoveWithPeakController, + curve: Interval(0.1, 0.2, curve: Curves.easeOut))); + _indicatorRadiusWithPeakAnimation = Tween(begin: 0.0, end: 1.0) + .animate(CurvedAnimation( + parent: _indicatorMoveWithPeakController, + curve: Interval(0.1, 0.2, curve: Curves.easeOut))); + + _indicatorTranslateInOutController = AnimationController(vsync: this); + _indicatorTranslateAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _indicatorTranslateInOutController, + curve: Interval(0.2, 0.6, curve: Curves.easeOut))); + + _radiusController = AnimationController(vsync: this); + _radiusAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _radiusController, curve: Curves.easeIn)); + + _positionController = AnimationController(vsync: this); + _value = _positionController.drive(_threeQuarterTween); + + _childOpacityAnimation = _positionController.drive(_oneToZeroTween); + } + + @override + void didChangeDependencies() { + final ThemeData theme = Theme.of(context); + _valueColor = _positionController.drive( + ColorTween( + begin: (widget.color ?? theme.accentColor).withOpacity(0.0), + end: (widget.color ?? theme.accentColor).withOpacity(1.0)) + .chain(CurveTween( + curve: const Interval(0.0, 1.0 / _kDragSizeFactorLimit))), + ); + super.didChangeDependencies(); + } + + @override + void dispose() { + _springController.dispose(); + _progressingController.dispose(); + _positionController.dispose(); + _ringDisappearController.dispose(); + _showPeakController.dispose(); + _indicatorMoveWithPeakController.dispose(); + _indicatorTranslateInOutController.dispose(); + _radiusController.dispose(); + super.dispose(); + } + + bool _handleScrollNotification(ScrollNotification notification) { + if (notification is ScrollStartNotification && + notification.metrics.extentBefore == 0.0 && + _mode == null && + _start(notification.metrics.axisDirection)) { + setState(() { + _mode = _LiquidPullToRefreshMode.drag; + }); + return false; + } + bool indicatorAtTopNow; + switch (notification.metrics.axisDirection) { + case AxisDirection.down: + indicatorAtTopNow = true; + break; + case AxisDirection.up: + indicatorAtTopNow = false; + break; + case AxisDirection.left: + case AxisDirection.right: + indicatorAtTopNow = null; + break; + } + if (indicatorAtTopNow != _isIndicatorAtTop) { + if (_mode == _LiquidPullToRefreshMode.drag || + _mode == _LiquidPullToRefreshMode.armed) + _dismiss(_LiquidPullToRefreshMode.canceled); + } else if (notification is ScrollUpdateNotification) { + if (_mode == _LiquidPullToRefreshMode.drag || + _mode == _LiquidPullToRefreshMode.armed) { + if (notification.metrics.extentBefore > 0.0) { + _dismiss(_LiquidPullToRefreshMode.canceled); + } else { + if (_dragOffset != null) _dragOffset = _dragOffset - notification.scrollDelta; + _checkDragOffset(notification.metrics.viewportDimension); + } + } + if (_mode == _LiquidPullToRefreshMode.armed && + notification.dragDetails == null) { + // On iOS start the refresh when the Scrollable bounces back from the + // OverScroll (ScrollNotification indicating this don't have dragDetails + // because the scroll activity is not directly triggered by a drag). + _show(); + } + } else if (notification is OverscrollNotification) { + if (_mode == _LiquidPullToRefreshMode.drag || + _mode == _LiquidPullToRefreshMode.armed) { + if (_dragOffset != null) _dragOffset = _dragOffset - notification.overscroll / 2.0; + _checkDragOffset(notification.metrics.viewportDimension); + } + } else if (notification is ScrollEndNotification) { + switch (_mode) { + case _LiquidPullToRefreshMode.armed: + _show(); + break; + case _LiquidPullToRefreshMode.drag: + _dismiss(_LiquidPullToRefreshMode.canceled); + break; + default: + // do nothing + break; + } + } + return false; + } + + bool _handleGlowNotification(OverscrollIndicatorNotification notification) { + if (notification.depth != 0 || !notification.leading) return false; + if (_mode == _LiquidPullToRefreshMode.drag) { + notification.disallowGlow(); + return true; + } + return false; + } + + // Stop showing the progress indicator. + Future _dismiss(_LiquidPullToRefreshMode newMode) async { + await Future.value(); + // This can only be called from _show() when refreshing and + // _handleScrollNotification in response to a ScrollEndNotification or + // direction change. + assert(newMode == _LiquidPullToRefreshMode.canceled || + newMode == _LiquidPullToRefreshMode.done); + setState(() { + _mode = newMode; + }); + switch (_mode) { + case _LiquidPullToRefreshMode.done: + //stop progressing animation + _progressingController.stop(); + + // progress ring disappear animation + _ringDisappearController.animateTo(1.0, + duration: Duration( + milliseconds: (widget.springAnimationDurationInMilliseconds / + widget.animSpeedFactor) + .round()), + curve: Curves.linear); + + // indicator translate out + _indicatorMoveWithPeakController.animateTo(0.0, + duration: Duration( + milliseconds: (widget.springAnimationDurationInMilliseconds / + widget.animSpeedFactor) + .round()), + curve: Curves.linear); + _indicatorTranslateInOutController.animateTo(0.0, + duration: Duration( + milliseconds: (widget.springAnimationDurationInMilliseconds / + widget.animSpeedFactor) + .round()), + curve: Curves.linear); + + //initial value of controller is 1.0 + await _showPeakController.animateTo(0.3, + duration: Duration( + milliseconds: (widget.springAnimationDurationInMilliseconds / + widget.animSpeedFactor) + .round()), + curve: Curves.linear); + + _radiusController.animateTo(0.0, + duration: Duration( + milliseconds: (widget.springAnimationDurationInMilliseconds / + (widget.animSpeedFactor * 5)) + .round()), + curve: Curves.linear); + + _showPeakController.value = 0.175; + await _showPeakController.animateTo(0.1, + duration: Duration( + milliseconds: (widget.springAnimationDurationInMilliseconds / + (widget.animSpeedFactor * 5)) + .round()), + curve: Curves.easeOut); + _showPeakController.value = 0.0; + + await _positionController.animateTo(0.0, + duration: Duration( + milliseconds: (widget.springAnimationDurationInMilliseconds / + widget.animSpeedFactor) + .round())); + break; + + case _LiquidPullToRefreshMode.canceled: + await _positionController.animateTo(0.0, + duration: _kIndicatorScaleDuration); + break; + default: + assert(false); + } + if (mounted && _mode == newMode) { + _dragOffset = null; + _isIndicatorAtTop = null; + setState(() { + _mode = null; + }); + } + } + + bool _start(AxisDirection direction) { + assert(_mode == null); + assert(_isIndicatorAtTop == null); + assert(_dragOffset == null); + switch (direction) { + case AxisDirection.down: + _isIndicatorAtTop = true; + break; + case AxisDirection.up: + _isIndicatorAtTop = false; + break; + case AxisDirection.left: + case AxisDirection.right: + _isIndicatorAtTop = null; + // we do not support horizontal scroll views. + return false; + } + _dragOffset = 0.0; + _positionController.value = 0.0; + _springController.value = 0.0; + _progressingController.value = 0.0; + _ringDisappearController.value = 1.0; + _showPeakController.value = 0.0; + _indicatorMoveWithPeakController.value = 0.0; + _indicatorTranslateInOutController.value = 0.0; + _radiusController.value = 1.0; + return true; + } + + void _checkDragOffset(double containerExtent) { + assert(_mode == _LiquidPullToRefreshMode.drag || + _mode == _LiquidPullToRefreshMode.armed); + double newValue = + _dragOffset / (containerExtent * _kDragContainerExtentPercentage); + if (_mode == _LiquidPullToRefreshMode.armed) + newValue = math.max(newValue, 1.0 / _kDragSizeFactorLimit); + _positionController.value = + newValue.clamp(0.0, 1.0); // this triggers various rebuilds + if (_mode == _LiquidPullToRefreshMode.drag && + _valueColor.value.alpha == 0xFF) _mode = _LiquidPullToRefreshMode.armed; + } + + void _show() { + assert(_mode != _LiquidPullToRefreshMode.refresh); + assert(_mode != _LiquidPullToRefreshMode.snap); + final Completer completer = Completer(); + _pendingRefreshFuture = completer.future; + _mode = _LiquidPullToRefreshMode.snap; + + _positionController.animateTo(1.0 / _kDragSizeFactorLimit, + duration: Duration( + milliseconds: widget.springAnimationDurationInMilliseconds), + curve: Curves.linear); + + _showPeakController.animateTo(1.0, + duration: Duration( + milliseconds: widget.springAnimationDurationInMilliseconds), + curve: Curves.linear); + + //indicator translate in with peak + _indicatorMoveWithPeakController.animateTo(1.0, + duration: Duration( + milliseconds: widget.springAnimationDurationInMilliseconds), + curve: Curves.linear); + + //indicator move to center + _indicatorTranslateInOutController.animateTo(1.0, + duration: Duration( + milliseconds: widget.springAnimationDurationInMilliseconds), + curve: Curves.linear); + + // progress ring fade in + _ringDisappearController.animateTo(0.0, + duration: Duration( + milliseconds: widget.springAnimationDurationInMilliseconds)); + + _springController + .animateTo(0.5, + duration: Duration( + milliseconds: widget.springAnimationDurationInMilliseconds), + curve: Curves.elasticOut) + .then((void value) { + if (mounted && _mode == _LiquidPullToRefreshMode.snap) { + assert(widget.onRefresh != null); + + setState(() { + // Show the indeterminate progress indicator. + _mode = _LiquidPullToRefreshMode.refresh; + }); + + //run progress animation + _progressingController..repeat(); + + final Future refreshResult = widget.onRefresh(); + assert(() { + if (refreshResult == null) { + // See https://github.com/flutter/flutter/issues/31962#issuecomment-488882515 + // Delete this code when the new context update reaches stable versions of Flutter. + final bool _useDiagnosticsNode = + FlutterError('text') is Diagnosticable; + + dynamic safeContext(String context) { + return _useDiagnosticsNode + ? DiagnosticsNode.message(context) + : context; + } + + FlutterError.reportError(FlutterErrorDetails( + exception: FlutterError('The onRefresh callback returned null.\n' + 'The LiquidPullToRefresh onRefresh callback must return a Future.'), + context: safeContext('when calling onRefresh'), + library: 'LiquidPullToRefresh library', + )); + } + return true; + }()); + + if (refreshResult == null) return; + + refreshResult.whenComplete(() { + if (mounted && _mode == _LiquidPullToRefreshMode.refresh) { + completer.complete(); + + _dismiss(_LiquidPullToRefreshMode.done); + } + }); + } + }); + } + + /// Show the progress indicator and run the refresh callback as if it had + /// been started interactively. If this method is called while the refresh + /// callback is running, it quietly does nothing. + /// + /// Creating the [LiquidPullToRefresh] with a [GlobalKey] + /// makes it possible to refer to the [LiquidPullToRefreshState]. + /// + /// The future returned from this method completes when the + /// [LiquidPullToRefresh.onRefresh] callback's future completes. + /// + /// If you await the future returned by this function from a [State], you + /// should check that the state is still [mounted] before calling [setState]. + /// + /// When initiated in this manner, the progress indicator is independent of any + /// actual scroll view. It defaults to showing the indicator at the top. To + /// show it at the bottom, set `atTop` to false. + Future show({bool atTop = true}) { + if (_mode != _LiquidPullToRefreshMode.refresh && + _mode != _LiquidPullToRefreshMode.snap) { + if (_mode == null) _start(atTop ? AxisDirection.down : AxisDirection.up); + _show(); + } + return _pendingRefreshFuture; + } + + final GlobalKey _key = GlobalKey(); + + @override + Widget build(BuildContext context) { + assert(debugCheckHasMaterialLocalizations(context)); + + // assigning default color and background color + Color _defaultColor = Theme.of(context).accentColor; + Color _defaultBackgroundColor = Theme.of(context).canvasColor; + + // assigning default height + double _defaultHeight = 100.0; + + // checking whether to take default values or not + Color color = (widget.color != null) ? widget.color : _defaultColor; + Color backgroundColor = (widget.backgroundColor != null) + ? widget.backgroundColor + : _defaultBackgroundColor; + double height = (widget.height != null) ? widget.height : _defaultHeight; + + //Code Added for testing +// slivers.insert( +// 0, +// SliverToBoxAdapter( +// child: ClipPath( +// clipper: HillClipper( +// centreHeight: 100, +// curveHeight: 50.0, +// peakHeight: 30.0, +// peakWidth: 15.0 * 5 / 2, +// ), +// child: Container( +// height: 100.0, +// color: Colors.yellow, +// child: Align( +// alignment: Alignment(0.0, 1.0), +// child: Opacity( +// opacity: 1.0, +// child: CircularProgress( +// progressCircleOpacity: 1.0, +// innerCircleRadius: 15.0, +// progressCircleBorderWidth: 0.0, +// progressCircleRadius: 0.0, +// progressPercent: 0.5, +// ), +// ), +// ), +// ), +// ), +// ), +// ); + + final Widget child = NotificationListener( + key: _key, + onNotification: _handleScrollNotification, + child: NotificationListener( + onNotification: _handleGlowNotification, child: widget.child), + ); + + if (_mode == null) { + assert(_dragOffset == null); + assert(_isIndicatorAtTop == null); + return child; + } + assert(_dragOffset != null); + assert(_isIndicatorAtTop != null); + + return Stack( + children: [ + AnimatedBuilder( + animation: _positionController, + child: child, + builder: (BuildContext buildContext, Widget child) { + if (widget.showChildOpacityTransition) { + return Opacity( + // -0.01 is done for elasticOut curve + opacity: (widget.showChildOpacityTransition) + ? (_childOpacityAnimation.value - (1 / 3) - 0.01) + .clamp(0.0, 1.0) + : 1.0, + child: child); + } + return Transform.translate( + offset: new Offset(0.0, _positionController.value * height * 1.5), + child: child, + ); + }, + ), + AnimatedBuilder( + animation: Listenable.merge([ + _positionController, + _springController, + _showPeakController, + ]), + builder: (BuildContext buildContext, Widget child) { + return ClipPath( + clipper: CurveHillClipper( + centreHeight: height, + curveHeight: height / 2 * _springAnimation.value, // 50.0 + peakHeight: height * + 3 / + 10 * + ((_peakHeightUpAnimation.value != 1.0) //30.0 + ? _peakHeightUpAnimation.value + : _peakHeightDownAnimation.value), + peakWidth: (_peakHeightUpAnimation.value != 0.0 && + _peakHeightDownAnimation.value != 0.0) + ? height * 35 / 100 //35.0 + : 0.0, + ), + child: Container( + height: _value.value * height * 2, // 100.0 + color: color, + ), + ); + }, + ), + Container( + height: height, //100.0 + child: AnimatedBuilder( + animation: Listenable.merge([ + _progressingController, + _ringDisappearController, + _indicatorMoveWithPeakController, + _indicatorTranslateInOutController, + _radiusController, + ]), + builder: (BuildContext buildContext, Widget child) { + return Align( + alignment: Alignment( + 0.0, + (1.0 - + (0.36 * _indicatorTranslateWithPeakAnimation.value) - + (0.64 * _indicatorTranslateAnimation.value)), + ), + child: Transform( + transform: Matrix4.identity() + ..rotateZ(_progressingRotateAnimation.value * 5 * pi / 6), + alignment: FractionalOffset.center, + child: CircularProgress( + backgroundColor: backgroundColor, + progressCircleOpacity: _ringOpacityAnimation.value, + innerCircleRadius: height * + 15 / + 100 * // 15.0 + ((_mode != _LiquidPullToRefreshMode.done) + ? _indicatorRadiusWithPeakAnimation.value + : _radiusAnimation.value), + progressCircleBorderWidth: widget.borderWidth, + //2.0 + progressCircleRadius: (_ringOpacityAnimation.value != 0.0) + ? (height * 2 / 10) * _ringRadiusAnimation.value //20.0 + : 0.0, + startAngle: _progressingStartAngleAnimation.value * pi, + progressPercent: _progressingPercentAnimation.value, + ), + ), + ); + }, + ), + ), + ], + ); + } +} + +class ProgressRingCurve extends Curve { + @override + double transform(double t) { + if (t <= 0.5) { + return 2 * t; + } else { + return 2 * (1 - t); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/src/circular_progress.dart b/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/src/circular_progress.dart new file mode 100644 index 00000000..daac7b07 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/src/circular_progress.dart @@ -0,0 +1,126 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +/// Progress Indicator for [LiquidPullToRefresh] +class CircularProgress extends StatefulWidget { + final double innerCircleRadius; + final double progressPercent; + final double progressCircleOpacity; + final double progressCircleRadius; + final double progressCircleBorderWidth; + final Color backgroundColor; + final double startAngle; + + const CircularProgress({ + Key key, + @required this.innerCircleRadius, + @required this.progressPercent, + @required this.progressCircleRadius, + @required this.progressCircleBorderWidth, + @required this.backgroundColor, + @required this.progressCircleOpacity, + @required this.startAngle, + }) : super(key: key); + + @override + _CircularProgressState createState() => _CircularProgressState(); +} + +class _CircularProgressState extends State { + @override + Widget build(BuildContext context) { + double containerLength = + 2 * max(widget.progressCircleRadius, widget.innerCircleRadius); + + return Container( + height: containerLength, + width: containerLength, + child: Stack( + children: [ + Opacity( + opacity: widget.progressCircleOpacity, + child: Container( + height: widget.progressCircleRadius * 2, + width: widget.progressCircleRadius * 2, + child: CustomPaint( + painter: RingPainter( + startAngle: widget.startAngle, + paintWidth: widget.progressCircleBorderWidth, + progressPercent: widget.progressPercent, + trackColor: widget.backgroundColor, + ), + ), + ), + ), + Align( + alignment: Alignment.center, + child: Container( + width: widget.innerCircleRadius * 2, + height: widget.innerCircleRadius * 2, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: widget.backgroundColor, + ), + ), + ) + ], + ), + ); + } +} + +class CircularProgressIndicator extends StatefulWidget { + @override + _CircularProgressIndicatorState createState() => + _CircularProgressIndicatorState(); +} + +class _CircularProgressIndicatorState extends State { + @override + Widget build(BuildContext context) { + return Container(); + } +} + +class RingPainter extends CustomPainter { + final double paintWidth; + final Paint trackPaint; + final Color trackColor; + final double progressPercent; + final double startAngle; + + RingPainter({ + @required this.startAngle, + @required this.paintWidth, + @required this.progressPercent, + @required this.trackColor, + }) : trackPaint = Paint() + ..color = trackColor + ..style = PaintingStyle.stroke + ..strokeWidth = paintWidth + ..strokeCap = StrokeCap.square; + + @override + void paint(Canvas canvas, Size size) { + final center = Offset(size.width / 2, size.height / 2); + final radius = (min(size.width, size.height) - paintWidth) / 2; + + final progressAngle = 2 * pi * progressPercent; + + canvas.drawArc( + Rect.fromCircle( + center: center, + radius: radius, + ), + startAngle, + progressAngle, + false, + trackPaint); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/src/clipper.dart b/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/src/clipper.dart new file mode 100644 index 00000000..58329abc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/lib/src/clipper.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; + +/// Clipper for [LiquidPullToRefresh] +class CurveHillClipper extends CustomClipper { + final double centreHeight; + double curveHeight; + final double peakHeight; + final double peakWidth; + + CurveHillClipper({ + @required this.centreHeight, + @required this.curveHeight, + @required this.peakHeight, + @required this.peakWidth, + }); + + @override + Path getClip(Size size) { + var path = new Path(); + if (peakHeight == null && peakWidth == null) { + if (size.height > centreHeight) { + if (curveHeight > (size.height - centreHeight)) { + curveHeight = size.height - centreHeight; + } + + path.lineTo(0.0, centreHeight); + + path.quadraticBezierTo(size.width / 4, centreHeight + curveHeight, + size.width / 2, centreHeight + curveHeight); + + path.quadraticBezierTo(size.width * 3 / 4, centreHeight + curveHeight, + size.width, centreHeight); + + path.lineTo(size.width, 0.0); + + path.lineTo(0.0, 0.0); + } else { + path.lineTo(0.0, size.height); + path.lineTo(size.width, size.height); + path.lineTo(size.width, 0.0); + path.lineTo(0.0, 0.0); + } + } else { + if (size.height >= centreHeight) { + if (curveHeight > (size.height - centreHeight)) { + curveHeight = size.height - centreHeight; + } + + path.lineTo(0.0, centreHeight); + + path.quadraticBezierTo(size.width / 4, centreHeight + curveHeight, + (size.width / 2) - (peakWidth / 2), centreHeight + curveHeight); + + path.quadraticBezierTo( + (size.width / 2) - (peakWidth / 4), + centreHeight + curveHeight - peakHeight, + (size.width / 2), + centreHeight + curveHeight - peakHeight); + + path.quadraticBezierTo( + (size.width / 2) + (peakWidth / 4), + centreHeight + curveHeight - peakHeight, + (size.width / 2) + (peakWidth / 2), + centreHeight + curveHeight); + + path.quadraticBezierTo(size.width * 3 / 4, centreHeight + curveHeight, + size.width, centreHeight); + + path.lineTo(size.width, 0.0); + + path.lineTo(0.0, 0.0); + } else { + path.lineTo(0.0, size.height); + path.lineTo(size.width, size.height); + path.lineTo(size.width, 0.0); + path.lineTo(0.0, 0.0); + } + } + + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) => true; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/main.dart b/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/main.dart new file mode 100644 index 00000000..25d38053 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/liquid_pull_to_refresh/main.dart @@ -0,0 +1,125 @@ +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter/material.dart'; + +import 'lib/liquid_pull_to_refresh.dart'; + +void main() => runApp(LiquidPullToRefreshApp()); + +class LiquidPullToRefreshApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + debugShowCheckedModeBanner: false, + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyHomePage(title: 'Liquid Pull To Refresh'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + final GlobalKey _refreshIndicatorKey = + GlobalKey(); + + static int refreshNum = 10; // number that changes when refreshed + Stream counterStream = + Stream.periodic(Duration(seconds: 3), (x) => refreshNum); + + ScrollController _scrollController; + + @override + void initState() { + super.initState(); + _scrollController = new ScrollController(); + } + + static final List _items = [ + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N' + ]; + + Future _handleRefresh() { + final Completer completer = Completer(); + Timer(const Duration(seconds: 3), () { + completer.complete(); + }); + setState(() { + refreshNum = new Random().nextInt(100); + }); + return completer.future.then((_) { + _scaffoldKey.currentState?.showSnackBar(SnackBar( + content: const Text('Refresh complete'), + action: SnackBarAction( + label: 'RETRY', + onPressed: () { + _refreshIndicatorKey.currentState.show(); + }))); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: AppBar( + title: Stack( + children: [ + Align(alignment: Alignment(-1.0, 0.0), child: Icon(Icons.reorder)), + Align(alignment: Alignment(-0.3, 0.0), child: Text(widget.title)), + ], + ), + ), + body: LiquidPullToRefresh( + key: _refreshIndicatorKey, + onRefresh: _handleRefresh, + showChildOpacityTransition: false, + child: StreamBuilder( + stream: counterStream, + builder: (context, snapshot) { + return ListView.builder( + padding: kMaterialListPadding, + itemCount: _items.length, + controller: _scrollController, + itemBuilder: (BuildContext context, int index) { + final String item = _items[index]; + return ListTile( + isThreeLine: true, + leading: CircleAvatar(child: Text(item)), + title: Text('This item represents $item.'), + subtitle: Text( + 'Even more additional list item information appears on line three. ${snapshot.data}'), + ); + }, + ); + }), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/main.dart b/FlutterHelper/flutter_helper/lib/samples/main.dart new file mode 100644 index 00000000..e3ce7e0a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/main.dart @@ -0,0 +1,270 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/animated_selection_slide/lib/main.dart'; +import 'package:flutter_helper/boss/boss_app.dart'; +import 'package:flutter_helper/boss/utils.dart'; +import 'package:flutter_helper/flutter_tags/main.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/other/other_app.dart'; +import 'package:flutter_helper/samples/beautiful_popup/main.dart'; +import 'package:flutter_helper/samples/card_settings/main.dart'; +import 'package:flutter_helper/samples/credit_card_input_form/main.dart'; +import 'package:flutter_helper/samples/direct_select_flutter/main.dart'; +import 'package:flutter_helper/samples/fb_reaction_box/main.dart'; +import 'package:flutter_helper/samples/flip_panel/main.dart'; +import 'package:flutter_helper/samples/flushbar/main.dart'; +import 'package:flutter_helper/samples/flutter_image_sequence_animator/main.dart'; +import 'package:flutter_helper/samples/flutter_neumorphic/main.dart'; +import 'package:flutter_helper/samples/folding_cell/demos/demos_new.dart'; +import 'package:flutter_helper/samples/liquid_pull_to_refresh/main.dart'; +import 'package:flutter_helper/samples/pin_code_text_field/main.dart'; +import 'package:flutter_helper/samples/radial_menu/demo.dart'; +import 'package:flutter_helper/samples/samples_1.dart'; +import 'package:flutter_helper/samples/scatcher/main.dart'; +import 'package:flutter_helper/samples/snaplist/main.dart'; +import 'package:flutter_helper/samples/staggerd/main.dart'; +import 'package:flutter_helper/samples/step_touch/main.dart'; +import 'package:flutter_helper/samples/table_calendar/main.dart'; +import 'package:flutter_helper/samples/table_planner/main.dart'; +import 'package:flutter_helper/samples/timeline_tile/main.dart'; +import 'package:flutter_helper/samples/timelines/main.dart'; +import 'package:flutter_helper/samples/tinder_cards/main.dart'; +import 'package:flutter_helper/samples/typeahed/cupertino_app.dart'; +import 'package:flutter_helper/samples/typeahed/material_app.dart'; +import 'package:flutter_helper/trip/trip_app.dart'; +import 'package:flutter_helper/ui_helpers/flutter_offline/main.dart'; +import 'package:flutter_helper/ui_helpers/flutter_showcaseview/main.dart'; +import 'package:flutter_helper/ui_helpers/scroll_to_index/main.dart'; +import 'package:flutter_helper/utils/util_log.dart'; +import 'package:flutter_helper/widgets/widgets_page.dart'; +import 'package:flutter_helper/widgets2/search_appbar.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'before_after/main.dart'; +import 'dough/main.dart'; +import 'flutter_calendar/main.dart'; +import 'flutter_calendar_carousel/main.dart'; +void main() { + LogUtil.init(isDebug: true); + + runApp(SamplesApp()); +} + +class SamplesApp extends StatefulWidget { + @override + _SamplesAppState createState() => _SamplesAppState(); +} + +class _SamplesAppState extends State { + + var _simpleItem = false; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: Scaffold( + appBar: _searchAppBarWidget, + // appBar: AppBar( + // title: Text("Flutter"), + // actions: [ + // IconButton( + // onPressed: () { + // setState(() { + // _simpleItem = !_simpleItem; + // }); + // }, + // icon: Icon(Icons.swap_calls)), + // ], + // ), + body: Column( + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(right: 30), + child: + _simpleItem ? _buildSImpleGridView(context) : _buildGrid(), + ), + ), + ], + ), + ), + ); + } + + List _mwidgets = [ + FlutterOfflineApp(), + ScrollToIndexApp(), + ShowCaseApp(), + CalendarApp(), + CalendarCarouselApp(), + TablePlanneryApp(), + TableCanlendarApp(), + TimelineTileApp(), + TimeLinesApp(), + CardSettingsApp(), + DoughApp(), + FlutterNeumorphicApp(), + FlutterTagsApp(), + AnimatedSelectionSlideApp(), + CreditCardInputFormApp(), + BeautifulPopupApp(), + ImageSequenceAnimatorApp(), + ScatcherApp(), + BeforeAfterApp(), + LiquidPullToRefreshApp(), + DirectSelectFlutterApp(), + FoldingCellSimpleDemo(), + PinCodeTextFieldApp(), + SnapListApp(), + TypeAheadMaterialApp(), + TypeAheadCupertinoApp(), + StepTouchApp(), + YourAwesomeApp(), + FbReactionBoxApp(), + FlipPanelApp(), + TinderCardsApp(), + GridViewCount(), + ListViewHorizontal(), + StaggerApp(), + RadialMenuApp(), + ]; + + ScrollController _scrollController = ScrollController(); + + var _listDisplay ; + FocusNode _focusNode = new FocusNode(); + TextEditingController _controller = TextEditingController(); + + PreferredSizeWidget get _searchAppBarWidget => SearchAppBarWidget( + focusNode: _focusNode, + controller: _controller, + elevation: 2.0, + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Icon(Icons.arrow_back), + ), + inputFormatters: [LengthLimitingTextInputFormatter(50)], + onChangedCallback: (str) { + if(str.isNotEmpty) { + setState(() { + // double _items.clear() + LogUtil.e('onChangeCallBack -> $str'); + var tmp = _mwidgets + .where((e) => + e.toStringShort().toLowerCase().contains(str.toLowerCase())) + .toList(); + _listDisplay = tmp; + }); + } else { + setState(() { + _listDisplay = null; + }); + } + }, + onEditingComplete: () { + showToast('onEditingComplete!'); + setState(() { + _listDisplay = null; + }); + }, + ); + + + + _buildSImpleGridView(BuildContext context) { + if(_listDisplay == null) { + _listDisplay = _mwidgets; + } + return GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, //每行三列 + childAspectRatio: 1.0 //显示区域宽高相等 + ), + itemCount: _listDisplay.length, + itemBuilder: (context, index) { + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) { + return _listDisplay[index]; + }), + ); + }, + child: Text("${_listDisplay[index].toStringShort()}"), + ); + }, + ); + } + + _buildGrid() { + return StaggeredGridView.countBuilder( + controller: _scrollController, + crossAxisCount: 4, + itemCount: _mwidgets.length, + itemBuilder: _builtItem, + staggeredTileBuilder: (int index) => new StaggeredTile.fit(2), + ); + } + + Widget _builtItem(BuildContext context, int index) { + Widget w = _mwidgets[index]; + High high; + if (w is HighMixin) { + high = (w as HighMixin).getHigh(); + } else { + high = High(w.toStringShort(), "没有实现minxin"); + } + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) { + return w; + }), + ); + }, + child: Card( + color: Colors.transparent, + child: Container( + color: Colors.white, + width: 20, + height: 280, + child: Column( + children: [ + Text(high.title), + SizedBox(height: 5), + ConstrainedBox( + constraints: BoxConstraints( + // maxWidth: 150, + maxHeight: 250, + ), + child: w, + ), + ], + ), + ), + ), + ); + } +} + +class AppData { + final String name; + final String imageUrl; + final Widget app; + + AppData({ + Key key, + this.app, + this.imageUrl = 'images/bossapp2x.png', + this.name = "app", + }); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/pin_code_text_field/main.dart b/FlutterHelper/flutter_helper/lib/samples/pin_code_text_field/main.dart new file mode 100644 index 00000000..24c3ed6e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/pin_code_text_field/main.dart @@ -0,0 +1,405 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import './pin_code_text_field.dart'; + +const String MATERIAL_SCREEN = "/material_screen"; +const String CUPERTINO_SCREEN = "/cupertino_screen"; + +void main() => runApp(new PinCodeTextFieldApp()); + +class PinCodeTextFieldApp extends StatelessWidget { + bool isMaterial = true; + + MaterialPageRoute _buildRoute(RouteSettings settings, Widget builder) { + return new MaterialPageRoute( + settings: settings, + builder: (ctx) => builder, + ); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( +// home: MainApp(), +// initialRoute: '/', + routes: { + MATERIAL_SCREEN: (context) => MyApp( + isMaterial: true, + ), + CUPERTINO_SCREEN: (context) => MyApp( + isMaterial: false, + ), + }, + home: MainApp(), + ); + } +} + +class MainApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + // double: implement build + return Scaffold( + appBar: AppBar(), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Container( + child: Column( + children: [ + RaisedButton( + child: Text("Material"), + onPressed: () { + Navigator.pushNamed(context, MATERIAL_SCREEN); + }, + ), + if (!kIsWeb) + RaisedButton( + child: Text("Cupertino"), + onPressed: () { + Navigator.of(context).pushNamed(CUPERTINO_SCREEN); + }, + ) + ], + ), + ), + ), + ); + } +} + +class MyApp extends StatefulWidget { + // This widget is the root of your application. + final bool isMaterial; + + const MyApp({Key key, this.isMaterial}) : super(key: key); + + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + TextEditingController controller = TextEditingController(text: ""); + String thisText = ""; + int pinLength = 4; + bool hasError = false; + String errorMessage; + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.isMaterial + ? new MaterialApp( + title: "Flutter Demo", + home: materialPin(), + theme: ThemeData( + inputDecorationTheme: InputDecorationTheme( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Color(0xFF9FA0A5), + ), + ), + ), + ), + ) + : new CupertinoApp( + title: 'Flutter Demo', + theme: CupertinoThemeData(), + home: cupertinoPin(), + ); + } + + Scaffold materialPin() { + return Scaffold( + appBar: AppBar( + title: Text("Material Pin Code Text Field Example"), + ), + body: Container( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, +// crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 60.0), + child: Text(thisText, style: Theme.of(context).textTheme.title), + ), + Container( + height: 100.0, + child: GestureDetector( + onLongPress: () { + print("LONG"); + showDialog( + context: context, + builder: (context) { + return AlertDialog( + content: + Text("Paste clipboard stuff into the pinbox?"), + actions: [ + FlatButton( + onPressed: () async { + var copiedText = + await Clipboard.getData("text/plain"); + if (copiedText.text.isNotEmpty) { + controller.text = copiedText.text; + } + Navigator.of(context).pop(); + }, + child: Text("YES")), + FlatButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text("No")) + ], + ); + }); + }, + child: PinCodeTextField( + autofocus: true, + controller: controller, + hideCharacter: true, + highlight: true, + highlightColor: Colors.blue, + defaultBorderColor: Colors.black, + hasTextBorderColor: Colors.green, + maxLength: pinLength, + hasError: hasError, + maskCharacter: "😎", + onTextChanged: (text) { + setState(() { + hasError = false; + }); + }, + onDone: (text) { + print("DONE $text"); + print("DONE CONTROLLER ${controller.text}"); + }, + pinBoxWidth: 50, + pinBoxHeight: 64, + hasUnderline: true, + wrapAlignment: WrapAlignment.spaceAround, + pinBoxDecoration: + ProvidedPinBoxDecoration.defaultPinBoxDecoration, + pinTextStyle: TextStyle(fontSize: 22.0), + pinTextAnimatedSwitcherTransition: + ProvidedPinBoxTextAnimation.scalingTransition, +// pinBoxColor: Colors.green[100], + pinTextAnimatedSwitcherDuration: + Duration(milliseconds: 300), +// highlightAnimation: true, + highlightAnimationBeginColor: Colors.black, + highlightAnimationEndColor: Colors.white12, + keyboardType: TextInputType.number, + ), + ), + ), + Visibility( + child: Text( + "Wrong PIN!", + ), + visible: hasError, + ), + Padding( + padding: const EdgeInsets.only(top: 32.0), + child: Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + if (!kIsWeb) + MaterialButton( + color: Colors.blue, + textColor: Colors.white, + child: Text("Copy 1234 to Clipboard"), + onPressed: () { + setState(() { + Clipboard.setData(ClipboardData(text: "1111")); + }); + }, + ), + MaterialButton( + color: Colors.blue, + textColor: Colors.white, + child: Text("+"), + onPressed: () { + setState(() { + this.pinLength++; + }); + }, + ), + MaterialButton( + color: Colors.blue, + textColor: Colors.white, + child: Text("-"), + onPressed: () { + setState(() { + this.pinLength--; + }); + }, + ), + MaterialButton( + color: Colors.blue, + textColor: Colors.white, + child: Text("SUBMIT"), + onPressed: () { + setState(() { + this.thisText = controller.text; + }); + }, + ), + MaterialButton( + color: Colors.red, + textColor: Colors.white, + child: Text("SUBMIT Error"), + onPressed: () { + setState(() { + this.hasError = true; + }); + }, + ), + MaterialButton( + color: Colors.pink, + textColor: Colors.white, + child: Text("CLEAR PIN"), + onPressed: () { + controller.clear(); + }, + ), + MaterialButton( + color: Colors.lime, + textColor: Colors.black, + child: Text("SET TO 456"), + onPressed: () { + controller.text = "456"; + }, + ), + ], + ), + ) + ], + ), + ), + ), + ); + } + + CupertinoPageScaffold cupertinoPin() { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text("Cupertino Pin Code Text Field Example"), + ), + child: SafeArea( + child: Container( + child: SingleChildScrollView( + child: Container( + color: Colors.blue, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 60.0), + child: Text(thisText), + ), + PinCodeTextField( + autofocus: false, + controller: controller, + hideCharacter: true, + highlight: true, + highlightColor: CupertinoColors.activeBlue, + defaultBorderColor: CupertinoColors.black, + hasTextBorderColor: CupertinoColors.activeGreen, + maxLength: pinLength, + hasError: hasError, + maskCharacter: "🐶", + onTextChanged: (text) { + setState(() { + hasError = false; + thisText = text; + }); + }, + isCupertino: true, + onDone: (text) { + print("DONE $text"); + }, + wrapAlignment: WrapAlignment.end, + pinBoxDecoration: + ProvidedPinBoxDecoration.roundedPinBoxDecoration, + pinTextStyle: TextStyle(fontSize: 30.0), + pinTextAnimatedSwitcherTransition: + ProvidedPinBoxTextAnimation.scalingTransition, + pinTextAnimatedSwitcherDuration: + Duration(milliseconds: 300), + highlightAnimation: true, + highlightAnimationBeginColor: Colors.black, + highlightAnimationEndColor: Colors.white12, + ), + Visibility( + child: Text( + "Wrong PIN!", + style: TextStyle(color: CupertinoColors.destructiveRed), + ), + visible: hasError, + ), + Padding( + padding: const EdgeInsets.only(top: 32.0), + child: Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + CupertinoButton( +// color: Colors.blue, +// textColor: Colors.white, + child: Text("+"), + onPressed: () { + setState(() { + this.pinLength++; + }); + }, + ), + CupertinoButton( +// color: Colors.blue, +// textColor: Colors.white, + child: Text("-"), + onPressed: () { + setState(() { + this.pinLength--; + }); + }, + ), + CupertinoButton( +// color: Colors.blue, +// textColor: Colors.white, + child: Text("SUBMIT"), + onPressed: () { + setState(() { + this.thisText = controller.text; + }); + }, + ), + CupertinoButton( +// color: Colors.red, +// textColor: Colors.white, + child: Text("SUBMIT Error"), + onPressed: () { + setState(() { + this.hasError = true; + }); + }, + ) + ], + ), + ) + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/pin_code_text_field/pin_code_text_field.dart b/FlutterHelper/flutter_helper/lib/samples/pin_code_text_field/pin_code_text_field.dart new file mode 100644 index 00000000..cb72e598 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/pin_code_text_field/pin_code_text_field.dart @@ -0,0 +1,603 @@ +import 'dart:async'; + +import 'package:flutter/animation.dart'; +import 'package:flutter/cupertino.dart' show CupertinoTextField; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; + +typedef OnDone = void Function(String text); +typedef PinBoxDecoration = BoxDecoration Function( + Color borderColor, + Color pinBoxColor, { + double borderWidth, + double radius, + }); + +/// class to provide some standard PinBoxDecoration such as standard box or underlined +class ProvidedPinBoxDecoration { + /// Default BoxDecoration + static PinBoxDecoration defaultPinBoxDecoration = (Color borderColor, + Color pinBoxColor, { + double borderWidth = 2.0, + double radius = 5.0, + }) { + return BoxDecoration( + border: Border.all( + color: borderColor, + width: borderWidth, + ), + color: pinBoxColor, + borderRadius: BorderRadius.circular(radius)); + }; + + /// Underlined BoxDecoration + static PinBoxDecoration underlinedPinBoxDecoration = (Color borderColor, + Color pinBoxColor, { + double borderWidth = 2.0, + double radius, + }) { + return BoxDecoration( + border: Border( + bottom: BorderSide( + color: borderColor, + width: borderWidth, + ), + ), + ); + }; + + static PinBoxDecoration roundedPinBoxDecoration = (Color borderColor, + Color pinBoxColor, { + double borderWidth = 2.0, + double radius, + }) { + return BoxDecoration( + border: Border.all( + color: borderColor, + width: borderWidth, + ), + shape: BoxShape.circle, + color: pinBoxColor, + ); + }; +} + +class ProvidedPinBoxTextAnimation { + /// A combination of RotationTransition, DefaultTextStyleTransition, ScaleTransition + static AnimatedSwitcherTransitionBuilder awesomeTransition = + (Widget child, Animation animation) { + return RotationTransition( + child: DefaultTextStyleTransition( + style: TextStyleTween( + begin: TextStyle(color: Colors.pink), + end: TextStyle(color: Colors.blue)) + .animate(animation), + child: ScaleTransition( + child: child, + scale: animation, + ), + ), + turns: animation); + }; + + /// Simple Scaling Transition + static AnimatedSwitcherTransitionBuilder scalingTransition = + (child, animation) { + return ScaleTransition( + child: child, + scale: animation, + ); + }; + + /// No transition + static AnimatedSwitcherTransitionBuilder defaultNoTransition = + (Widget child, Animation animation) { + return child; + }; + + /// Rotate Transition + static AnimatedSwitcherTransitionBuilder rotateTransition = + (Widget child, Animation animation) { + return RotationTransition(child: child, turns: animation); + }; +} + +class PinCodeTextField extends StatefulWidget { + final bool isCupertino; + final int maxLength; + final TextEditingController controller; + final bool hideCharacter; + final bool highlight; + final bool highlightAnimation; + final Color highlightAnimationBeginColor; + final Color highlightAnimationEndColor; + final Duration highlightAnimationDuration; + final Color highlightColor; + final Color defaultBorderColor; + final Color pinBoxColor; + final Color highlightPinBoxColor; + final double pinBoxBorderWidth; + final double pinBoxRadius; + final bool hideDefaultKeyboard; + final PinBoxDecoration pinBoxDecoration; + final String maskCharacter; + final TextStyle pinTextStyle; + final double pinBoxHeight; + final double pinBoxWidth; + final OnDone onDone; + final bool hasError; + final Color errorBorderColor; + final Color hasTextBorderColor; + final Function(String) onTextChanged; + final bool autofocus; + final FocusNode focusNode; + final AnimatedSwitcherTransitionBuilder pinTextAnimatedSwitcherTransition; + final Duration pinTextAnimatedSwitcherDuration; + final WrapAlignment wrapAlignment; + final TextDirection textDirection; + final TextInputType keyboardType; + final EdgeInsets pinBoxOuterPadding; + final bool hasUnderline; + + const PinCodeTextField({ + Key key, + this.isCupertino: false, + this.maxLength: 4, + this.controller, + this.hideCharacter: false, + this.highlight: false, + this.highlightAnimation: false, + this.highlightAnimationBeginColor: Colors.white, + this.highlightAnimationEndColor: Colors.black, + this.highlightAnimationDuration, + this.highlightColor: Colors.black, + this.pinBoxDecoration, + this.maskCharacter: "\u25CF", + this.pinBoxWidth: 70.0, + this.pinBoxHeight: 70.0, + this.pinTextStyle, + this.onDone, + this.defaultBorderColor: Colors.black, + this.hasTextBorderColor: Colors.black, + this.pinTextAnimatedSwitcherTransition, + this.pinTextAnimatedSwitcherDuration: const Duration(), + this.hasError: false, + this.errorBorderColor: Colors.red, + this.onTextChanged, + this.autofocus: false, + this.focusNode, + this.wrapAlignment: WrapAlignment.start, + this.textDirection: TextDirection.ltr, + this.keyboardType: TextInputType.number, + this.pinBoxOuterPadding = const EdgeInsets.symmetric(horizontal: 4.0), + this.pinBoxColor, + this.highlightPinBoxColor, + this.pinBoxBorderWidth = 2.0, + this.pinBoxRadius = 0, + this.hideDefaultKeyboard = false, + this.hasUnderline = false, + }) : super(key: key); + + @override + State createState() { + return PinCodeTextFieldState(); + } +} + +class PinCodeTextFieldState extends State + with SingleTickerProviderStateMixin { + AnimationController _highlightAnimationController; + Animation _highlightAnimationColorTween; + FocusNode focusNode; + String text = ""; + int currentIndex = 0; + List strList = []; + bool hasFocus = false; + double screenWidth; + + @override + void didUpdateWidget(PinCodeTextField oldWidget) { + super.didUpdateWidget(oldWidget); + focusNode = widget.focusNode ?? focusNode; + + if (oldWidget.maxLength < widget.maxLength) { + setState(() { + currentIndex = text.length; + }); + widget.controller?.text = text; + widget.controller?.selection = + TextSelection.collapsed(offset: text.length); + } else if (oldWidget.maxLength > widget.maxLength && + widget.maxLength > 0 && + text.length > 0 && + text.length > widget.maxLength) { + setState(() { + text = text.substring(0, widget.maxLength); + currentIndex = text.length; + }); + widget.controller?.text = text; + widget.controller?.selection = + TextSelection.collapsed(offset: text.length); + } + } + + _calculateStrList() async { + if (strList.length > widget.maxLength) { + strList.length = widget.maxLength; + } + while (strList.length < widget.maxLength) { + strList.add(""); + } + } + + @override + void initState() { + super.initState(); + if (widget.highlightAnimation) { + _highlightAnimationController = AnimationController( + vsync: this, + duration: + widget.highlightAnimationDuration ?? Duration(milliseconds: 500)); + _highlightAnimationController.addStatusListener((status) { + if (status == AnimationStatus.completed) { + _highlightAnimationController.reverse(); + } else if (status == AnimationStatus.dismissed) { + _highlightAnimationController.forward(); + } + }); + _highlightAnimationColorTween = ColorTween( + begin: widget.highlightAnimationBeginColor, + end: widget.highlightAnimationEndColor) + .animate(_highlightAnimationController); + _highlightAnimationController.forward(); + } + focusNode = widget.focusNode ?? FocusNode(); + + _initTextController(); + _calculateStrList(); + widget.controller?.addListener(_controllerListener); + focusNode?.addListener(_focusListener); + } + + void _controllerListener() { + if (mounted == true) { + setState(() { + _initTextController(); + }); + + if (widget.onTextChanged != null) { + widget.onTextChanged(widget.controller.text); + } + } + } + + void _focusListener() { + if (mounted == true) { + setState(() { + hasFocus = focusNode.hasFocus; + }); + } + } + + void _initTextController() { + if (widget.controller == null) { + return; + } + strList.clear(); + if (widget.controller.text.isNotEmpty) { + if (widget.controller.text.length > widget.maxLength) { + throw Exception("TextEditingController length exceeded maxLength!"); + } + } + + text = widget.controller.text; + for (var i = 0; i < text.length; i++) { + strList.add(widget.hideCharacter ? widget.maskCharacter : text[i]); + } + } + + double get _width { + var width = 0.0; + for (var i = 0; i < widget.maxLength; i++) { + width += widget.pinBoxWidth; + if (i == 0) { + width += widget.pinBoxOuterPadding?.left ?? 0; + } else if (i + 1 == widget.maxLength) { + width += widget.pinBoxOuterPadding?.right ?? 0; + } else { + width += widget.pinBoxOuterPadding?.left ?? + 0 + widget.pinBoxOuterPadding?.right ?? + 0; + } + } + return width; + } + + @override + void dispose() { + if (widget.focusNode == null) { + // Only dispose the focus node if it's internal. Don't dispose the passed + // in focus node as it's owned by the parent not this child widget. + focusNode?.dispose(); + } else { + focusNode.removeListener(_focusListener); + } + _highlightAnimationController?.dispose(); + widget.controller?.removeListener(_controllerListener); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + !widget.isCupertino ? _fakeTextInput() : _fakeTextInputCupertino(), + _touchPinBoxRow(), + ], + ); + } + + Widget _touchPinBoxRow() { + return widget.hideDefaultKeyboard + ? _pinBoxRow(context) + : GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + if (hasFocus) { + FocusScope.of(context).requestFocus(FocusNode()); + Future.delayed(Duration(milliseconds: 100), () { + FocusScope.of(context).requestFocus(focusNode); + }); + } else { + FocusScope.of(context).requestFocus(focusNode); + } + }, + child: _pinBoxRow(context), + ); + } + + Widget _fakeTextInput() { + var transparentBorder = OutlineInputBorder( + borderSide: BorderSide( + color: Colors.transparent, + width: 0.0, + ), + ); + return Container( + width: _width, + height: widget.pinBoxHeight, + child: TextField( + autofocus: !kIsWeb ? widget.autofocus : false, + enableInteractiveSelection: false, + focusNode: focusNode, + controller: widget.controller, + keyboardType: widget.keyboardType, + inputFormatters: widget.keyboardType == TextInputType.number + ? [WhitelistingTextInputFormatter.digitsOnly] + : null, + style: TextStyle( + height: 0.1, color: Colors.transparent, +// color: Colors.transparent, + ), + decoration: InputDecoration( + focusedErrorBorder: transparentBorder, + errorBorder: transparentBorder, + disabledBorder: transparentBorder, + enabledBorder: transparentBorder, + focusedBorder: transparentBorder, + counterText: null, + counterStyle: null, + helperStyle: TextStyle( + height: 0.0, + color: Colors.transparent, + ), + labelStyle: TextStyle(height: 0.1), + fillColor: Colors.transparent, + border: InputBorder.none, + ), + cursorColor: Colors.transparent, + showCursor: false, + maxLength: widget.maxLength, + onChanged: _onTextChanged, + ), + ); + } + + Widget _fakeTextInputCupertino() { + return Container( + width: _width, + height: widget.pinBoxHeight, + child: CupertinoTextField( + autofocus: !kIsWeb ? widget.autofocus : false, + focusNode: focusNode, + controller: widget.controller, + keyboardType: widget.keyboardType, + inputFormatters: widget.keyboardType == TextInputType.number + ? [WhitelistingTextInputFormatter.digitsOnly] + : null, + style: TextStyle( + color: Colors.transparent, + ), + decoration: BoxDecoration( + color: Colors.transparent, + border: null, + ), + cursorColor: Colors.transparent, + showCursor: false, + maxLength: widget.maxLength, + onChanged: _onTextChanged, + ), + ); + } + + void _onTextChanged(text) { + if (widget.onTextChanged != null) { + widget.onTextChanged(text); + } + setState(() { + this.text = text; + if (text.length < currentIndex) { + strList[text.length] = ""; + } else { + for (int i = currentIndex; i < text.length; i++) { + strList[i] = widget.hideCharacter ? widget.maskCharacter : text[i]; + } + } + currentIndex = text.length; + }); + if (text.length == widget.maxLength) { + FocusScope.of(context).requestFocus(FocusNode()); + widget.onDone(text); + } + } + + Widget _pinBoxRow(BuildContext context) { + _calculateStrList(); + List pinCodes = List.generate(widget.maxLength, (int i) { + return _buildPinCode(i, context); + }); + return Wrap( + direction: Axis.horizontal, + alignment: widget.wrapAlignment, + verticalDirection: VerticalDirection.down, + textDirection: widget.textDirection, + children: pinCodes, + ); + } + + Widget _buildPinCode(int i, BuildContext context) { + Color borderColor; + Color pinBoxColor; + BoxDecoration boxDecoration; + if (widget.hasError) { + borderColor = widget.errorBorderColor; + } else if (widget.highlightAnimation && _shouldHighlight(i)) { + pinBoxColor = widget.pinBoxColor; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: AnimatedBuilder( + animation: _highlightAnimationController, + builder: (BuildContext context, Widget child) { + if (widget.pinBoxDecoration != null) { + boxDecoration = widget.pinBoxDecoration( + _highlightAnimationColorTween.value, + pinBoxColor, + borderWidth: widget.pinBoxBorderWidth, + radius: widget.pinBoxRadius, + ); + } else { + boxDecoration = + ProvidedPinBoxDecoration.defaultPinBoxDecoration( + _highlightAnimationColorTween.value, + pinBoxColor, + borderWidth: widget.pinBoxBorderWidth, + radius: widget.pinBoxRadius, + ); + } + + return Container( + key: ValueKey("container$i"), + child: Center(child: _animatedTextBox(strList[i], i)), + decoration: boxDecoration, + width: widget.pinBoxWidth, + height: widget.pinBoxHeight, + ); + })); + } else if (widget.highlight && _shouldHighlight(i)) { + borderColor = widget.highlightColor; + pinBoxColor = widget.highlightPinBoxColor; + } else if (i < text.length) { + borderColor = widget.hasTextBorderColor; + pinBoxColor = widget.highlightPinBoxColor; + } else { + borderColor = widget.defaultBorderColor; + pinBoxColor = widget.pinBoxColor; + } + + if (widget.pinBoxDecoration != null) { + boxDecoration = widget.pinBoxDecoration( + borderColor, + pinBoxColor, + borderWidth: widget.pinBoxBorderWidth, + radius: widget.pinBoxRadius, + ); + } else { + boxDecoration = ProvidedPinBoxDecoration.defaultPinBoxDecoration( + borderColor, + pinBoxColor, + borderWidth: widget.pinBoxBorderWidth, + radius: widget.pinBoxRadius, + ); + } + EdgeInsets insets; + if (i == 0) { + insets = EdgeInsets.only( + left: 0, + top: widget.pinBoxOuterPadding.top, + right: widget.pinBoxOuterPadding.right, + bottom: widget.pinBoxOuterPadding.bottom, + ); + } else if (i == strList.length - 1) { + insets = EdgeInsets.only( + left: widget.pinBoxOuterPadding.left, + top: widget.pinBoxOuterPadding.top, + right: 0, + bottom: widget.pinBoxOuterPadding.bottom, + ); + } else { + insets = widget.pinBoxOuterPadding; + } + return Padding( + padding: insets, + child: Container( + key: ValueKey("container$i"), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 8), + child: Container( + child: Center(child: _animatedTextBox(strList[i], i)), + decoration: widget.hasUnderline + ? BoxDecoration( + border: Border(bottom: BorderSide(color: borderColor ?? Colors.black,),), + ) + : null, + ), + ), + decoration: boxDecoration, + width: widget.pinBoxWidth, + height: widget.pinBoxHeight, + ), + ); + } + + bool _shouldHighlight(int i) { + return hasFocus && + (i == text.length || + (i == text.length - 1 && text.length == widget.maxLength)); + } + + Widget _animatedTextBox(String text, int i) { + if (widget.pinTextAnimatedSwitcherTransition != null) { + return AnimatedSwitcher( + duration: widget.pinTextAnimatedSwitcherDuration, + transitionBuilder: widget.pinTextAnimatedSwitcherTransition ?? + (Widget child, Animation animation) { + return child; + }, + child: Text( + text, + key: ValueKey("$text$i"), + style: widget.pinTextStyle, + ), + ); + } else { + return Text( + text, + key: ValueKey("${strList[i]}$i"), + style: widget.pinTextStyle, + ); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/radial_menu/demo.dart b/FlutterHelper/flutter_helper/lib/samples/radial_menu/demo.dart new file mode 100644 index 00000000..4a46cde3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/radial_menu/demo.dart @@ -0,0 +1,210 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/samples/radial_menu/src/radial_menu.dart'; +import 'package:flutter_helper/samples/radial_menu/src/radial_menu_item.dart'; + +enum MenuOptions { + unread, + share, + archive, + delete, + backup, + copy, +} + +class RadialMenuApp extends StatelessWidget with HighMixin{ + + + + GlobalKey _menuKey = new GlobalKey(); + + final List> items = >[ + new RadialMenuItem( + value: MenuOptions.unread, + child: new Icon( + Icons.markunread, + ), + iconColor: Colors.white, + backgroundColor: Colors.blue[400], + tooltip: 'unread', + ), + new RadialMenuItem( + value: MenuOptions.share, + child: new Icon( + Icons.share, + ), + iconColor: Colors.white, + backgroundColor: Colors.green[400], + ), + new RadialMenuItem( + value: MenuOptions.archive, + child: new Icon( + Icons.archive, + ), + iconColor: Colors.white, + backgroundColor: Colors.yellow[400], + ), + new RadialMenuItem( + value: MenuOptions.delete, + child: new Icon( + Icons.delete, + ), + iconColor: Colors.white, + backgroundColor: Colors.red[400], + ), + new RadialMenuItem( + value: MenuOptions.backup, + child: new Icon( + Icons.backup, + ), + iconColor: Colors.white, + backgroundColor: Colors.black, + ), + new RadialMenuItem( + value: MenuOptions.copy, + child: new Icon( + Icons.content_copy, + ), + iconColor: Colors.white, + backgroundColor: Colors.indigo[400], + ), + ]; + + void _onItemSelected(MenuOptions value) { + print(value); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: new Scaffold( + body: new Center( + child: new RadialMenu( + key: _menuKey, + items: items, + radius: 100.0, + onSelected: _onItemSelected, + ), + ), + floatingActionButton: new FloatingActionButton( + child: new Icon(Icons.restore), + onPressed: () => _menuKey.currentState.reset(), + ), + ), + ); + } + + @override + High getHigh()=>High(toStringShort(), """ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/samples/radial_menu/src/radial_menu.dart'; +import 'package:flutter_helper/samples/radial_menu/src/radial_menu_item.dart'; + +enum MenuOptions { + unread, + share, + archive, + delete, + backup, + copy, +} + +class RadialMenuApp extends StatelessWidget with HighMixin{ + + + + GlobalKey _menuKey = new GlobalKey(); + + final List> items = >[ + new RadialMenuItem( + value: MenuOptions.unread, + child: new Icon( + Icons.markunread, + ), + iconColor: Colors.white, + backgroundColor: Colors.blue[400], + tooltip: 'unread', + ), + new RadialMenuItem( + value: MenuOptions.share, + child: new Icon( + Icons.share, + ), + iconColor: Colors.white, + backgroundColor: Colors.green[400], + ), + new RadialMenuItem( + value: MenuOptions.archive, + child: new Icon( + Icons.archive, + ), + iconColor: Colors.white, + backgroundColor: Colors.yellow[400], + ), + new RadialMenuItem( + value: MenuOptions.delete, + child: new Icon( + Icons.delete, + ), + iconColor: Colors.white, + backgroundColor: Colors.red[400], + ), + new RadialMenuItem( + value: MenuOptions.backup, + child: new Icon( + Icons.backup, + ), + iconColor: Colors.white, + backgroundColor: Colors.black, + ), + new RadialMenuItem( + value: MenuOptions.copy, + child: new Icon( + Icons.content_copy, + ), + iconColor: Colors.white, + backgroundColor: Colors.indigo[400], + ), + ]; + + void _onItemSelected(MenuOptions value) { + print(value); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: new Scaffold( + body: new Center( + child: new RadialMenu( + key: _menuKey, + items: items, + radius: 100.0, + onSelected: _onItemSelected, + ), + ), + floatingActionButton: new FloatingActionButton( + child: new Icon(Icons.restore), + onPressed: () => _menuKey.currentState.reset(), + ), + ), + ); + } + + @override + High getHigh()=>High(toStringShort(), """ + + """); +} + +void main() { + runApp(RadialMenuApp()); +} + + """); +} + +void main() { + runApp(RadialMenuApp()); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/radial_menu/flutter_radial_menu.dart b/FlutterHelper/flutter_helper/lib/samples/radial_menu/flutter_radial_menu.dart new file mode 100644 index 00000000..509e6813 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/radial_menu/flutter_radial_menu.dart @@ -0,0 +1,4 @@ +library flutter_radial_menu; + +export 'src/radial_menu.dart'; +export 'src/radial_menu_item.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/arc_progress_indicator.dart b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/arc_progress_indicator.dart new file mode 100644 index 00000000..ae2e9048 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/arc_progress_indicator.dart @@ -0,0 +1,134 @@ +import 'dart:math' as Math; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// Draws an [ActionIcon] and [_ArcProgressPainter] that represent an active action. +/// As the provided [Animation] progresses the ActionArc grows into a full +/// circle and the ActionIcon moves along it. +class ArcProgressIndicator extends StatelessWidget { + // required + final Animation controller; + final double radius; + + // optional + final double startAngle; + final double width; + + /// The color to use when filling the arc. + /// + /// Defaults to the accent color of the current theme. + final Color color; + final IconData icon; + final Color iconColor; + final double iconSize; + + // private + final Animation _progress; + + ArcProgressIndicator({ + @required this.controller, + @required this.radius, + this.startAngle = 0.0, + this.width, + this.color, + this.icon, + this.iconColor, + this.iconSize, + }) : _progress = new Tween(begin: 0.0, end: 1.0).animate(controller); + + @override + Widget build(BuildContext context) { + TextPainter _iconPainter; + final ThemeData theme = Theme.of(context); + final Color _iconColor = iconColor ?? theme.accentIconTheme.color; + final double _iconSize = iconSize ?? IconTheme.of(context).size; + + if (icon != null) { + _iconPainter = new TextPainter( + textDirection: Directionality.of(context), + text: new TextSpan( + text: new String.fromCharCode(icon.codePoint), + style: new TextStyle( + inherit: false, + color: _iconColor, + fontSize: _iconSize, + fontFamily: icon.fontFamily, + package: icon.fontPackage, + ), + ), + )..layout(); + } + + return new CustomPaint( + painter: new _ArcProgressPainter( + controller: _progress, + color: color ?? theme.accentColor, + radius: radius, + width: width ?? _iconSize * 2, + startAngle: startAngle, + icon: _iconPainter, + ), + ); + } +} + +class _ArcProgressPainter extends CustomPainter { + // required + final Animation controller; + final Color color; + final double radius; + final double width; + + // optional + final double startAngle; + final TextPainter icon; + + _ArcProgressPainter({ + @required this.controller, + @required this.color, + @required this.radius, + @required this.width, + this.startAngle = 0.0, + this.icon, + }) : super(repaint: controller); + + @override + void paint(Canvas canvas, Size size) { + Paint paint = new Paint() + ..color = color + ..strokeWidth = width + ..strokeCap = StrokeCap.round + ..style = PaintingStyle.stroke; + + final double sweepAngle = controller.value * 2 * Math.pi; + + canvas.drawArc( + Offset.zero & size, + startAngle, + sweepAngle, + false, + paint, + ); + + if (icon != null) { + double angle = startAngle + sweepAngle; + Offset offset = new Offset( + (size.width / 2 - icon.size.width / 2) + radius * Math.cos(angle), + (size.height / 2 - icon.size.height / 2) + radius * Math.sin(angle), + ); + + icon.paint(canvas, offset); + } + } + + @override + bool shouldRepaint(_ArcProgressPainter other) { + return controller.value != other.controller.value || + color != other.color || + radius != other.radius || + width != other.width || + startAngle != other.startAngle || + icon != other.icon; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu.dart b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu.dart new file mode 100644 index 00000000..c4e10800 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu.dart @@ -0,0 +1,303 @@ +import 'dart:async'; +import 'dart:math' as Math; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/radial_menu/src/radial_menu_button.dart'; +import 'package:flutter_helper/samples/radial_menu/src/radial_menu_center_button.dart'; +import 'package:flutter_helper/samples/radial_menu/src/radial_menu_item.dart'; + +import 'arc_progress_indicator.dart'; + +const double _radiansPerDegree = Math.pi / 180; +final double _startAngle = -90.0 * _radiansPerDegree; + +typedef double ItemAngleCalculator(int index); + +/// A radial menu for selecting from a list of items. +/// +/// A radial menu lets the user select from a number of items. It displays a +/// button that opens the menu, showing its items arranged in an arc. Selecting +/// an item triggers the animation of a progress bar drawn at the specified +/// [radius] around the central menu button. +/// +/// The type `T` is the type of the values the radial menu represents. All the +/// entries in a given menu must represent values with consistent types. +/// Typically, an enum is used. Each [RadialMenuItem] in [items] must be +/// specialized with that same type argument. +/// +/// Requires one of its ancestors to be a [Material] widget. +/// +/// See also: +/// +/// * [RadialMenuItem], the widget used to represent the [items]. +/// * [RadialMenuCenterButton], the button used to open and close the menu. +class RadialMenu extends StatefulWidget { + /// Creates a dropdown button. + /// + /// The [items] must have distinct values. + /// + /// The [radius], [menuAnimationDuration], and [progressAnimationDuration] + /// arguments must not be null (they all have defaults, so do not need to be + /// specified). + const RadialMenu({ + Key key, + @required this.items, + @required this.onSelected, + this.radius = 100.0, + this.menuAnimationDuration = const Duration(milliseconds: 1000), + this.progressAnimationDuration = const Duration(milliseconds: 1000), + }) : assert(radius != null), + assert(menuAnimationDuration != null), + assert(progressAnimationDuration != null), + super(key: key); + + /// The list of possible items to select among. + final List> items; + + /// Called when the user selects an item. + final ValueChanged onSelected; + + /// The radius of the arc used to lay out the items and draw the progress bar. + /// + /// Defaults to 100.0. + final double radius; + + /// Duration of the menu opening/closing animation. + /// + /// Defaults to 1000 milliseconds. + final Duration menuAnimationDuration; + + /// Duration of the action activation progress arc animation. + /// + /// Defaults to 1000 milliseconds. + final Duration progressAnimationDuration; + + @override + RadialMenuState createState() => new RadialMenuState(); +} + +class RadialMenuState extends State with TickerProviderStateMixin { + AnimationController _menuAnimationController; + AnimationController _progressAnimationController; + bool _isOpen = false; + int _activeItemIndex; + + // xqwzts: allow users to pass in their own calculator as a param. + // and change this to the default: radialItemAngleCalculator. + double calculateItemAngle(int index) { + double _itemSpacing = 360.0 / widget.items.length; + return _startAngle + index * _itemSpacing * _radiansPerDegree; + } + + @override + void initState() { + super.initState(); + _menuAnimationController = new AnimationController( + duration: widget.menuAnimationDuration, + vsync: this, + ); + _progressAnimationController = new AnimationController( + duration: widget.progressAnimationDuration, + vsync: this, + ); + } + + @override + void dispose() { + _menuAnimationController.dispose(); + _progressAnimationController.dispose(); + super.dispose(); + } + + void _openMenu() { + _menuAnimationController.forward(); + setState(() => _isOpen = true); + } + + void _closeMenu() { + _menuAnimationController.reverse(); + setState(() => _isOpen = false); + } + + Future _activate(int itemIndex) async { + setState(() => _activeItemIndex = itemIndex); + await _progressAnimationController.forward().orCancel; + if (widget.onSelected != null) { + widget.onSelected(widget.items[itemIndex].value); + } + } + + /// Resets the menu to its initial (closed) state. + void reset() { + _menuAnimationController.reset(); + _progressAnimationController.reverse(); + setState(() { + _isOpen = false; + _activeItemIndex = null; + }); + } + + Widget _buildActionButton(int index) { + final RadialMenuItem item = widget.items[index]; + + return new LayoutId( + id: '${_RadialMenuLayout.actionButton}$index', + child: new RadialMenuButton( + child: item, + backgroundColor: item.backgroundColor, + onPressed: () => _activate(index), + ), + ); + } + + Widget _buildActiveAction(int index) { + final RadialMenuItem item = widget.items[index]; + + return new LayoutId( + id: '${_RadialMenuLayout.activeAction}$index', + child: new ArcProgressIndicator( + controller: _progressAnimationController.view, + radius: widget.radius, + color: item.backgroundColor, + icon: item.child is Icon ? (item.child as Icon).icon : null, + iconColor: item.iconColor, + startAngle: calculateItemAngle(index), + ), + ); + } + + Widget _buildCenterButton() { + return new LayoutId( + id: _RadialMenuLayout.menuButton, + child: new RadialMenuCenterButton( + openCloseAnimationController: _menuAnimationController.view, + activateAnimationController: _progressAnimationController.view, + isOpen: _isOpen, + onPressed: _isOpen ? _closeMenu : _openMenu, + ), + ); + } + + @override + Widget build(BuildContext context) { + final List children = []; + + for (int i = 0; i < widget.items.length; i++) { + if (_activeItemIndex != i) { + children.add(_buildActionButton(i)); + } + } + + if (_activeItemIndex != null) { + children.add(_buildActiveAction(_activeItemIndex)); + } + + children.add(_buildCenterButton()); + + return new AnimatedBuilder( + animation: _menuAnimationController, + builder: (BuildContext context, Widget child) { + return new CustomMultiChildLayout( + delegate: new _RadialMenuLayout( + itemCount: widget.items.length, + radius: widget.radius, + calculateItemAngle: calculateItemAngle, + controller: _menuAnimationController.view, + ), + children: children, + ); + }, + ); + } +} + +class _RadialMenuLayout extends MultiChildLayoutDelegate { + static const String menuButton = 'menuButton'; + static const String actionButton = 'actionButton'; + static const String activeAction = 'activeAction'; + + final int itemCount; + final double radius; + final ItemAngleCalculator calculateItemAngle; + + final Animation controller; + + final Animation _progress; + + _RadialMenuLayout({ + @required this.itemCount, + @required this.radius, + @required this.calculateItemAngle, + this.controller, + }) : _progress = new Tween(begin: 0.0, end: radius).animate( + new CurvedAnimation(curve: Curves.elasticOut, parent: controller)); + + Offset center; + + @override + void performLayout(Size size) { + center = new Offset(size.width / 2, size.height / 2); + + if (hasChild(menuButton)) { + Size menuButtonSize; + menuButtonSize = layoutChild(menuButton, new BoxConstraints.loose(size)); + + // place the menubutton in the center + positionChild( + menuButton, + new Offset( + center.dx - menuButtonSize.width / 2, + center.dy - menuButtonSize.height / 2, + ), + ); + } + + for (int i = 0; i < itemCount; i++) { + final String actionButtonId = '$actionButton$i'; + final String actionArcId = '$activeAction$i'; + if (hasChild(actionArcId)) { + final Size arcSize = layoutChild( + actionArcId, + new BoxConstraints.expand( + width: _progress.value * 2, + height: _progress.value * 2, + ), + ); + + positionChild( + actionArcId, + new Offset( + center.dx - arcSize.width / 2, + center.dy - arcSize.height / 2, + ), + ); + } + + if (hasChild(actionButtonId)) { + final Size buttonSize = + layoutChild(actionButtonId, new BoxConstraints.loose(size)); + + final double itemAngle = calculateItemAngle(i); + + positionChild( + actionButtonId, + new Offset( + (center.dx - buttonSize.width / 2) + + (_progress.value) * Math.cos(itemAngle), + (center.dy - buttonSize.height / 2) + + (_progress.value) * Math.sin(itemAngle), + ), + ); + } + } + } + + @override + bool shouldRelayout(_RadialMenuLayout oldDelegate) => + itemCount != oldDelegate.itemCount || + radius != oldDelegate.radius || + calculateItemAngle != oldDelegate.calculateItemAngle || + controller != oldDelegate.controller || + _progress != oldDelegate._progress; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_button.dart b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_button.dart new file mode 100644 index 00000000..cab8c13a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_button.dart @@ -0,0 +1,32 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class RadialMenuButton extends StatelessWidget { + const RadialMenuButton({ + @required this.child, + this.backgroundColor, + this.onPressed, + }); + + final Widget child; + final Color backgroundColor; + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + final Color color = backgroundColor ?? Theme.of(context).primaryColor; + + return new Semantics( + button: true, + enabled: true, + child: new Material( + type: MaterialType.circle, + color: color, + child: new InkWell( + onTap: onPressed, + child: child, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_center_button.dart b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_center_button.dart new file mode 100644 index 00000000..001de0c8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_center_button.dart @@ -0,0 +1,107 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/radial_menu/src/radial_menu_button.dart'; + +const double _defaultButtonSize = 48.0; + +/// The button at the center of a [RadialMenu] which controls its open/closed +/// state. +class RadialMenuCenterButton extends StatelessWidget { + /// Drives the opening/closing animation of the [RadialMenu]. + final Animation openCloseAnimationController; + + /// Drives the animation when an item in the [RadialMenu] is pressed. + final Animation activateAnimationController; + + /// Called when the user presses this button. + final VoidCallback onPressed; + + /// The opened/closed state of the menu. + /// + /// Determines which of [closedColor] or [openedColor] should be used as the + /// background color of the button. + final bool isOpen; + + /// The color to use when painting the icon. + /// + /// Defaults to [Colors.black]. + final Color iconColor; + + /// Background color when it is in its closed state. + /// + /// Defaults to [Colors.white]. + final Color closedColor; + + /// Background color when it is in its opened state. + /// + /// Defaults to [Colors.grey]. + final Color openedColor; + + /// The size of the button. + /// + /// Defaults to 48.0. + final double size; + + /// The animation progress for the [AnimatedIcon] in the center of the button. + final Animation _progress; + + /// The scale factor applied to the button. + /// + /// Animates from 1.0 to 0.0 when an an item is pressed in the menu and + /// [activateAnimationController] progresses. + final Animation _scale; + + RadialMenuCenterButton({ + @required this.openCloseAnimationController, + @required this.activateAnimationController, + @required this.onPressed, + @required this.isOpen, + this.iconColor = Colors.black, + this.closedColor = Colors.white, + this.openedColor = Colors.grey, + this.size = _defaultButtonSize, + }) : _progress = new Tween(begin: 0.0, end: 1.0).animate( + new CurvedAnimation( + parent: openCloseAnimationController, + curve: new Interval( + 0.0, + 0.5, + curve: Curves.ease, + ), + ), + ), + _scale = new Tween(begin: 1.0, end: 0.0).animate( + new CurvedAnimation( + parent: activateAnimationController, + curve: Curves.elasticIn, + ), + ); + + @override + Widget build(BuildContext context) { + final AnimatedIcon animatedIcon = new AnimatedIcon( + color: iconColor, + icon: AnimatedIcons.menu_close, + progress: _progress, + ); + + final Widget child = new Container( + width: size, + height: size, + child: new Center( + child: animatedIcon, + ), + ); + + final Color color = isOpen ? openedColor : closedColor; + + return new ScaleTransition( + scale: _scale, + child: new RadialMenuButton( + child: child, + backgroundColor: color, + onPressed: onPressed, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_item.dart b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_item.dart new file mode 100644 index 00000000..d29919c3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/radial_menu/src/radial_menu_item.dart @@ -0,0 +1,91 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +const double _defaultButtonSize = 48.0; + +/// An item in a [RadialMenu]. +/// +/// The type `T` is the type of the value the entry represents. All the entries +/// in a given menu must represent values with consistent types. +class RadialMenuItem extends StatelessWidget { + /// Creates a circular action button for an item in a [RadialMenu]. + /// + /// The [child] argument is required. + const RadialMenuItem({ + Key key, + @required this.child, + this.value, + this.tooltip, + this.size = _defaultButtonSize, + this.backgroundColor, + this.iconColor, + // this.iconSize: 24.0, + }) : assert(child != null), + assert(size != null), + super(key: key); + + /// The widget below this widget in the tree. + /// + /// Typically an [Icon] widget. + final Widget child; + + /// The value to return if the user selects this menu item. + /// + /// Eventually returned in a call to [RadialMenu.onSelected]. + final T value; + + /// Text that describes the action that will occur when the button is pressed. + /// + /// This text is displayed when the user long-presses on the button and is + /// used for accessibility. + final String tooltip; + + /// The color to use when filling the button. + /// + /// Defaults to the primary color of the current theme. + final Color backgroundColor; + + /// The size of the button. + /// + /// Defaults to 48.0. + final double size; + + /// The color to use when painting the child icon. + /// + /// Defaults to the primary icon theme color. + final Color iconColor; + + @override + Widget build(BuildContext context) { + final Color _iconColor = + iconColor ?? Theme.of(context).primaryIconTheme.color; + + Widget result; + + if (child != null) { + result = new Center( + child: IconTheme.merge( + data: new IconThemeData( + color: _iconColor, + ), + child: child, + ), + ); + } + + if (tooltip != null) { + result = new Tooltip( + message: tooltip, + child: result, + ); + } + + result = new Container( + width: size, + height: size, + child: result, + ); + + return result; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/samples_1.dart b/FlutterHelper/flutter_helper/lib/samples/samples_1.dart new file mode 100644 index 00000000..972f6bbd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/samples_1.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class GridViewCount extends StatelessWidget with HighMixin { + @override + Widget build(BuildContext context) => GridView.count( + crossAxisCount: 2, + children: List.generate( + 100, + (index) => Text( + '$index', + style: Theme.of(context).textTheme.headline5, + )), + ); + + @override + High getHigh() => High(toStringShort(), """ + @override + Widget build(BuildContext context) => GridView.count( + crossAxisCount: 2, + children: List.generate( + 100, + (index) => Text( + 'index', + style: Theme.of(context).textTheme.headline5, + )), + ); + """); +} + +class ListViewHorizontal extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) => ListView( + scrollDirection: Axis.horizontal, + children: [ + Container( + width: 160.0, + color: Colors.red, + ), + Container( + width: 160.0, + color: Colors.blue, + ), + Container( + width: 160.0, + color: Colors.green, + ), + Container( + width: 160.0, + color: Colors.yellow, + ), + Container( + width: 160.0, + color: Colors.orange, + ), + ], + ); + + @override + High getHigh() => High(toStringShort(), """ + + """); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/scatcher/advanced.dart b/FlutterHelper/flutter_helper/lib/samples/scatcher/advanced.dart new file mode 100644 index 00000000..9a852f7a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/scatcher/advanced.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; + +import 'scratch_box.dart'; + +const _googleIcon = 'assets/google.png'; +const _dartIcon = 'assets/dart.png'; +const _flutterIcon = 'assets/flutter.png'; + +class AdvancedScreen extends StatefulWidget { + @override + _AdvancedScreenState createState() => _AdvancedScreenState(); +} + +class _AdvancedScreenState extends State + with SingleTickerProviderStateMixin { + double validScratches = 0; + AnimationController _animationController; + Animation _animation; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 1200), + )..addStatusListener( + (listener) { + if (listener == AnimationStatus.completed) { + _animationController.reverse(); + } + }, + ); + _animation = Tween(begin: 1.0, end: 1.25).animate( + CurvedAnimation( + parent: _animationController, + curve: Curves.elasticIn, + ), + ); + super.initState(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Text( + 'Scratcher', + style: TextStyle( + fontFamily: 'The unseen', + color: Colors.blueAccent, + fontSize: 50, + fontWeight: FontWeight.bold, + ), + ), + const Text( + 'scratch to win!', + style: TextStyle( + fontFamily: 'The unseen', + color: Colors.black, + fontSize: 20, + ), + ), + Container( + margin: const EdgeInsets.only(top: 10), + height: 1, + width: 300, + color: Colors.black12, + ) + ], + ), + buildRow(_googleIcon, _flutterIcon, _googleIcon), + buildRow(_dartIcon, _flutterIcon, _googleIcon), + buildRow(_dartIcon, _flutterIcon, _dartIcon), + ], + ), + ), + ); + } + + Widget buildRow(String left, String center, String right) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ScratchBox(image: left), + ScratchBox( + image: center, + animation: _animation, + onScratch: () { + setState(() { + validScratches++; + if (validScratches == 3) { + _animationController.forward(); + } + }); + }, + ), + ScratchBox(image: right), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/scatcher/basic.dart b/FlutterHelper/flutter_helper/lib/samples/scatcher/basic.dart new file mode 100644 index 00000000..0b0d95cc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/scatcher/basic.dart @@ -0,0 +1,160 @@ +import 'package:flutter/material.dart'; + +import 'lib/scratcher.dart'; + +class BasicScreen extends StatefulWidget { + @override + _BasicScreenState createState() => _BasicScreenState(); +} + +class _BasicScreenState extends State { + double brushSize = 30; + double progress = 0; + bool thresholdReached = false; + bool enabled = true; + double size; + final key = GlobalKey(); + + @override + Widget build(BuildContext context) { + return SafeArea( + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + RaisedButton( + child: const Text('Reset'), + onPressed: () { + key.currentState?.reset( + duration: const Duration(milliseconds: 2000), + ); + setState(() => thresholdReached = false); + }, + ), + RaisedButton( + child: const Text('Change size'), + onPressed: () { + setState(() { + if (size == null) { + size = 200; + } else if (size == 200) { + size = 0; + } else { + size = null; + } + }); + }, + ), + RaisedButton( + child: const Text('Reveal'), + onPressed: () { + key.currentState?.reveal( + duration: const Duration(milliseconds: 2000), + ); + }, + ), + ], + ), + Column( + children: [ + Text('Brush size (${brushSize.round()})'), + Slider( + value: brushSize, + onChanged: (v) => setState(() => brushSize = v), + min: 5, + max: 100, + ), + ], + ), + CheckboxListTile( + value: enabled, + title: Text('Scratcher enabled'), + onChanged: (e) => setState(() { + enabled = e ?? false; + }), + ), + Expanded( + child: Stack( + children: [ + SizedBox( + height: size, + width: size, + child: Scratcher( + key: key, + enabled: enabled, + brushSize: brushSize, + threshold: 30, + image: Image.asset('assets/background.jpg'), + onThreshold: () => setState(() => thresholdReached = true), + onChange: (value) { + setState(() { + progress = value; + }); + }, + onScratchStart: () { + print("Scratching has started"); + }, + onScratchUpdate: () { + print("Scratching in progress"); + }, + onScratchEnd: () { + print("Scratching has finished"); + }, + child: Container( + color: Colors.black, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Scratch the screen!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 36, + fontWeight: FontWeight.bold, + color: Colors.amber, + ), + ), + SizedBox(height: 8), + const Text( + 'Photo by Fabian Wiktor from Pexels', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.amber, + ), + ) + ], + ), + ), + ), + ), + Positioned( + bottom: 0, + right: 0, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 12, + ), + color: Colors.black, + child: Text( + '${progress.floor().toString()}% ' + '(${thresholdReached ? 'done' : 'pending'})', + textAlign: TextAlign.right, + style: const TextStyle( + color: Colors.white, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/painter.dart b/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/painter.dart new file mode 100755 index 00000000..06640324 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/painter.dart @@ -0,0 +1,96 @@ +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'utils.dart'; + +/// Custom painter object which handles revealing of color/image +class ScratchPainter extends CustomPainter { + ScratchPainter({ + @required this.points, + @required this.color, + @required this.onDraw, + this.image, + this.imageFit, + }); + + /// List of revealed points from scratcher + final List points; + + /// Background color of the scratch area + final Color color; + + /// Callback called each time the painter is redraw + final void Function(Size) onDraw; + + /// Path to local image which can be used as scratch area + final ui.Image image; + + /// Determine how the image should fit the scratch area + final BoxFit imageFit; + + Paint _getMainPaint(double strokeWidth) { + final paint = Paint() + ..strokeCap = StrokeCap.round + ..color = Colors.transparent + ..strokeWidth = strokeWidth + ..blendMode = BlendMode.src + ..style = PaintingStyle.stroke; + + return paint; + } + + @override + void paint(Canvas canvas, Size size) { + onDraw(size); + + canvas.saveLayer(null, Paint()); + + final areaRect = Rect.fromLTRB(0, 0, size.width, size.height); + canvas.drawRect(areaRect, Paint()..color = color); + if (image != null && imageFit != null) { + // double: why the ! are needed here, as check against null been performed? + final imageSize = Size(image.width.toDouble(), image.height.toDouble()); + final sizes = applyBoxFit(imageFit, imageSize, size); + final inputSubrect = + Alignment.center.inscribe(sizes.source, Offset.zero & imageSize); + final outputSubrect = + Alignment.center.inscribe(sizes.destination, areaRect); + + canvas.drawImageRect(image, inputSubrect, outputSubrect, Paint()); + } + + var path = Path(); + var isStarted = false; + ScratchPoint previousPoint; + + for (final point in points) { + if (point == null) { + if (previousPoint != null) { + canvas.drawPath(path, _getMainPaint(previousPoint.size)); + } + + path = Path(); + isStarted = false; + } else { + final position = point.position; + if (!isStarted) { + isStarted = true; + path.moveTo(position.dx, position.dy); + } else { + path.lineTo(position.dx, position.dy); + } + } + + previousPoint = point; + } + + if (previousPoint != null) { + canvas.drawPath(path, _getMainPaint(previousPoint.size)); + } + + canvas.restore(); + } + + @override + bool shouldRepaint(ScratchPainter oldDelegate) => true; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/scratcher.dart b/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/scratcher.dart new file mode 100755 index 00000000..ab1c0eea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/scratcher.dart @@ -0,0 +1,2 @@ +export 'painter.dart'; +export 'widgets.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/utils.dart b/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/utils.dart new file mode 100644 index 00000000..35bc10d6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/utils.dart @@ -0,0 +1,9 @@ +import 'package:flutter/material.dart'; + +class ScratchPoint { + ScratchPoint(this.position, this.size); + + // Null position is dedicated for point which closes the continuous drawing + final Offset position; + final double size; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/widgets.dart b/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/widgets.dart new file mode 100755 index 00000000..de7df416 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/scatcher/lib/widgets.dart @@ -0,0 +1,350 @@ +import 'dart:async'; +import 'dart:math'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'utils.dart'; + +import 'painter.dart'; + +const _progressReportStep = 0.1; + +/// How accurate should the progress be tracked. +enum ScratchAccuracy { + /// Low accuracy, higher performance. + low, + + /// Medium accuracy, medium performance + medium, + + /// High accuracy, lower performance. + high, +} + +double _getAccuracyValue(ScratchAccuracy accuracy) { + switch (accuracy) { + case ScratchAccuracy.low: + return 10.0; + case ScratchAccuracy.medium: + return 30.0; + case ScratchAccuracy.high: + return 100.0; + } +} + +/// Scratcher widget which covers given child with scratchable overlay. +class Scratcher extends StatefulWidget { + Scratcher({ + Key key, + @required this.child, + this.enabled = true, + this.threshold, + this.brushSize = 25, + this.accuracy = ScratchAccuracy.high, + this.color = Colors.black, + this.image, + this.rebuildOnResize = true, + this.onChange, + this.onThreshold, + this.onScratchStart, + this.onScratchUpdate, + this.onScratchEnd, + }) : super(key: key); + + /// Widget rendered under the scratch area. + final Widget child; + + /// Whether new scratches can be applied + final bool enabled; + + /// Percentage level of scratch area which should be revealed to complete. + final double threshold; + + /// Size of the brush. The bigger it is the faster user can scratch the card. + final double brushSize; + + /// Determines how accurate the progress should be reported. + /// Lower accuracy means higher performance. + final ScratchAccuracy accuracy; + + /// Color used to cover the child widget. + final Color color; + + /// Image widget used to cover the child widget. + final Image image; + + /// Determines if the scratcher should rebuild itself when space constraints change (resize). + final bool rebuildOnResize; + + /// Callback called when new part of area is revealed (min 0.1% difference, or progress == 100). + final Function(double value) onChange; + + /// Callback called when threshold is reached. + final VoidCallback onThreshold; + + /// Callback called when scratching starts + final VoidCallback onScratchStart; + + /// Callback called during scratching + final VoidCallback onScratchUpdate; + + /// Callback called when scratching ends + final VoidCallback onScratchEnd; + + @override + ScratcherState createState() => ScratcherState(); +} + +class ScratcherState extends State { + Future _imageLoader; + Offset _lastPosition; + + List points = []; + Set checkpoints; + Set checked = {}; + int totalCheckpoints = 0; + double progress = 0; + double progressReported = 0; + bool thresholdReported = false; + bool isFinished = false; + bool canScratch = true; + Duration transitionDuration; + Size _lastKnownSize; + + RenderBox get _renderObject { + return context.findRenderObject() as RenderBox; + } + + @override + void initState() { + if (widget.image == null) { + final completer = Completer()..complete(); + _imageLoader = completer.future; + } else { + _imageLoader = _loadImage(widget.image); + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _imageLoader, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState != ConnectionState.waiting) { + return GestureDetector( + behavior: HitTestBehavior.opaque, + onPanStart: canScratch + ? (details) { + widget.onScratchStart?.call(); + if (widget.enabled) { + _addPoint(details.localPosition); + } + } + : null, + onPanUpdate: canScratch + ? (details) { + widget.onScratchUpdate?.call(); + if (widget.enabled) { + _addPoint(details.localPosition); + } + } + : null, + onPanEnd: canScratch + ? (details) { + widget.onScratchEnd?.call(); + if (widget.enabled) { + setState(() => points.add(null)); + } + } + : null, + child: AnimatedSwitcher( + duration: transitionDuration ?? Duration.zero, + child: isFinished + ? widget.child + : CustomPaint( + foregroundPainter: ScratchPainter( + image: snapshot.data, + imageFit: widget.image == null + ? null + : widget.image.fit ?? BoxFit.cover, + points: points, + color: widget.color, + onDraw: (size) { + if (_lastKnownSize == null) { + _setCheckpoints(size); + } else if (_lastKnownSize != size && + widget.rebuildOnResize) { + WidgetsBinding.instance.addPostFrameCallback((_) { + reset(); + }); + } + + _lastKnownSize = size; + }, + ), + child: widget.child, + ), + ), + ); + } + + return Container(); + }, + ); + } + + Future _loadImage(Image image) async { + final completer = Completer(); + final imageProvider = image.image as dynamic; + final key = await imageProvider.obtainKey(const ImageConfiguration()); + + imageProvider.load(key, ( + Uint8List bytes, { + int cacheWidth, + int cacheHeight, + bool allowUpscaling, + }) async { + return ui.instantiateImageCodec(bytes); + }).addListener(ImageStreamListener((ImageInfo image, _) { + completer.complete(image.image); + })); + + return completer.future; + } + + bool _inCircle(Offset center, Offset point, double radius) { + final dX = center.dx - point.dx; + final dY = center.dy - point.dy; + final multi = dX * dX + dY * dY; + final distance = sqrt(multi).roundToDouble(); + + return distance <= radius; + } + + void _addPoint(Offset position) { + // Ignore when same point is reported multiple times in a row + if (_lastPosition == position) { + return; + } + _lastPosition = position; + + ui.Offset point = position; + + // Ignore when starting point of new line has been already scratched + if (points.isNotEmpty && points.contains(point)) { + if (points.last == null) { + return; + } else { + point = null; + } + } + + setState(() { + points.add(ScratchPoint(point, widget.brushSize)); + }); + + if (point != null && !checked.contains(point)) { + checked.add(point); + + final reached = {}; + for (final checkpoint in checkpoints) { + final radius = widget.brushSize / 2; + if (_inCircle(checkpoint, point, radius)) { + reached.add(checkpoint); + } + } + + checkpoints = checkpoints.difference(reached); + progress = + ((totalCheckpoints - checkpoints.length) / totalCheckpoints) * 100; + if (progress - progressReported >= _progressReportStep || + progress == 100) { + progressReported = progress; + widget.onChange?.call(progress); + } + + if (!thresholdReported && + widget.threshold != null && + progress >= widget.threshold) { + thresholdReported = true; + widget.onThreshold.call(); + } + + if (progress == 100) { + isFinished = true; + } + } + } + + void _setCheckpoints(Size size) { + final calculated = _calculateCheckpoints(size).toSet(); + + checkpoints = calculated; + totalCheckpoints = calculated.length; + } + + List _calculateCheckpoints(Size size) { + final accuracy = _getAccuracyValue(widget.accuracy); + final xOffset = size.width / accuracy; + final yOffset = size.height / accuracy; + + final points = []; + for (var x = 0; x < accuracy; x++) { + for (var y = 0; y < accuracy; y++) { + final point = Offset( + x * xOffset, + y * yOffset, + ); + points.add(point); + } + } + + return points; + } + + /// Resets the scratcher state to the initial values. + void reset({Duration duration}) { + setState(() { + transitionDuration = duration; + isFinished = false; + canScratch = duration == null; + thresholdReported = false; + + _lastPosition = null; + points = []; + checked = {}; + progress = 0; + progressReported = 0; + }); + + // Do not allow to scratch during transition + if (duration != null) { + Future.delayed(duration, () { + setState(() { + canScratch = true; + }); + }); + } + + _setCheckpoints(_renderObject.size); + widget.onChange.call(0); + } + + /// Reveals the whole scratcher, so than only original child is displayed. + void reveal({Duration duration}) { + setState(() { + transitionDuration = duration; + isFinished = true; + canScratch = false; + if (!thresholdReported && widget.threshold != null) { + thresholdReported = true; + widget.onThreshold.call(); + } + }); + + widget.onChange.call(100); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/scatcher/main.dart b/FlutterHelper/flutter_helper/lib/samples/scatcher/main.dart new file mode 100644 index 00000000..42f1ee56 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/scatcher/main.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +import 'advanced.dart'; +import 'basic.dart'; + +void main() => runApp(ScatcherApp()); + +class ScatcherApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + debugShowCheckedModeBanner: false, + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: DefaultTabController( + length: 2, + child: Scaffold( + bottomNavigationBar: SafeArea( + child: TabBar( + labelColor: Colors.blueAccent, + unselectedLabelColor: Colors.blueGrey, + indicatorColor: Colors.blueAccent, + indicatorSize: TabBarIndicatorSize.label, + tabs: [ + Tab(icon: Icon(Icons.looks_one)), + Tab(icon: Icon(Icons.looks_two)), + ], + ), + ), + body: TabBarView( + physics: const NeverScrollableScrollPhysics(), + children: [ + AdvancedScreen(), + BasicScreen(), + ], + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/scatcher/scratch_box.dart b/FlutterHelper/flutter_helper/lib/samples/scatcher/scratch_box.dart new file mode 100644 index 00000000..f0cad7bd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/scatcher/scratch_box.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +import 'lib/widgets.dart'; + +class ScratchBox extends StatefulWidget { + ScratchBox({ + @required this.image, + this.onScratch, + this.animation, + }); + + final String image; + final VoidCallback onScratch; + final Animation animation; + + @override + _ScratchBoxState createState() => _ScratchBoxState(); +} + +class _ScratchBoxState extends State { + bool isScratched = false; + double opacity = 0.5; + + @override + Widget build(BuildContext context) { + var icon = AnimatedOpacity( + opacity: opacity, + duration: const Duration(milliseconds: 750), + child: Image.asset( + widget.image, + width: 70, + height: 70, + fit: BoxFit.contain, + ), + ); + + return Container( + width: 80, + height: 80, + margin: const EdgeInsets.all(10), + child: Scratcher( + accuracy: ScratchAccuracy.low, + color: Colors.blueGrey, + image: Image.asset('assets/scratch.png'), + brushSize: 15, + threshold: 60, + onThreshold: () { + setState(() { + opacity = 1; + isScratched = true; + }); + widget.onScratch?.call(); + }, + child: Container( + child: widget.animation == null + ? icon + : ScaleTransition( + scale: widget.animation, + child: icon, + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/horizontal_explicit.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/horizontal_explicit.dart new file mode 100644 index 00000000..50dacbb8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/horizontal_explicit.dart @@ -0,0 +1,55 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/snaplist/snaplist_controller.dart'; +import 'package:flutter_helper/samples/snaplist/snaplist_view.dart'; + +class HorizontalExplicitTab extends StatelessWidget { + final List images; + final VoidCallback loadMore; + + const HorizontalExplicitTab({Key key, this.images, this.loadMore}) + : super(key: key); + + @override + Widget build(BuildContext context) { + final Size cardSize = Size(300.0, 460.0); + + final random = new Random(); + final controller = SnaplistController(initialPosition: 2); + return Stack( + children: [ + SnapList( + padding: EdgeInsets.only( + left: (MediaQuery.of(context).size.width - cardSize.width) / 2), + sizeProvider: (index, data) => cardSize, + separatorProvider: (index, data) => Size(10.0, 10.0), + positionUpdate: (int index) { + if (index == images.length - 1) { + loadMore(); + } + }, + builder: (context, index, data) { + return ClipRRect( + borderRadius: new BorderRadius.circular(16.0), + child: Image.network( + images[index], + fit: BoxFit.fill, + ), + ); + }, + count: images.length, + snaplistController: controller, + ), + Positioned( + child: FloatingActionButton( + onPressed: () => + controller.setPosition(random.nextInt(images.length)), + ), + bottom: 10, + right: 10, + ) + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/horziontal.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/horziontal.dart new file mode 100644 index 00000000..acad1fe7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/horziontal.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/snaplist/snaplist_view.dart'; + +class HorizontalTab extends StatelessWidget { + final List images; + final VoidCallback loadMore; + + const HorizontalTab({Key key, this.images, this.loadMore}) : super(key: key); + + @override + Widget build(BuildContext context) { + final Size cardSize = Size(300.0, 460.0); + return SnapList( + padding: EdgeInsets.only( + left: (MediaQuery.of(context).size.width - cardSize.width) / 2), + sizeProvider: (index, data) => cardSize, + separatorProvider: (index, data) => Size(10.0, 10.0), + positionUpdate: (int index) { + if (index == images.length - 1) { + loadMore(); + } + }, + builder: (context, index, data) { + return ClipRRect( + borderRadius: new BorderRadius.circular(16.0), + child: Image.network( + images[index], + fit: BoxFit.fill, + ), + ); + }, + count: images.length, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/main.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/main.dart new file mode 100644 index 00000000..d34f80e9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/main.dart @@ -0,0 +1,74 @@ +import './horizontal_explicit.dart'; +import './horziontal.dart'; +import './vertical.dart'; +import 'package:flutter/material.dart'; + +void main() => runApp(new SnapListApp()); + +class SnapListApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Snaplist Demo', + theme: new ThemeData( + primarySwatch: Colors.blue, + ), + home: new MyHomePage(), + ); + } +} + +class MyHomePage extends StatefulWidget { + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +class _MyHomePageState extends State { + List urls = [ + "https://image.tmdb.org/t/p/w370_and_h556_bestv2/2uNW4WbgBXL25BAbXGLnLqX71Sw.jpg", + "https://image.tmdb.org/t/p/w370_and_h556_bestv2/lNkDYKmrVem1J0aAfCnQlJOCKnT.jpg", + "https://image.tmdb.org/t/p/w370_and_h556_bestv2/wrFpXMNBRj2PBiN4Z5kix51XaIZ.jpg", + "https://image.tmdb.org/t/p/w370_and_h556_bestv2/r6pPUVUKU5eIpYj4oEzidk5ZibB.jpg", + "https://image.tmdb.org/t/p/w370_and_h556_bestv2/x1txcDXkcM65gl7w20PwYSxAYah.jpg", + "https://image.tmdb.org/t/p/w370_and_h556_bestv2/ptSrT1JwZFWGhjSpYUtJaasQrh.jpg", + "https://image.tmdb.org/t/p/w370_and_h556_bestv2/wMq9kQXTeQCHUZOG4fAe5cAxyUA.jpg", + "https://image.tmdb.org/t/p/w370_and_h556_bestv2/7WsyChQLEftFiDOVTGkv3hFpyyt.jpg", + ]; + + @override + Widget build(BuildContext context) { + return DefaultTabController( + child: Scaffold( + appBar: AppBar( + title: Text("Snaplist demo"), + bottom: TabBar(tabs: [ + Tab( + text: "Horizontal", + ), + Tab( + text: "Explicit", + ), + Tab(text: "Vertical") + ])), + body: TabBarView( + physics: NeverScrollableScrollPhysics(), + children: [ HorizontalTab( + images: urls, loadMore: _loadMoreItems, + ), + HorizontalExplicitTab( + images: urls, loadMore: _loadMoreItems, + ), + VerticalTab(images: urls, loadMore: _loadMoreItems) + ], + ), + ), + length: 3 + ); + } + + void _loadMoreItems() { + setState(() { + urls = new List.from(urls)..addAll(urls); + }); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/size_providers.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/size_providers.dart new file mode 100644 index 00000000..153955f4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/size_providers.dart @@ -0,0 +1,12 @@ +import 'package:flutter/widgets.dart'; + +typedef Size CardSizeProvider(int position, BuilderData data); +typedef Size SeparatorSizeProvider(int position, BuilderData data); + +class BuilderData { + final int center; + final int next; + final double progress; + + BuilderData(this.center, this.next, this.progress); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist.dart new file mode 100644 index 00000000..42b4304f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist.dart @@ -0,0 +1,4 @@ +library snaplist; + +export 'snaplist_view.dart'; +export 'snaplist_controller.dart'; \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_bloc.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_bloc.dart new file mode 100644 index 00000000..008c854f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_bloc.dart @@ -0,0 +1,249 @@ +import 'dart:async'; + +import 'package:flutter/widgets.dart'; +import 'package:flutter_helper/samples/snaplist/size_providers.dart'; +import 'package:flutter_helper/samples/snaplist/snaplist_events.dart'; + +class SnapListBloc { + int _itemsCount; + CardSizeProvider _sizeProvider; + SeparatorSizeProvider _separatorProvider; + double _swipeVelocity; + Axis _axis; + + int _centerItemPosition = 0; + int _nextItemPosition = -1; + + double _scrollOffset; + double _startPosition; + + double _scrollProgress; + + ScrollDirection _direction = ScrollDirection.NONE; + bool get _isVertical => _axis == Axis.vertical; + + StreamController _swipeStartController = StreamController(); + Sink get swipeStartSink => _swipeStartController.sink; + + StreamController _swipeUpdateController = StreamController(); + Sink get swipeUpdateSink => _swipeUpdateController.sink; + + StreamController _swipeEndController = StreamController(); + Sink get swipeEndSink => _swipeEndController.sink; + + StreamController _snipStartController = StreamController(); + Stream get snipStartStream => _snipStartController.stream; + + StreamController _snipUpdateController = StreamController(); + Sink get snipUpdateSink => _snipUpdateController.sink; + + StreamController _snipFinishController = StreamController(); + Sink get snipFinishSink => _snipFinishController.sink; + + StreamController _positionChangeController = + StreamController(); + Stream get positionStream => + _positionChangeController.stream; + + StreamController _explicitPositionChangeController = StreamController(); + Sink get explicitPositionChangeSink => + _explicitPositionChangeController.sink; + + StreamController _explicitPositionChangeStream = StreamController(); + Stream get explicitPositionChangeStream => + _explicitPositionChangeStream.stream; + + StreamController _offsetController = StreamController(); + Stream get offsetStream => _offsetController.stream; + + StreamController _itemCountController = StreamController(); + Sink get itemCountSink => _itemCountController.sink; + + StreamController _uiController = StreamController(); + Stream get uiStream => _uiController.stream; + + SnapListBloc( + {int itemsCount, sizeProvider, separatorProvider, axis, swipeVelocity}) { + initializeField( + itemsCount: itemsCount, + sizeProvider: sizeProvider, + axis: axis, + separatorProvider: separatorProvider, + swipeVelocity: swipeVelocity, + ); + + _swipeStartController.stream.listen((event) { + _direction = ScrollDirection.NONE; + + _scrollOffset = event.offset; + _startPosition = event.position; + + _scrollProgress = 0.0; + }); + + _swipeUpdateController.stream.listen((event) { + if (event.position < _startPosition) { + _direction = _isVertical ? ScrollDirection.DOWN : ScrollDirection.RIGHT; + _nextItemPosition = _centerItemPosition + 1; + } else { + _direction = _isVertical ? ScrollDirection.UP : ScrollDirection.LEFT; + _nextItemPosition = _centerItemPosition - 1; + } + + if (_nextItemPosition < 0 || _nextItemPosition >= _itemsCount) { + return; + } + + _scrollOffset = _scrollOffset - event.delta; + _scrollProgress = _calculateScrollProgress(event.position); + _offsetController.add(OffsetEvent(_scrollOffset, _scrollProgress, + _centerItemPosition, _nextItemPosition)); + + _uiController.add( + UiEvent(_centerItemPosition, _nextItemPosition, _scrollProgress)); + }); + + _swipeEndController.stream.listen((event) { + if (_swipeVelocity != 0.0 && + _swipeVelocity >= + (_isVertical ? event.vector.dy.abs() : event.vector.dx.abs()) && + _scrollProgress < 50) { + _scrollProgress = 100 - _scrollProgress; + _swipeNextAndCenter(); + _direction = ScrollDirection.NONE; + } + + if (_direction != null && + _nextItemPosition >= 0 && + _nextItemPosition < _itemsCount) { + _snipStartController.add(SnipStartEvent( + _scrollOffset, _calculateTargetOffset(), _scrollProgress)); + } + }); + + _snipUpdateController.stream.listen((event) { + _scrollProgress = event.progress; + _scrollOffset = event.snip; + + _offsetController.add(OffsetEvent(_scrollOffset, _scrollProgress, + _centerItemPosition, _nextItemPosition)); + _uiController.add( + UiEvent(_centerItemPosition, _nextItemPosition, _scrollProgress)); + }); + + _snipFinishController.stream.listen((event) { + _centerItemPosition = _nextItemPosition.clamp(0, _itemsCount - 1); + _nextItemPosition = -1; + _scrollProgress = 0.0; + + _positionChangeController.add(PositionChangeEvent(_centerItemPosition)); + }); + + _explicitPositionChangeController.stream.listen((position) { + _nextItemPosition = position.clamp(0, _itemsCount - 1); + _scrollProgress = 0.0; + + _explicitPositionChangeStream.add(_calculateTargetOffset()); + + _centerItemPosition = _nextItemPosition; + _nextItemPosition = -1; + }); + + _itemCountController.stream.listen((itemCount) { + _itemsCount = itemCount; + + if (_centerItemPosition >= _itemsCount - 1) { + _centerItemPosition = _itemsCount - 1; + _positionChangeController.add(PositionChangeEvent(_centerItemPosition)); + } + }); + } + + initializeField( + {itemsCount, sizeProvider, separatorProvider, axis, swipeVelocity}) { + _itemsCount = itemsCount ?? 0; + _sizeProvider = sizeProvider; + _separatorProvider = separatorProvider; + _axis = axis; + _swipeVelocity = swipeVelocity; + } + + _swipeNextAndCenter() { + final tmp = _centerItemPosition; + _centerItemPosition = _nextItemPosition; + _nextItemPosition = tmp; + } + + _calculateScrollProgress(double currentPosition) { + final distance = (_startPosition - currentPosition).abs(); + Size cardSize = _sizeProvider(_centerItemPosition, _createBuilderData()); + return ((distance * 100) / (_isVertical ? cardSize.height : cardSize.width)) + .clamp(0.0, 100.0); + } + + double _calculateTargetOffset() { + return calculateTargetOffset( + _centerItemPosition, _nextItemPosition, _isVertical, _sizeProvider, _separatorProvider, _createBuilderData()); + } + + _createBuilderData() { + return BuilderData(_centerItemPosition, _nextItemPosition, _scrollProgress); + } + + void onSwipingFinished() { + _centerItemPosition = _nextItemPosition; + _nextItemPosition = -1; + } + + void dispose() { + _itemCountController.close(); + + _swipeStartController.close(); + _swipeUpdateController.close(); + _swipeEndController.close(); + + _snipStartController.close(); + _snipUpdateController.close(); + _snipFinishController.close(); + + _positionChangeController.close(); + _offsetController.close(); + + _explicitPositionChangeController.close(); + _explicitPositionChangeStream.close(); + + _uiController.close(); + } +} + +double calculateTargetOffset( + int currentItem, + int calculateTo, + bool isVertical, + CardSizeProvider sizeProvider, + SeparatorSizeProvider separatorSizeProvider, + BuilderData builderData) { + double result = 0.0; + + for (var i = 1; i <= calculateTo; ++i) { + Size cardSize = sizeProvider( + i - 1, + BuilderData( + currentItem, + calculateTo, + 100.0, + )); + Size separatorSize = separatorSizeProvider(i - 1, builderData); + + if (isVertical) { + result += cardSize.height; + result += separatorSize.height; + } else { + result += cardSize.width; + result += separatorSize.width; + } + } + return result; +} + +enum ScrollDirection { RIGHT, NONE, LEFT, UP, DOWN } diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_controller.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_controller.dart new file mode 100644 index 00000000..0dc9d146 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_controller.dart @@ -0,0 +1,18 @@ +class SnaplistController { + + final int initialPosition; + + PositionChanged positionChanged; + + SnaplistController({ + this.initialPosition + }); + + setPosition(int position) { + if (positionChanged != null) { + positionChanged(position); + } + } +} + +typedef PositionChanged(int position); \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_events.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_events.dart new file mode 100644 index 00000000..57c80959 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_events.dart @@ -0,0 +1,59 @@ + +import 'dart:ui'; + +class StartEvent { + final double offset; + final double position; + + StartEvent(this.offset, this.position); +} +class UpdateEvent { + final double position; + final double delta; + + UpdateEvent(this.position, this.delta); +} +class EndEvent { + final Offset vector; + + EndEvent(this.vector); +} + +class SnipStartEvent { + final double offset; + final double targetOffset; + final double progress; + + SnipStartEvent(this.offset, this.targetOffset, this.progress); +} +class SnipUpdateEvent { + final double snip; + final double progress; + + SnipUpdateEvent(this.snip, this.progress); +} +class SnipFinishEvent {} + +class PositionChangeEvent { + final newPosition; + + PositionChangeEvent(this.newPosition); +} + +class OffsetEvent { + final double offset; + final double progress; + final int centerPosition; + final int nextPosition; + + OffsetEvent( + this.offset, this.progress, this.centerPosition, this.nextPosition); +} + +class UiEvent { + final int center; + final int next; + final double progress; + + UiEvent(this.center, this.next, this.progress); +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_view.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_view.dart new file mode 100644 index 00000000..ad198f02 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/snaplist_view.dart @@ -0,0 +1,281 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_helper/samples/snaplist/size_providers.dart'; +import 'package:flutter_helper/samples/snaplist/snaplist_bloc.dart'; +import 'package:flutter_helper/samples/snaplist/snaplist_controller.dart'; +import 'package:flutter_helper/samples/snaplist/snaplist_events.dart'; + +class SnapList extends StatefulWidget { + final SeparatorSizeProvider separatorProvider; + final CardSizeProvider sizeProvider; + final CardBuilder builder; + final int count; + + final ScrollProgressUpdate progressUpdate; + final PositionUpdate positionUpdate; + final ScrollStart scrollStart; + final Axis axis; + + final Duration snipDuration; + final Curve snipCurve; + + final EdgeInsets padding; + final Alignment alignment; + final double swipeVelocity; + + final SnaplistController snaplistController; + + SnapList({ + Key key, + @required this.sizeProvider, + @required this.builder, + @required this.separatorProvider, + @required this.count, + this.padding, + this.progressUpdate, + this.positionUpdate, + this.scrollStart, + this.axis = Axis.horizontal, + this.snipDuration, + this.snipCurve, + this.alignment = Alignment.center, + this.swipeVelocity = 0.0, + this.snaplistController, + }) : super(key: key) { + assert(this.sizeProvider != null); + assert(this.builder != null); + assert(this.separatorProvider != null); + assert(this.count != null); + } + + @override + State createState() => _SnapListState(); +} + +class _SnapListState extends State with TickerProviderStateMixin { + GlobalKey _listKey = GlobalKey(); + ScrollController _controller = ScrollController(); + + SnapListBloc bloc; + + AnimationController _snipController; + Tween _progressTween = Tween(); + Tween _snipTween = Tween(); + + @override + void initState() { + bloc = SnapListBloc( + itemsCount: widget.count, + sizeProvider: widget.sizeProvider, + axis: widget.axis, + separatorProvider: widget.separatorProvider, + swipeVelocity: widget.swipeVelocity); + + bloc.offsetStream.listen((event) { + _controller.jumpTo(event.offset); + _updateProgress(event.progress, event.centerPosition, event.nextPosition); + }); + + bloc.positionStream.listen((event) { + _updatePosition(event.newPosition); + }); + + bloc.snipStartStream.listen((event) { + _snipTween = Tween(begin: event.offset, end: event.targetOffset); + _progressTween = Tween(begin: event.progress, end: 100.0); + + _snipController.forward(from: 0.0); + }); + + bloc.explicitPositionChangeStream.listen((offset) { + print("new offset: $offset"); + _controller.jumpTo(offset); + }); + + _snipController = AnimationController( + vsync: this, + duration: widget.snipDuration ?? Duration(milliseconds: 300)) + ..addListener(() { + Animation resultAnimation = _snipController; + if (widget.snipCurve != null) { + resultAnimation = + CurvedAnimation(parent: _snipController, curve: widget.snipCurve); + } + final scrollProgress = _progressTween.evaluate(resultAnimation); + final snip = _snipTween.evaluate(resultAnimation); + bloc.snipUpdateSink.add(SnipUpdateEvent(snip, scrollProgress)); + }) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + bloc.snipFinishSink.add(SnipFinishEvent()); + } + }); + + widget.snaplistController?.positionChanged = (position) { + bloc.explicitPositionChangeSink.add(position); + }; + + if (widget.snaplistController?.initialPosition != null) { + bloc.explicitPositionChangeSink + .add(widget.snaplistController.initialPosition); + } + + super.initState(); + } + + _updateProgress( + double progress, int centerItemPosition, int nextItemPosition) { + if (widget.progressUpdate != null) { + widget.progressUpdate(progress, centerItemPosition, nextItemPosition); + } + } + + _updatePosition(int newPosition) { + if (widget.positionUpdate != null) { + widget.positionUpdate(newPosition); + } + } + + @override + void didUpdateWidget(SnapList oldWidget) { + bloc.itemCountSink.add(widget.count); + + super.didUpdateWidget(oldWidget); + bloc.initializeField( + itemsCount: widget.count, + sizeProvider: widget.sizeProvider, + axis: widget.axis, + separatorProvider: widget.separatorProvider, + swipeVelocity: widget.swipeVelocity, + ); + + widget.snaplistController?.positionChanged = (position) { + bloc.explicitPositionChangeSink.add(position); + }; + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + initialData: UiEvent(0, -1, 0.0), + stream: bloc.uiStream, + builder: (context, snapshot) { + UiEvent event = snapshot.data; + + if (isAnimating) { + return _buildList(event.center, event.next, event.progress); + } + if (widget.axis == Axis.vertical) { + return GestureDetector( + onVerticalDragStart: _onVerticalStart, + onVerticalDragUpdate: _onVerticalUpdate, + onVerticalDragEnd: _onVerticalEnd, + child: _buildList(event.center, event.next, event.progress), + ); + } else { + return GestureDetector( + onHorizontalDragStart: _onHorizontalStart, + onHorizontalDragUpdate: _onHorizontalUpdate, + onHorizontalDragEnd: _onHorizontalEnd, + child: _buildList(event.center, event.next, event.progress), + ); + } + }, + ); + } + + _buildList(int center, int next, double progress) { + return ListView.separated( + key: _listKey, + padding: widget.padding, + scrollDirection: widget.axis, + physics: NeverScrollableScrollPhysics(), + controller: _controller, + separatorBuilder: (context, index) { + if (widget.axis == Axis.vertical) { + return SizedBox( + height: widget + .separatorProvider(index, BuilderData(center, next, progress)) + .height, + ); + } else { + return SizedBox( + width: widget + .separatorProvider(index, BuilderData(center, next, progress)) + .width, + ); + } + }, + itemBuilder: (context, index) { + final builderData = BuilderData(center, next, progress); + final size = widget.sizeProvider(index, builderData); + return Align( + alignment: widget.alignment, + child: SizedBox.fromSize( + size: size, + child: widget.builder( + context, + index, + builderData, + ), + ), + ); + }, + itemCount: widget.count); + } + + @override + void dispose() { + bloc.dispose(); + _controller.dispose(); + _snipController.dispose(); + super.dispose(); + } + + void _onHorizontalStart(DragStartDetails details) { + bloc.swipeStartSink + .add(StartEvent(_controller.offset, details.globalPosition.dx)); + + if (widget.scrollStart != null) { + widget.scrollStart(); + } + } + + void _onHorizontalUpdate(DragUpdateDetails details) { + bloc.swipeUpdateSink + .add(UpdateEvent(details.globalPosition.dx, details.delta.dx)); + } + + void _onHorizontalEnd(DragEndDetails details) { + bloc.swipeEndSink.add(EndEvent(details.velocity.pixelsPerSecond)); + } + + void _onVerticalStart(DragStartDetails details) { + bloc.swipeStartSink + .add(StartEvent(_controller.offset, details.globalPosition.dy)); + + if (widget.scrollStart != null) { + widget.scrollStart(); + } + } + + void _onVerticalUpdate(DragUpdateDetails details) { + bloc.swipeUpdateSink + .add(UpdateEvent(details.globalPosition.dy, details.delta.dy)); + } + + void _onVerticalEnd(DragEndDetails details) { + bloc.swipeEndSink.add(EndEvent(details.velocity.pixelsPerSecond)); + } + + bool get isAnimating => _snipController.isAnimating; +} + +typedef Widget CardBuilder( + BuildContext context, + int position, + BuilderData data, +); + +typedef ScrollStart(); +typedef void ScrollProgressUpdate(double progress, int center, int next); +typedef void PositionUpdate(int center); diff --git a/FlutterHelper/flutter_helper/lib/samples/snaplist/vertical.dart b/FlutterHelper/flutter_helper/lib/samples/snaplist/vertical.dart new file mode 100644 index 00000000..897cda35 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/snaplist/vertical.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/snaplist/snaplist_view.dart'; + +class VerticalTab extends StatelessWidget { + final List images; + final VoidCallback loadMore; + + const VerticalTab({Key key, this.images, this.loadMore}) : super(key: key); + + @override + Widget build(BuildContext context) { + final Size cardSize = Size(250.0, 250.0); + return SnapList( + padding: EdgeInsets.only( + top: (MediaQuery.of(context).size.height - 180 - cardSize.height) / 2), + sizeProvider: (index, data) => cardSize, + separatorProvider: (index, data) => Size(50.0, 50.0), + positionUpdate: (int index){ + if(index==images.length-1){ + loadMore(); + } + }, + builder: (context, index, data) { + return ClipOval( + child: Image.network( + images[index], + fit: BoxFit.cover, + ), + ); + }, + count: images.length, + axis: Axis.vertical, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_1.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_1.dart new file mode 100644 index 00000000..0ac20d28 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_1.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +const List _staggeredTiles = [ + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + StaggeredTile.count(1, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(2, 2), + StaggeredTile.count(1, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(3, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(4, 1), +]; + +const List _tiles = [ + _Example01Tile(Colors.green, Icons.widgets), + _Example01Tile(Colors.lightBlue, Icons.wifi), + _Example01Tile(Colors.amber, Icons.panorama_wide_angle), + _Example01Tile(Colors.brown, Icons.map), + _Example01Tile(Colors.deepOrange, Icons.send), + _Example01Tile(Colors.indigo, Icons.airline_seat_flat), + _Example01Tile(Colors.red, Icons.bluetooth), + _Example01Tile(Colors.pink, Icons.battery_alert), + _Example01Tile(Colors.purple, Icons.desktop_windows), + _Example01Tile(Colors.blue, Icons.radio), +]; + +class Example01 extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('example 01'), + ), + body: Padding( + padding: const EdgeInsets.only(top: 12), + child: StaggeredGridView.count( + crossAxisCount: 4, + staggeredTiles: _staggeredTiles, + mainAxisSpacing: 4, + crossAxisSpacing: 4, + padding: const EdgeInsets.all(4), + children: _tiles, + ))); + } +} + +class _Example01Tile extends StatelessWidget { + const _Example01Tile(this.backgroundColor, this.iconData); + + final Color backgroundColor; + final IconData iconData; + + @override + Widget build(BuildContext context) { + return Card( + color: backgroundColor, + child: InkWell( + onTap: () {}, + child: Center( + child: Padding( + padding: const EdgeInsets.all(4), + child: Icon( + iconData, + color: Colors.white, + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_2.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_2.dart new file mode 100644 index 00000000..67a6ac86 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_2.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +class Example02 extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('example 02'), + ), + body: Padding( + padding: const EdgeInsets.all(4), + child: StaggeredGridView.countBuilder( + crossAxisCount: 4, + itemCount: 8, + itemBuilder: (BuildContext context, int index) => Container( + color: Colors.green, + child: Center( + child: CircleAvatar( + backgroundColor: Colors.white, + child: Text('$index'), + ), + )), + staggeredTileBuilder: (int index) => + StaggeredTile.count(2, index.isEven ? 2 : 1), + mainAxisSpacing: 4, + crossAxisSpacing: 4, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_3.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_3.dart new file mode 100644 index 00000000..84248f24 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_3.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +class Example03 extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('staggeredGridView.count'), + ), + body: StaggeredGridView.count( + primary: false, + crossAxisCount: 4, + mainAxisSpacing: 4, + crossAxisSpacing: 4, + staggeredTiles: const [ + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + ], + children: const [ + Text('1'), + Text('2'), + Text('3'), + Text('4'), + Text('5'), + Text('6'), + Text('7'), + Text('8'), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_4.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_4.dart new file mode 100644 index 00000000..3d376c2e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_4.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +class Example04 extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('customScrollView'), + ), + body: CustomScrollView( + primary: false, + slivers: [ + SliverStaggeredGrid.count( + crossAxisCount: 4, + mainAxisSpacing: 4, + crossAxisSpacing: 4, + staggeredTiles: const [ + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + StaggeredTile.count(2, 2), + StaggeredTile.count(2, 1), + ], + children: const [ + Text('1'), + Text('2'), + Text('3'), + Text('4'), + Text('5'), + Text('6'), + Text('7'), + Text('8'), + ], + ) + ], + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_5.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_5.dart new file mode 100644 index 00000000..f5522ca8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_5.dart @@ -0,0 +1,69 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +const List _kColors = [ + Colors.green, + Colors.blue, + Colors.red, + Colors.pink, + Colors.indigo, + Colors.purple, + Colors.blueGrey, +]; + +List _generateRandomTiles(int count) { + final rnd = Random(); + return List.generate( + count, + (i) => StaggeredTile.count( + rnd.nextInt(4) + 1, rnd.nextInt(6).toDouble() + 1)); +} + +List _generateRandomColors(int count) { + final rnd = Random(); + return List.generate(count, (i) => _kColors[rnd.nextInt(_kColors.length)]); +} + +class Example05 extends StatelessWidget { + Example05() + : _tiles = _generateRandomTiles(_kItemCount).toList(), + _colors = _generateRandomColors(_kItemCount).toList(); + + static const int _kItemCount = 1000; + final List _tiles; + final List _colors; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('random tiles'), + ), + body: StaggeredGridView.countBuilder( + primary: false, + crossAxisCount: 4, + crossAxisSpacing: 4, + mainAxisSpacing: 4, + staggeredTileBuilder: _getTile, + itemBuilder: _getChild, + itemCount: _kItemCount, + )); + } + + StaggeredTile _getTile(int index) => _tiles[index]; + + Widget _getChild(BuildContext context, int index) { + return Container( + key: ObjectKey('$index'), + color: _colors[index], + child: Center( + child: CircleAvatar( + backgroundColor: Colors.white, + child: Text('$index'), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_6.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_6.dart new file mode 100644 index 00000000..48d40546 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_6.dart @@ -0,0 +1,203 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +class Example06 extends StatefulWidget { + @override + _Example06State createState() => _Example06State(); +} + +class _Example06State extends State { + _Example06State() : crossAxisCount = 4; + final List _sizes = [ + 1, + 2, + 3, + 1, + 2, + 1, + 1, + 1, + 2, + 4, + 2, + 1, + 1, + 2, + 3, + 1, + 2, + 4, + ]; + + int _selectedIndex; + + final int crossAxisCount; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('dynamic resizing'), + ), + body: Padding( + padding: const EdgeInsets.all(4), + child: StaggeredGridView.countBuilder( + crossAxisCount: crossAxisCount, + itemCount: _sizes.length, + itemBuilder: (BuildContext context, int index) => _Example06Tile( + key: ObjectKey(index), + index: index, + size: _sizes[index], + onSizeDown: _handleSizeDown, + onSizeUp: _handleSizeUp, + onSelectedItemChanged: _handleSelectedItemChanged, + maxSize: crossAxisCount, + isSelected: _selectedIndex == index, + ), + staggeredTileBuilder: (int index) => + StaggeredTile.count(_sizes[index], _sizes[index].toDouble()), + mainAxisSpacing: 4, + crossAxisSpacing: 4, + ), + ), + ); + } + + void _handleSizeDown(int index) { + final currentSize = _sizes[index]; + if (currentSize > 0) { + setState(() { + _sizes[index] = currentSize - 1; + }); + } + } + + void _handleSizeUp(int index) { + final currentSize = _sizes[index]; + if (currentSize < crossAxisCount) { + setState(() { + _sizes[index] = currentSize + 1; + }); + } + } + + void _handleSelectedItemChanged(int index) { + setState(() { + _selectedIndex = _selectedIndex == index ? null : index; + }); + } +} + +class _Example06Tile extends StatelessWidget { + const _Example06Tile({ + Key key, + @required this.index, + @required this.size, + @required this.onSizeDown, + @required this.onSizeUp, + @required this.onSelectedItemChanged, + @required this.maxSize, + @required this.isSelected, + }) : super(key: key); + + final int index; + final int size; + final ValueChanged onSizeDown; + final ValueChanged onSizeUp; + final ValueChanged onSelectedItemChanged; + final int maxSize; + final bool isSelected; + + @override + Widget build(BuildContext context) { + final List widgets = [ + Padding( + padding: EdgeInsets.all(isSelected ? 8.0 : 0.0), + child: Card( + color: Colors.green, + child: InkWell( + onLongPress: () => onSelectedItemChanged(index), + child: Center( + child: CircleAvatar( + backgroundColor: Colors.white, + child: Text('$index'), + ), + ), + ), + ), + ), + ]; + + if (isSelected) { + widgets.add(_buildTileButton(_kCloseTileButton)); + + if (size > 1) { + widgets.add(_buildTileButton(_kSizeDownTileButton)); + } + + if (size < maxSize) { + widgets.add(_buildTileButton(_kSizeUpTileButton)); + } + } + + return Stack(children: widgets); + } + + Widget _buildTileButton(_TileButton tileButton) { + return Positioned( + top: tileButton.top, + bottom: tileButton.bottom, + left: tileButton.left, + right: tileButton.right, + child: GestureDetector( + onTap: () => tileButton.onTap(this), + child: CircleAvatar( + radius: 16, + backgroundColor: Colors.teal, + child: Text(tileButton.text), + ), + ), + ); + } +} + +final _TileButton _kSizeDownTileButton = _TileButton( + text: '-', + isLeft: true, + isTop: false, + onTap: (_Example06Tile tile) => tile.onSizeDown(tile.index), +); + +final _TileButton _kSizeUpTileButton = _TileButton( + text: '+', + isLeft: false, + isTop: false, + onTap: (_Example06Tile tile) => tile.onSizeUp(tile.index), +); + +final _TileButton _kCloseTileButton = _TileButton( + text: 'x', + isLeft: false, + isTop: true, + onTap: (_Example06Tile tile) => tile.onSelectedItemChanged(tile.index), +); + +class _TileButton { + const _TileButton({ + @required this.text, + @required this.onTap, + @required bool isLeft, + @required bool isTop, + }) : bottom = isTop ? null : 0.0, + top = isTop ? 0.0 : null, + left = isLeft ? 0.0 : null, + right = isLeft ? null : 0.0; + + final double bottom; + final double top; + final double left; + final double right; + final String text; + final ValueChanged<_Example06Tile> onTap; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_7.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_7.dart new file mode 100644 index 00000000..0a79f3a5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_7.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +class Example07 extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('dynamic tile sizes'), + ), + body: StaggeredGridView.count( + primary: false, + crossAxisCount: 4, + staggeredTiles: const [ + StaggeredTile.fit(2), + StaggeredTile.fit(2), + StaggeredTile.fit(1), + StaggeredTile.fit(3), + StaggeredTile.fit(3), + StaggeredTile.fit(1), + StaggeredTile.fit(2), + StaggeredTile.fit(2), + ], + children: const [ + _Tile( + 'https://cdn.pixabay.com/photo/2013/04/07/21/30/croissant-101636_960_720.jpg', + 1), + _Tile( + 'https://cdn.pixabay.com/photo/2016/01/22/16/42/eiffel-tower-1156146_960_720.jpg', + 2), + _Tile( + 'https://cdn.pixabay.com/photo/2016/10/22/20/34/two-types-of-wine-1761613_960_720.jpg', + 3), + _Tile( + 'https://cdn.pixabay.com/photo/2016/10/21/14/50/plouzane-1758197_960_720.jpg', + 4), + _Tile( + 'https://cdn.pixabay.com/photo/2016/11/16/10/59/mountains-1828596_960_720.jpg', + 5), + _Tile( + 'https://cdn.pixabay.com/photo/2013/04/13/18/42/the-eiffel-tower-103417_960_720.jpg', + 6), + _Tile( + 'https://cdn.pixabay.com/photo/2017/08/24/22/37/gyrfalcon-2678684_960_720.jpg', + 7), + _Tile( + 'https://cdn.pixabay.com/photo/2013/01/17/08/25/sunset-75159_960_720.jpg', + 8), + ], + ), + ); + } +} + +class _Tile extends StatelessWidget { + const _Tile(this.source, this.index); + + final String source; + final int index; + + @override + Widget build(BuildContext context) { + return Card( + child: Column( + children: [ + Image.network(source), + Padding( + padding: const EdgeInsets.all(4), + child: Column( + children: [ + Text( + 'Image number $index', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + const Text( + 'Vincent Van Gogh', + style: TextStyle(color: Colors.grey), + ), + ], + ), + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_8.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_8.dart new file mode 100644 index 00000000..b09917ea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_8.dart @@ -0,0 +1,156 @@ +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +final Uint8List kTransparentImage = Uint8List.fromList([ + 0x89, + 0x50, + 0x4E, + 0x47, + 0x0D, + 0x0A, + 0x1A, + 0x0A, + 0x00, + 0x00, + 0x00, + 0x0D, + 0x49, + 0x48, + 0x44, + 0x52, + 0x00, + 0x00, + 0x00, + 0x01, + 0x00, + 0x00, + 0x00, + 0x01, + 0x08, + 0x06, + 0x00, + 0x00, + 0x00, + 0x1F, + 0x15, + 0xC4, + 0x89, + 0x00, + 0x00, + 0x00, + 0x0A, + 0x49, + 0x44, + 0x41, + 0x54, + 0x78, + 0x9C, + 0x63, + 0x00, + 0x01, + 0x00, + 0x00, + 0x05, + 0x00, + 0x01, + 0x0D, + 0x0A, + 0x2D, + 0xB4, + 0x00, + 0x00, + 0x00, + 0x00, + 0x49, + 0x45, + 0x4E, + 0x44, + 0xAE, +]); + +List _createSizes(int count) { + final rnd = Random(); + return List.generate( + count, (i) => IntSize(rnd.nextInt(500) + 200, rnd.nextInt(800) + 200)); +} + +class Example08 extends StatelessWidget { + Example08() : _sizes = _createSizes(_kItemCount).toList(); + + static const int _kItemCount = 1000; + final List _sizes; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('random dynamic tile sizes'), + ), + body: StaggeredGridView.countBuilder( + primary: false, + crossAxisCount: 4, + mainAxisSpacing: 4, + crossAxisSpacing: 4, + itemBuilder: (context, index) => _Tile(index, _sizes[index]), + staggeredTileBuilder: (index) => const StaggeredTile.fit(2), + ), + ); + } +} + +class IntSize { + const IntSize(this.width, this.height); + + final int width; + final int height; +} + +class _Tile extends StatelessWidget { + const _Tile(this.index, this.size); + + final IntSize size; + final int index; + + @override + Widget build(BuildContext context) { + return Card( + child: Column( + children: [ + Stack( + children: [ + //Center(child: CircularProgressIndicator()), + Center( + child: FadeInImage.memoryNetwork( + placeholder: kTransparentImage, + image: 'https://picsum.photos/${size.width}/${size.height}/', + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(4), + child: Column( + children: [ + Text( + 'Image number $index', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + Text( + 'Width: ${size.width}', + style: const TextStyle(color: Colors.grey), + ), + Text( + 'Height: ${size.height}', + style: const TextStyle(color: Colors.grey), + ), + ], + ), + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/example_tests.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_tests.dart new file mode 100644 index 00000000..eccb5c67 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/example_tests.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +class ExampleTests extends StatelessWidget { + ExampleTests() : products = List.generate(50, (i) => Product('test $i')); + + final List products; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('random dynamic tile sizes'), + ), + body: CustomScrollView( + slivers: [ + SliverStaggeredGrid.countBuilder( + crossAxisCount: 2, + staggeredTileBuilder: (_) => const StaggeredTile.fit(1), + itemBuilder: (context, index) => ProductGridItem( + products[index], + ), + itemCount: products.length, + ), + ], + )); + } +} + +class Leaf extends StatefulWidget { + const Leaf({Key key, this.child}) : super(key: key); + final Widget child; + @override + _LeafState createState() => _LeafState(); +} + +class _LeafState extends State { + bool _keepAlive = false; + KeepAliveHandle _handle; + + @override + void deactivate() { + _handle?.release(); + _handle = null; + super.deactivate(); + } + + void setKeepAlive(bool value) { + _keepAlive = value; + if (_keepAlive) { + if (_handle == null) { + _handle = KeepAliveHandle(); + KeepAliveNotification(_handle).dispatch(context); + } + } else { + _handle?.release(); + _handle = null; + } + } + + @override + Widget build(BuildContext context) { + if (_keepAlive && _handle == null) { + _handle = KeepAliveHandle(); + KeepAliveNotification(_handle).dispatch(context); + } + return widget.child; + } +} + +class Product { + const Product(this.name); + final String name; +} + +class ProductGridItem extends StatelessWidget { + const ProductGridItem(this.product); + + final Product product; + + @override + Widget build(BuildContext context) { + return Card( + child: Container( + color: Colors.blue, + height: 80, + child: Center( + child: Text(product.name), + ), + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/home.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/home.dart new file mode 100644 index 00000000..e71bc92d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/home.dart @@ -0,0 +1,143 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'routes.dart'; + +const List _tiles = [ + StaggeredTile.count(2, 0.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(2, 0.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(2, 0.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + //const StaggeredTile.count(1, 1), +]; + +List _children = const [ + HomeHeaderTile('Staggered layouts', Colors.indigo), + HomeTile( + 'count constructor\ncount tile', Colors.indigo, staggeredCountCountRoute), + HomeTile('extent constructor\ncount tile', Colors.indigo, + staggeredExtentCountRoute), + HomeTile('count constructor\nextent tile', Colors.indigo, + staggeredCountExtentRoute), + HomeTile('extent constructor\nextent tile', Colors.indigo, + staggeredExtentExtentRoute), + HomeHeaderTile('Spannable layouts', Colors.purple), + HomeTile( + 'count constructor\ncount tile', Colors.purple, spannableCountCountRoute), + HomeTile('extent constructor\ncount tile', Colors.purple, + spannableExtentCountRoute), + HomeTile('count constructor\nextent tile', Colors.purple, + spannableCountExtentRoute), + HomeTile('extent constructor\nextent tile', Colors.purple, + spannableExtentExtentRoute), + HomeHeaderTile('More examples', Colors.pink), + HomeTile('example 01', Colors.pink, example01), + HomeTile('example 02', Colors.pink, example02), + HomeTile('example 03', Colors.pink, example03), + HomeTile('example 04', Colors.pink, example04), + HomeTile('random tiles', Colors.pink, example05), + HomeTile('dynamic resizing', Colors.pink, example06), + HomeTile('dynamic tile sizes', Colors.pink, example07), + HomeTile('random dynamic tile sizes', Colors.pink, example08), + //HomeTile('test', Colors.pink, exampleTests), +]; + +class Home extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('StaggeredGridView Demo'), + ), + body: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: StaggeredGridView.count( + crossAxisCount: 2, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + staggeredTiles: _tiles, + children: _children, + ), + )); + } +} + +class HomeHeaderTile extends StatelessWidget { + const HomeHeaderTile(this.title, this.backgroundColor); + + final String title; + final Color backgroundColor; + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: backgroundColor, + ))), + child: Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + title, + textAlign: TextAlign.center, + style: Theme.of(context) + .primaryTextTheme + .headline6 + .copyWith(color: backgroundColor), + ), + ), + ), + ); + } +} + +class HomeTile extends StatelessWidget { + const HomeTile(this.title, this.backgroundColor, this.route); + + final String title; + final String route; + final Color backgroundColor; + + @override + Widget build(BuildContext context) { + return Card( + color: backgroundColor, + child: InkWell( + onTap: () => Navigator.of(context).pushNamed(route), + child: Center( + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + title, + textAlign: TextAlign.center, + style: Theme.of(context).primaryTextTheme.headline6.copyWith( + color: + ThemeData.estimateBrightnessForColor(backgroundColor) == + Brightness.dark + ? Colors.white + : Colors.black), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/flutter_staggered_grid_view.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/flutter_staggered_grid_view.dart new file mode 100644 index 00000000..9769f21d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/flutter_staggered_grid_view.dart @@ -0,0 +1,9 @@ +library flutter_staggered_grid_view; + +export 'package:flutter_staggered_grid_view/src/rendering/sliver_staggered_grid.dart'; +export 'package:flutter_staggered_grid_view/src/rendering/sliver_variable_size_box_adaptor.dart'; +export 'package:flutter_staggered_grid_view/src/rendering/tile_container_render_object_mixin.dart'; + +export 'package:flutter_staggered_grid_view/src/widgets/sliver.dart'; +export 'package:flutter_staggered_grid_view/src/widgets/staggered_grid_view.dart'; +export 'package:flutter_staggered_grid_view/src/widgets/staggered_tile.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/sliver_staggered_grid.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/sliver_staggered_grid.dart new file mode 100644 index 00000000..5df41663 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/sliver_staggered_grid.dart @@ -0,0 +1,787 @@ +import 'dart:collection'; +import 'dart:math' as math; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; + +import 'package:flutter_staggered_grid_view/src/widgets/staggered_tile.dart'; +import 'package:flutter_staggered_grid_view/src/rendering/sliver_variable_size_box_adaptor.dart'; + +/// Signature for a function that creates [StaggeredTile] for a given index. +typedef IndexedStaggeredTileBuilder = StaggeredTile Function(int index); + +/// Specifies how a staggered grid is configured. +@immutable +class StaggeredGridConfiguration { + /// Creates an object that holds the configuration of a staggered grid. + const StaggeredGridConfiguration({ + @required this.crossAxisCount, + @required this.staggeredTileBuilder, + @required this.cellExtent, + @required this.mainAxisSpacing, + @required this.crossAxisSpacing, + @required this.reverseCrossAxis, + @required this.staggeredTileCount, + this.mainAxisOffsetsCacheSize = 3, + }) : assert(crossAxisCount > 0), + assert(cellExtent >= 0), + assert(mainAxisSpacing >= 0), + assert(crossAxisSpacing >= 0), + assert(mainAxisOffsetsCacheSize > 0), + cellStride = cellExtent + crossAxisSpacing; + + /// The maximum number of children in the cross axis. + final int crossAxisCount; + + /// The number of pixels from the leading edge of one cell to the trailing + /// edge of the same cell in both axis. + final double cellExtent; + + /// The number of logical pixels between each child along the main axis. + final double mainAxisSpacing; + + /// The number of logical pixels between each child along the cross axis. + final double crossAxisSpacing; + + /// Called to get the tile at the specified index for the + /// [SliverGridStaggeredTileLayout]. + final IndexedStaggeredTileBuilder staggeredTileBuilder; + + /// The total number of tiles this delegate can provide. + /// + /// If null, the number of tiles is determined by the least index for which + /// [builder] returns null. + final int staggeredTileCount; + + /// Whether the children should be placed in the opposite order of increasing + /// coordinates in the cross axis. + /// + /// For example, if the cross axis is horizontal, the children are placed from + /// left to right when [reverseCrossAxis] is false and from right to left when + /// [reverseCrossAxis] is true. + /// + /// Typically set to the return value of [axisDirectionIsReversed] applied to + /// the [SliverConstraints.crossAxisDirection]. + final bool reverseCrossAxis; + + final double cellStride; + + /// The number of pages necessary to cache a mainAxisOffsets value. + final int mainAxisOffsetsCacheSize; + + List generateMainAxisOffsets() => + List.generate(crossAxisCount, (i) => 0.0); + + /// Gets a normalized tile for the given index. + StaggeredTile getStaggeredTile(int index) { + StaggeredTile tile; + if (staggeredTileCount == null || index < staggeredTileCount) { + // There is maybe a tile for this index. + tile = _normalizeStaggeredTile(staggeredTileBuilder(index)); + } + return tile; + } + + /// Computes the main axis extent of any staggered tile. + double _getStaggeredTileMainAxisExtent(StaggeredTile tile) { + return tile.mainAxisExtent ?? + (tile.mainAxisCellCount * cellExtent) + + (tile.mainAxisCellCount - 1) * mainAxisSpacing; + } + + /// Creates a staggered tile with the computed extent from the given tile. + StaggeredTile _normalizeStaggeredTile(StaggeredTile staggeredTile) { + if (staggeredTile == null) { + return null; + } else { + final crossAxisCellCount = + staggeredTile.crossAxisCellCount.clamp(0, crossAxisCount).toInt(); + if (staggeredTile.fitContent) { + return StaggeredTile.fit(crossAxisCellCount); + } else { + return StaggeredTile.extent( + crossAxisCellCount, _getStaggeredTileMainAxisExtent(staggeredTile)); + } + } + } +} + +class _Block { + const _Block(this.index, this.crossAxisCount, this.minOffset, this.maxOffset); + + final int index; + final int crossAxisCount; + final double minOffset; + final double maxOffset; +} + +const double _epsilon = 0.0001; + +bool _nearEqual(double d1, double d2) { + return (d1 - d2).abs() < _epsilon; +} + +/// Describes the placement of a child in a [RenderSliverStaggeredGrid]. +/// +/// See also: +/// +/// * [RenderSliverStaggeredGrid], which uses this class during its +/// [RenderSliverStaggeredGrid.performLayout] method. +@immutable +class SliverStaggeredGridGeometry { + /// Creates an object that describes the placement of a child in a [RenderSliverStaggeredGrid]. + const SliverStaggeredGridGeometry({ + @required this.scrollOffset, + @required this.crossAxisOffset, + @required this.mainAxisExtent, + @required this.crossAxisExtent, + @required this.crossAxisCellCount, + @required this.blockIndex, + }); + + /// The scroll offset of the leading edge of the child relative to the leading + /// edge of the parent. + final double scrollOffset; + + /// The offset of the child in the non-scrolling axis. + /// + /// If the scroll axis is vertical, this offset is from the left-most edge of + /// the parent to the left-most edge of the child. If the scroll axis is + /// horizontal, this offset is from the top-most edge of the parent to the + /// top-most edge of the child. + final double crossAxisOffset; + + /// The extent of the child in the scrolling axis. + /// + /// If the scroll axis is vertical, this extent is the child's height. If the + /// scroll axis is horizontal, this extent is the child's width. + final double mainAxisExtent; + + /// The extent of the child in the non-scrolling axis. + /// + /// If the scroll axis is vertical, this extent is the child's width. If the + /// scroll axis is horizontal, this extent is the child's height. + final double crossAxisExtent; + + final int crossAxisCellCount; + + final int blockIndex; + + bool get hasTrailingScrollOffset => mainAxisExtent != null; + + /// The scroll offset of the trailing edge of the child relative to the + /// leading edge of the parent. + double get trailingScrollOffset => scrollOffset + (mainAxisExtent ?? 0); + + SliverStaggeredGridGeometry copyWith({ + double scrollOffset, + double crossAxisOffset, + double mainAxisExtent, + double crossAxisExtent, + int crossAxisCellCount, + int blockIndex, + }) { + return SliverStaggeredGridGeometry( + scrollOffset: scrollOffset ?? this.scrollOffset, + crossAxisOffset: crossAxisOffset ?? this.crossAxisOffset, + mainAxisExtent: mainAxisExtent ?? this.mainAxisExtent, + crossAxisExtent: crossAxisExtent ?? this.crossAxisExtent, + crossAxisCellCount: crossAxisCellCount ?? this.crossAxisCellCount, + blockIndex: blockIndex ?? this.blockIndex, + ); + } + + /// Returns a tight [BoxConstraints] that forces the child to have the + /// required size. + BoxConstraints getBoxConstraints(SliverConstraints constraints) { + return constraints.asBoxConstraints( + minExtent: mainAxisExtent ?? 0.0, + maxExtent: mainAxisExtent ?? double.infinity, + crossAxisExtent: crossAxisExtent, + ); + } + + @override + String toString() { + return 'SliverStaggeredGridGeometry(' + 'scrollOffset: $scrollOffset, ' + 'crossAxisOffset: $crossAxisOffset, ' + 'mainAxisExtent: $mainAxisExtent, ' + 'crossAxisExtent: $crossAxisExtent, ' + 'crossAxisCellCount: $crossAxisCellCount, ' + 'startIndex: $blockIndex)'; + } +} + +/// A sliver that places multiple box children in a two dimensional arrangement. +/// +/// [RenderSliverGrid] places its children in arbitrary positions determined by +/// [gridDelegate]. Each child is forced to have the size specified by the +/// [gridDelegate]. +/// +/// See also: +/// +/// * [RenderSliverList], which places its children in a linear +/// array. +/// * [RenderSliverFixedExtentList], which places its children in a linear +/// array with a fixed extent in the main axis. +class RenderSliverStaggeredGrid extends RenderSliverVariableSizeBoxAdaptor { + /// Creates a sliver that contains multiple box children that whose size and + /// position are determined by a delegate. + /// + /// The [configuration] and [childManager] arguments must not be null. + RenderSliverStaggeredGrid({ + @required RenderSliverVariableSizeBoxChildManager childManager, + @required SliverStaggeredGridDelegate gridDelegate, + }) : _gridDelegate = gridDelegate, + _pageSizeToViewportOffsets = + HashMap>(), + super(childManager: childManager); + + @override + void setupParentData(RenderObject child) { + if (child.parentData is! SliverVariableSizeBoxAdaptorParentData) { + final data = SliverVariableSizeBoxAdaptorParentData(); + + // By default we will keep it true. + //data.keepAlive = true; + child.parentData = data; + } + } + + /// The delegate that controls the configuration of the staggered grid. + SliverStaggeredGridDelegate get gridDelegate => _gridDelegate; + SliverStaggeredGridDelegate _gridDelegate; + + set gridDelegate(SliverStaggeredGridDelegate value) { + if (_gridDelegate == value) { + return; + } + if (value.runtimeType != _gridDelegate.runtimeType || + value.shouldRelayout(_gridDelegate)) { + markNeedsLayout(); + } + _gridDelegate = value; + } + + final HashMap> + _pageSizeToViewportOffsets; + + @override + void performLayout() { + childManager.didStartLayout(); + childManager.setDidUnderflow(false); + + final double scrollOffset = + constraints.scrollOffset + constraints.cacheOrigin; + assert(scrollOffset >= 0.0); + final double remainingExtent = constraints.remainingCacheExtent; + assert(remainingExtent >= 0.0); + final double targetEndScrollOffset = scrollOffset + remainingExtent; + + bool reachedEnd = false; + double trailingScrollOffset = 0; + double leadingScrollOffset = double.infinity; + bool visible = false; + int firstIndex = 0; + int lastIndex = 0; + + final configuration = _gridDelegate.getConfiguration(constraints); + + final pageSize = configuration.mainAxisOffsetsCacheSize * + constraints.viewportMainAxisExtent; + if (pageSize == 0.0) { + geometry = SliverGeometry.zero; + childManager.didFinishLayout(); + return; + } + final pageIndex = scrollOffset ~/ pageSize; + assert(pageIndex >= 0); + + // If the viewport is resized, we keep the in memory the old offsets caches. (Useful if only the orientation changes multiple times). + final viewportOffsets = _pageSizeToViewportOffsets.putIfAbsent( + pageSize, () => SplayTreeMap()); + + _ViewportOffsets viewportOffset; + if (viewportOffsets.isEmpty) { + viewportOffset = + _ViewportOffsets(configuration.generateMainAxisOffsets(), pageSize); + viewportOffsets[0] = viewportOffset; + } else { + final smallestKey = viewportOffsets.lastKeyBefore(pageIndex + 1); + viewportOffset = viewportOffsets[smallestKey]; + } + + // A staggered grid always have to layout the child from the zero-index based one to the last visible. + final mainAxisOffsets = viewportOffset.mainAxisOffsets.toList(); + final visibleIndices = HashSet(); + + // Iterate through all children while they can be visible. + for (var index = viewportOffset.firstChildIndex; + mainAxisOffsets.any((o) => o <= targetEndScrollOffset); + index++) { + SliverStaggeredGridGeometry geometry = + getSliverStaggeredGeometry(index, configuration, mainAxisOffsets); + if (geometry == null) { + // There are either no children, or we are past the end of all our children. + reachedEnd = true; + break; + } + + final bool hasTrailingScrollOffset = geometry.hasTrailingScrollOffset; + RenderBox child; + if (!hasTrailingScrollOffset) { + // Layout the child to compute its tailingScrollOffset. + final constraints = + BoxConstraints.tightFor(width: geometry.crossAxisExtent); + child = addAndLayoutChild(index, constraints, parentUsesSize: true); + geometry = geometry.copyWith(mainAxisExtent: paintExtentOf(child)); + } + + if (!visible && + targetEndScrollOffset >= geometry.scrollOffset && + scrollOffset <= geometry.trailingScrollOffset) { + visible = true; + leadingScrollOffset = geometry.scrollOffset; + firstIndex = index; + } + + if (visible && hasTrailingScrollOffset) { + child = + addAndLayoutChild(index, geometry.getBoxConstraints(constraints)); + } + + if (child != null) { + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + childParentData.layoutOffset = geometry.scrollOffset; + childParentData.crossAxisOffset = geometry.crossAxisOffset; + assert(childParentData.index == index); + } + + if (visible && indices.contains(index)) { + visibleIndices.add(index); + } + + if (geometry.trailingScrollOffset >= + viewportOffset.trailingScrollOffset) { + final nextPageIndex = viewportOffset.pageIndex + 1; + final nextViewportOffset = _ViewportOffsets(mainAxisOffsets, + (nextPageIndex + 1) * pageSize, nextPageIndex, index); + viewportOffsets[nextPageIndex] = nextViewportOffset; + viewportOffset = nextViewportOffset; + } + + final double endOffset = + geometry.trailingScrollOffset + configuration.mainAxisSpacing; + for (var i = 0; i < geometry.crossAxisCellCount; i++) { + mainAxisOffsets[i + geometry.blockIndex] = endOffset; + } + + trailingScrollOffset = mainAxisOffsets.reduce(math.max); + lastIndex = index; + } + + collectGarbage(visibleIndices); + + if (!visible) { + if (scrollOffset > viewportOffset.trailingScrollOffset) { + // We are outside the bounds, we have to correct the scroll. + final viewportOffsetScrollOffset = pageSize * viewportOffset.pageIndex; + final correction = viewportOffsetScrollOffset - scrollOffset; + geometry = SliverGeometry( + scrollOffsetCorrection: correction, + ); + } else { + geometry = SliverGeometry.zero; + childManager.didFinishLayout(); + } + return; + } + + double estimatedMaxScrollOffset; + if (reachedEnd) { + estimatedMaxScrollOffset = trailingScrollOffset; + } else { + estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset( + constraints, + firstIndex: firstIndex, + lastIndex: lastIndex, + leadingScrollOffset: leadingScrollOffset, + trailingScrollOffset: trailingScrollOffset, + ); + assert(estimatedMaxScrollOffset >= + trailingScrollOffset - leadingScrollOffset); + } + + final double paintExtent = calculatePaintOffset( + constraints, + from: leadingScrollOffset, + to: trailingScrollOffset, + ); + final double cacheExtent = calculateCacheOffset( + constraints, + from: leadingScrollOffset, + to: trailingScrollOffset, + ); + + geometry = SliverGeometry( + scrollExtent: estimatedMaxScrollOffset, + paintExtent: paintExtent, + cacheExtent: cacheExtent, + maxPaintExtent: estimatedMaxScrollOffset, + // Conservative to avoid flickering away the clip during scroll. + hasVisualOverflow: trailingScrollOffset > targetEndScrollOffset || + constraints.scrollOffset > 0.0, + ); + + // We may have started the layout while scrolled to the end, which would not + // expose a child. + if (estimatedMaxScrollOffset == trailingScrollOffset) { + childManager.setDidUnderflow(true); + } + childManager.didFinishLayout(); + } + + static SliverStaggeredGridGeometry getSliverStaggeredGeometry(int index, + StaggeredGridConfiguration configuration, List offsets) { + final tile = configuration.getStaggeredTile(index); + if (tile == null) { + return null; + } + + final block = _findFirstAvailableBlockWithCrossAxisCount( + tile.crossAxisCellCount, offsets); + + final scrollOffset = block.minOffset; + var blockIndex = block.index; + if (configuration.reverseCrossAxis) { + blockIndex = + configuration.crossAxisCount - tile.crossAxisCellCount - blockIndex; + } + final crossAxisOffset = blockIndex * configuration.cellStride; + final geometry = SliverStaggeredGridGeometry( + scrollOffset: scrollOffset, + crossAxisOffset: crossAxisOffset, + mainAxisExtent: tile.mainAxisExtent, + crossAxisExtent: configuration.cellStride * tile.crossAxisCellCount - + configuration.crossAxisSpacing, + crossAxisCellCount: tile.crossAxisCellCount, + blockIndex: block.index, + ); + return geometry; + } + + /// Finds the first available block with at least the specified [crossAxisCount] in the [offsets] list. + static _Block _findFirstAvailableBlockWithCrossAxisCount( + int crossAxisCount, List offsets) { + return _findFirstAvailableBlockWithCrossAxisCountAndOffsets( + crossAxisCount, List.from(offsets)); + } + + /// Finds the first available block with at least the specified [crossAxisCount]. + static _Block _findFirstAvailableBlockWithCrossAxisCountAndOffsets( + int crossAxisCount, List offsets) { + final block = _findFirstAvailableBlock(offsets); + if (block.crossAxisCount < crossAxisCount) { + // Not enough space for the specified cross axis count. + // We have to fill this block and try again. + for (var i = 0; i < block.crossAxisCount; ++i) { + offsets[i + block.index] = block.maxOffset; + } + return _findFirstAvailableBlockWithCrossAxisCountAndOffsets( + crossAxisCount, offsets); + } else { + return block; + } + } + + /// Finds the first available block for the specified [offsets] list. + static _Block _findFirstAvailableBlock(List offsets) { + int index = 0; + double minBlockOffset = double.infinity; + double maxBlockOffset = double.infinity; + int crossAxisCount = 1; + bool contiguous = false; + + // We have to use the _nearEqual function because of floating-point arithmetic. + // Ex: 0.1 + 0.2 = 0.30000000000000004 and not 0.3. + + for (var i = index; i < offsets.length; ++i) { + final offset = offsets[i]; + if (offset < minBlockOffset && !_nearEqual(offset, minBlockOffset)) { + index = i; + maxBlockOffset = minBlockOffset; + minBlockOffset = offset; + crossAxisCount = 1; + contiguous = true; + } else if (_nearEqual(offset, minBlockOffset) && contiguous) { + crossAxisCount++; + } else if (offset < maxBlockOffset && + offset > minBlockOffset && + !_nearEqual(offset, minBlockOffset)) { + contiguous = false; + maxBlockOffset = offset; + } else { + contiguous = false; + } + } + + return _Block(index, crossAxisCount, minBlockOffset, maxBlockOffset); + } +} + +class _ViewportOffsets { + _ViewportOffsets( + List mainAxisOffsets, + this.trailingScrollOffset, [ + this.pageIndex = 0, + this.firstChildIndex = 0, + ]) : mainAxisOffsets = mainAxisOffsets.toList(); + + final int pageIndex; + + final int firstChildIndex; + + final double trailingScrollOffset; + + final List mainAxisOffsets; + + @override + String toString() => + '[$pageIndex-$trailingScrollOffset] ($firstChildIndex, $mainAxisOffsets)'; +} + +/// Creates staggered grid layouts. +/// +/// This delegate creates grids with variable sized but equally spaced tiles. +/// +/// See also: +/// +/// * [StaggeredGridView], which can use this delegate to control the layout of its +/// tiles. +/// * [SliverStaggeredGrid], which can use this delegate to control the layout of its +/// tiles. +/// * [RenderSliverStaggeredGrid], which can use this delegate to control the layout of +/// its tiles. +abstract class SliverStaggeredGridDelegate { + /// Creates a delegate that makes staggered grid layouts + /// + /// All of the arguments must not be null. The [mainAxisSpacing] and + /// [crossAxisSpacing] arguments must not be negative. + const SliverStaggeredGridDelegate({ + @required this.staggeredTileBuilder, + this.mainAxisSpacing = 0, + this.crossAxisSpacing = 0, + this.staggeredTileCount, + }) : assert(mainAxisSpacing >= 0), + assert(crossAxisSpacing >= 0); + + /// The number of logical pixels between each child along the main axis. + final double mainAxisSpacing; + + /// The number of logical pixels between each child along the cross axis. + final double crossAxisSpacing; + + /// Called to get the tile at the specified index for the + /// [RenderSliverStaggeredGrid]. + final IndexedStaggeredTileBuilder staggeredTileBuilder; + + /// The total number of tiles this delegate can provide. + /// + /// If null, the number of tiles is determined by the least index for which + /// [builder] returns null. + final int staggeredTileCount; + + bool _debugAssertIsValid() { + assert(mainAxisSpacing >= 0); + assert(crossAxisSpacing >= 0); + return true; + } + + /// Returns information about the staggered grid configuration. + StaggeredGridConfiguration getConfiguration(SliverConstraints constraints); + + /// Override this method to return true when the children need to be + /// laid out. + /// + /// This should compare the fields of the current delegate and the given + /// `oldDelegate` and return true if the fields are such that the layout would + /// be different. + bool shouldRelayout(SliverStaggeredGridDelegate oldDelegate) { + return oldDelegate.mainAxisSpacing != mainAxisSpacing || + oldDelegate.crossAxisSpacing != crossAxisSpacing || + oldDelegate.staggeredTileCount != staggeredTileCount || + oldDelegate.staggeredTileBuilder != staggeredTileBuilder; + } +} + +/// Creates staggered grid layouts with a fixed number of cells in the cross +/// axis. +/// +/// For example, if the grid is vertical, this delegate will create a layout +/// with a fixed number of columns. If the grid is horizontal, this delegate +/// will create a layout with a fixed number of rows. +/// +/// This delegate creates grids with variable sized but equally spaced tiles. +/// +/// See also: +/// +/// * [SliverStaggeredGridDelegate], which creates staggered grid layouts. +/// * [StaggeredGridView], which can use this delegate to control the layout of its +/// tiles. +/// * [SliverStaggeredGrid], which can use this delegate to control the layout of its +/// tiles. +/// * [RenderSliverStaggeredGrid], which can use this delegate to control the layout of +/// its tiles. +class SliverStaggeredGridDelegateWithFixedCrossAxisCount + extends SliverStaggeredGridDelegate { + /// Creates a delegate that makes staggered grid layouts with a fixed number + /// of tiles in the cross axis. + /// + /// All of the arguments must not be null. The [mainAxisSpacing] and + /// [crossAxisSpacing] arguments must not be negative. The [crossAxisCount] + /// argument must be greater than zero. + const SliverStaggeredGridDelegateWithFixedCrossAxisCount({ + @required this.crossAxisCount, + @required IndexedStaggeredTileBuilder staggeredTileBuilder, + double mainAxisSpacing = 0, + double crossAxisSpacing = 0, + int staggeredTileCount, + }) : assert(crossAxisCount > 0), + super( + staggeredTileBuilder: staggeredTileBuilder, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileCount: staggeredTileCount, + ); + + /// The number of children in the cross axis. + final int crossAxisCount; + + @override + bool _debugAssertIsValid() { + assert(crossAxisCount > 0); + return super._debugAssertIsValid(); + } + + @override + StaggeredGridConfiguration getConfiguration(SliverConstraints constraints) { + assert(_debugAssertIsValid()); + final double usableCrossAxisExtent = + constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1); + final double cellExtent = usableCrossAxisExtent / crossAxisCount; + return StaggeredGridConfiguration( + crossAxisCount: crossAxisCount, + staggeredTileBuilder: staggeredTileBuilder, + staggeredTileCount: staggeredTileCount, + cellExtent: cellExtent, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), + ); + } + + @override + bool shouldRelayout( + covariant SliverStaggeredGridDelegateWithFixedCrossAxisCount + oldDelegate) { + return oldDelegate.crossAxisCount != crossAxisCount || + super.shouldRelayout(oldDelegate); + } +} + +/// Creates staggered grid layouts with tiles that each have a maximum +/// cross-axis extent. +/// +/// This delegate will select a cross-axis extent for the tiles that is as +/// large as possible subject to the following conditions: +/// +/// - The extent evenly divides the cross-axis extent of the grid. +/// - The extent is at most [maxCrossAxisExtent]. +/// +/// For example, if the grid is vertical, the grid is 500.0 pixels wide, and +/// [maxCrossAxisExtent] is 150.0, this delegate will create a grid with 4 +/// columns that are 125.0 pixels wide. +/// +/// This delegate creates grids with variable sized but equally spaced tiles. +/// +/// See also: +/// +/// * [SliverStaggeredGridDelegate], which creates staggered grid layouts. +/// * [StaggeredGridView], which can use this delegate to control the layout of its +/// tiles. +/// * [SliverStaggeredGrid], which can use this delegate to control the layout of its +/// tiles. +/// * [RenderSliverStaggeredGrid], which can use this delegate to control the layout of +/// its tiles. +class SliverStaggeredGridDelegateWithMaxCrossAxisExtent + extends SliverStaggeredGridDelegate { + /// Creates a delegate that makes staggered grid layouts with tiles that + /// have a maximum cross-axis extent. + /// + /// All of the arguments must not be null. The [maxCrossAxisExtent], + /// [mainAxisSpacing] and [crossAxisSpacing] arguments must not be negative. + const SliverStaggeredGridDelegateWithMaxCrossAxisExtent({ + @required this.maxCrossAxisExtent, + @required IndexedStaggeredTileBuilder staggeredTileBuilder, + double mainAxisSpacing = 0, + double crossAxisSpacing = 0, + int staggeredTileCount, + }) : assert(maxCrossAxisExtent > 0), + super( + staggeredTileBuilder: staggeredTileBuilder, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileCount: staggeredTileCount, + ); + + /// The maximum extent of tiles in the cross axis. + /// + /// This delegate will select a cross-axis extent for the tiles that is as + /// large as possible subject to the following conditions: + /// + /// - The extent evenly divides the cross-axis extent of the grid. + /// - The extent is at most [maxCrossAxisExtent]. + /// + /// For example, if the grid is vertical, the grid is 500.0 pixels wide, and + /// [maxCrossAxisExtent] is 150.0, this delegate will create a grid with 4 + /// columns that are 125.0 pixels wide. + final double maxCrossAxisExtent; + + @override + bool _debugAssertIsValid() { + assert(maxCrossAxisExtent >= 0); + return super._debugAssertIsValid(); + } + + @override + StaggeredGridConfiguration getConfiguration(SliverConstraints constraints) { + assert(_debugAssertIsValid()); + final int crossAxisCount = + ((constraints.crossAxisExtent + crossAxisSpacing) / + (maxCrossAxisExtent + crossAxisSpacing)) + .ceil(); + + final double usableCrossAxisExtent = + constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1); + + final double cellExtent = usableCrossAxisExtent / crossAxisCount; + return StaggeredGridConfiguration( + crossAxisCount: crossAxisCount, + staggeredTileBuilder: staggeredTileBuilder, + staggeredTileCount: staggeredTileCount, + cellExtent: cellExtent, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection), + ); + } + + @override + bool shouldRelayout( + covariant SliverStaggeredGridDelegateWithMaxCrossAxisExtent oldDelegate) { + return oldDelegate.maxCrossAxisExtent != maxCrossAxisExtent || + super.shouldRelayout(oldDelegate); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/sliver_variable_size_box_adaptor.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/sliver_variable_size_box_adaptor.dart new file mode 100644 index 00000000..ebfe8af5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/sliver_variable_size_box_adaptor.dart @@ -0,0 +1,510 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_staggered_grid_view/src/rendering/tile_container_render_object_mixin.dart'; + +/// A delegate used by [RenderSliverVariableSizeBoxAdaptor] to manage its children. +/// +/// [RenderSliverVariableSizeBoxAdaptor] objects reify their children lazily to avoid +/// spending resources on children that are not visible in the viewport. This +/// delegate lets these objects create and remove children as well as estimate +/// the total scroll offset extent occupied by the full child list. +abstract class RenderSliverVariableSizeBoxChildManager { + /// Called during layout when a new child is needed. The child should be + /// inserted into the child list in the appropriate position. Its index and + /// scroll offsets will automatically be set appropriately. + /// + /// The `index` argument gives the index of the child to show. It is possible + /// for negative indices to be requested. For example: if the user scrolls + /// from child 0 to child 10, and then those children get much smaller, and + /// then the user scrolls back up again, this method will eventually be asked + /// to produce a child for index -1. + /// + /// If no child corresponds to `index`, then do nothing. + /// + /// Which child is indicated by index zero depends on the [GrowthDirection] + /// specified in the [RenderSliverVariableSizeBoxAdaptor.constraints]. For example + /// if the children are the alphabet, then if + /// [SliverConstraints.growthDirection] is [GrowthDirection.forward] then + /// index zero is A, and index 25 is Z. On the other hand if + /// [SliverConstraints.growthDirection] is [GrowthDirection.reverse] + /// then index zero is Z, and index 25 is A. + /// + /// During a call to [createChild] it is valid to remove other children from + /// the [RenderSliverVariableSizeBoxAdaptor] object if they were not created during + /// this frame and have not yet been updated during this frame. It is not + /// valid to add any other children to this render object. + /// + /// If this method does not create a child for a given `index` greater than or + /// equal to zero, then [computeMaxScrollOffset] must be able to return a + /// precise value. + void createChild(int index); + + /// Remove the given child from the child list. + /// + /// Called by [RenderSliverVariableSizeBoxAdaptor.collectGarbage], which itself is + /// called from [RenderSliverVariableSizeBoxAdaptor.performLayout]. + /// + /// The index of the given child can be obtained using the + /// [RenderSliverVariableSizeBoxAdaptor.indexOf] method, which reads it from the + /// [SliverVariableSizeBoxAdaptorParentData.index] field of the child's + /// [RenderObject.parentData]. + void removeChild(RenderBox child); + + /// Called to estimate the total scrollable extents of this object. + /// + /// Must return the total distance from the start of the child with the + /// earliest possible index to the end of the child with the last possible + /// index. + double estimateMaxScrollOffset( + SliverConstraints constraints, { + int firstIndex, + int lastIndex, + double leadingScrollOffset, + double trailingScrollOffset, + }); + + /// Called to obtain a precise measure of the total number of children. + /// + /// Must return the number that is one greater than the greatest `index` for + /// which `createChild` will actually create a child. + /// + /// This is used when [createChild] cannot add a child for a positive `index`, + /// to determine the precise dimensions of the sliver. It must return an + /// accurate and precise non-null value. It will not be called if + /// [createChild] is always able to create a child (e.g. for an infinite + /// list). + int get childCount; + + /// Called during [RenderSliverVariableSizeBoxAdaptor.adoptChild]. + /// + /// Subclasses must ensure that the [SliverVariableSizeBoxAdaptorParentData.index] + /// field of the child's [RenderObject.parentData] accurately reflects the + /// child's index in the child list after this function returns. + void didAdoptChild(RenderBox child); + + /// Called during layout to indicate whether this object provided insufficient + /// children for the [RenderSliverVariableSizeBoxAdaptor] to fill the + /// [SliverConstraints.remainingPaintExtent]. + /// + /// Typically called unconditionally at the start of layout with false and + /// then later called with true when the [RenderSliverVariableSizeBoxAdaptor] + /// fails to create a child @required to fill the + /// [SliverConstraints.remainingPaintExtent]. + /// + /// Useful for subclasses to determine whether newly added children could + /// affect the visible contents of the [RenderSliverVariableSizeBoxAdaptor]. + // ignore: avoid_positional_boolean_parameters + void setDidUnderflow(bool value); + + /// Called at the beginning of layout to indicate that layout is about to + /// occur. + void didStartLayout() {} + + /// Called at the end of layout to indicate that layout is now complete. + void didFinishLayout() {} + + /// In debug mode, asserts that this manager is not expecting any + /// modifications to the [RenderSliverVariableSizeBoxAdaptor]'s child list. + /// + /// This function always returns true. + /// + /// The manager is not @required to track whether it is expecting modifications + /// to the [RenderSliverVariableSizeBoxAdaptor]'s child list and can simply return + /// true without making any assertions. + bool debugAssertChildListLocked() => true; +} + +/// Parent data structure used by [RenderSliverVariableSizeBoxAdaptor]. +class SliverVariableSizeBoxAdaptorParentData + extends SliverMultiBoxAdaptorParentData { + /// The offset of the child in the non-scrolling axis. + /// + /// If the scroll axis is vertical, this offset is from the left-most edge of + /// the parent to the left-most edge of the child. If the scroll axis is + /// horizontal, this offset is from the top-most edge of the parent to the + /// top-most edge of the child. + double crossAxisOffset; + + /// Whether the widget is currently in the + /// [RenderSliverVariableSizeBoxAdaptor._keepAliveBucket]. + bool _keptAlive = false; + + @override + String toString() => 'crossAxisOffset=$crossAxisOffset; ${super.toString()}'; +} + +/// A sliver with multiple variable size box children. +/// +/// [RenderSliverVariableSizeBoxAdaptor] is a base class for slivers that have multiple +/// variable size box children. The children are managed by a [RenderSliverBoxChildManager], +/// which lets subclasses create children lazily during layout. Typically +/// subclasses will create only those children that are actually needed to fill +/// the [SliverConstraints.remainingPaintExtent]. +/// +/// The contract for adding and removing children from this render object is +/// more strict than for normal render objects: +/// +/// * Children can be removed except during a layout pass if they have already +/// been laid out during that layout pass. +/// * Children cannot be added except during a call to [childManager], and +/// then only if there is no child corresponding to that index (or the child +/// child corresponding to that index was first removed). +/// +/// See also: +/// +/// * [RenderSliverToBoxAdapter], which has a single box child. +/// * [RenderSliverList], which places its children in a linear +/// array. +/// * [RenderSliverFixedExtentList], which places its children in a linear +/// array with a fixed extent in the main axis. +/// * [RenderSliverGrid], which places its children in arbitrary positions. +abstract class RenderSliverVariableSizeBoxAdaptor extends RenderSliver + with + TileContainerRenderObjectMixin, + RenderSliverWithKeepAliveMixin, + RenderSliverHelpers { + /// Creates a sliver with multiple box children. + /// + /// The [childManager] argument must not be null. + RenderSliverVariableSizeBoxAdaptor( + {@required RenderSliverVariableSizeBoxChildManager childManager}) + : _childManager = childManager; + + @override + void setupParentData(RenderObject child) { + if (child.parentData is! SliverVariableSizeBoxAdaptorParentData) { + child.parentData = SliverVariableSizeBoxAdaptorParentData(); + } + } + + /// The delegate that manages the children of this object. + /// + /// Rather than having a concrete list of children, a + /// [RenderSliverVariableSizeBoxAdaptor] uses a [RenderSliverVariableSizeBoxChildManager] to + /// create children during layout in order to fill the + /// [SliverConstraints.remainingPaintExtent]. + @protected + RenderSliverVariableSizeBoxChildManager get childManager => _childManager; + final RenderSliverVariableSizeBoxChildManager _childManager; + + /// The nodes being kept alive despite not being visible. + final Map _keepAliveBucket = {}; + + @override + void adoptChild(RenderObject child) { + super.adoptChild(child); + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + if (!childParentData._keptAlive) { + childManager.didAdoptChild(child as RenderBox); + } + } + + bool _debugAssertChildListLocked() => + childManager.debugAssertChildListLocked(); + + @override + void remove(int index) { + final RenderBox child = this[index]; + + // if child is null, it means this element was cached - drop the cached element + if (child == null) { + final RenderBox cachedChild = _keepAliveBucket[index]; + if (cachedChild != null) { + dropChild(cachedChild); + _keepAliveBucket.remove(index); + } + return; + } + + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + if (!childParentData._keptAlive) { + super.remove(index); + return; + } + assert(_keepAliveBucket[childParentData.index] == child); + _keepAliveBucket.remove(childParentData.index); + dropChild(child); + } + + @override + void removeAll() { + super.removeAll(); + _keepAliveBucket.values.forEach(dropChild); + _keepAliveBucket.clear(); + } + + void _createOrObtainChild(int index) { + invokeLayoutCallback((SliverConstraints constraints) { + assert(constraints == this.constraints); + if (_keepAliveBucket.containsKey(index)) { + final RenderBox child = _keepAliveBucket.remove(index); + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + assert(childParentData._keptAlive); + dropChild(child); + child.parentData = childParentData; + this[index] = child; + childParentData._keptAlive = false; + } else { + _childManager.createChild(index); + } + }); + } + + void _destroyOrCacheChild(int index) { + final RenderBox child = this[index]; + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + if (childParentData.keepAlive) { + assert(!childParentData._keptAlive); + remove(index); + _keepAliveBucket[childParentData.index] = child; + child.parentData = childParentData; + super.adoptChild(child); + childParentData._keptAlive = true; + } else { + assert(child.parent == this); + _childManager.removeChild(child); + assert(child.parent == null); + } + } + + @override + void attach(PipelineOwner owner) { + super.attach(owner); + _keepAliveBucket.values.forEach((child) => child.attach(owner)); + } + + @override + void detach() { + super.detach(); + _keepAliveBucket.values.forEach((child) => child.detach()); + } + + @override + void redepthChildren() { + super.redepthChildren(); + _keepAliveBucket.values.forEach(redepthChild); + } + + @override + void visitChildren(RenderObjectVisitor visitor) { + super.visitChildren(visitor); + _keepAliveBucket.values.forEach(visitor); + } + + bool addChild(int index) { + assert(_debugAssertChildListLocked()); + _createOrObtainChild(index); + final child = this[index]; + if (child != null) { + assert(indexOf(child) == index); + return true; + } + childManager.setDidUnderflow(true); + return false; + } + + RenderBox addAndLayoutChild( + int index, + BoxConstraints childConstraints, { + bool parentUsesSize = false, + }) { + assert(_debugAssertChildListLocked()); + _createOrObtainChild(index); + final child = this[index]; + if (child != null) { + assert(indexOf(child) == index); + child.layout(childConstraints, parentUsesSize: parentUsesSize); + return child; + } + childManager.setDidUnderflow(true); + return null; + } + + /// Called after layout with the number of children that can be garbage + /// collected at the head and tail of the child list. + /// + /// Children whose [SliverVariableSizeBoxAdaptorParentData.keepAlive] property is + /// set to true will be removed to a cache instead of being dropped. + /// + /// This method also collects any children that were previously kept alive but + /// are now no longer necessary. As such, it should be called every time + /// [performLayout] is run, even if the arguments are both zero. + @protected + void collectGarbage(Set visibleIndices) { + assert(_debugAssertChildListLocked()); + assert(childCount >= visibleIndices.length); + invokeLayoutCallback((SliverConstraints constraints) { + // We destroy only those which are not visible. + indices.toSet().difference(visibleIndices).forEach(_destroyOrCacheChild); + + // Ask the child manager to remove the children that are no longer being + // kept alive. (This should cause _keepAliveBucket to change, so we have + // to prepare our list ahead of time.) + _keepAliveBucket.values + .where((RenderBox child) { + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + return !childParentData.keepAlive; + }) + .toList() + .forEach(_childManager.removeChild); + assert(_keepAliveBucket.values.where((RenderBox child) { + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + return !childParentData.keepAlive; + }).isEmpty); + }); + } + + /// Returns the index of the given child, as given by the + /// [SliverVariableSizeBoxAdaptorParentData.index] field of the child's [parentData]. + int indexOf(RenderBox child) { + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + assert(childParentData.index != null); + return childParentData.index; + } + + /// Returns the dimension of the given child in the main axis, as given by the + /// child's [RenderBox.size] property. This is only valid after layout. + @protected + double paintExtentOf(RenderBox child) { + assert(child.hasSize); + switch (constraints.axis) { + case Axis.horizontal: + return child.size.width; + case Axis.vertical: + return child.size.height; + } + } + + @override + bool hitTestChildren(HitTestResult result, + {@required double mainAxisPosition, @required double crossAxisPosition}) { + for (final child in children) { + if (hitTestBoxChild(BoxHitTestResult.wrap(result), child, + mainAxisPosition: mainAxisPosition, + crossAxisPosition: crossAxisPosition)) { + return true; + } + } + return false; + } + + @override + double childMainAxisPosition(RenderBox child) { + return childScrollOffset(child) - constraints.scrollOffset; + } + + @override + double childCrossAxisPosition(RenderBox child) { + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + return childParentData.crossAxisOffset; + } + + @override + double childScrollOffset(RenderObject child) { + assert(child.parent == this); + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + assert(childParentData.layoutOffset != null); + return childParentData.layoutOffset; + } + + @override + void applyPaintTransform(RenderObject child, Matrix4 transform) { + applyPaintTransformForBoxChild(child as RenderBox, transform); + } + + @override + void paint(PaintingContext context, Offset offset) { + if (childCount == 0) { + return; + } + // offset is to the top-left corner, regardless of our axis direction. + // originOffset gives us the delta from the real origin to the origin in the axis direction. + Offset mainAxisUnit, crossAxisUnit, originOffset; + bool addExtent; + switch (applyGrowthDirectionToAxisDirection( + constraints.axisDirection, constraints.growthDirection)) { + case AxisDirection.up: + mainAxisUnit = const Offset(0, -1); + crossAxisUnit = const Offset(1, 0); + originOffset = offset + Offset(0, geometry.paintExtent); + addExtent = true; + break; + case AxisDirection.right: + mainAxisUnit = const Offset(1, 0); + crossAxisUnit = const Offset(0, 1); + originOffset = offset; + addExtent = false; + break; + case AxisDirection.down: + mainAxisUnit = const Offset(0, 1); + crossAxisUnit = const Offset(1, 0); + originOffset = offset; + addExtent = false; + break; + case AxisDirection.left: + mainAxisUnit = const Offset(-1, 0); + crossAxisUnit = const Offset(0, 1); + originOffset = offset + Offset(geometry.paintExtent, 0); + addExtent = true; + break; + } + + for (final child in children) { + final double mainAxisDelta = childMainAxisPosition(child); + final double crossAxisDelta = childCrossAxisPosition(child); + Offset childOffset = Offset( + originOffset.dx + + mainAxisUnit.dx * mainAxisDelta + + crossAxisUnit.dx * crossAxisDelta, + originOffset.dy + + mainAxisUnit.dy * mainAxisDelta + + crossAxisUnit.dy * crossAxisDelta, + ); + if (addExtent) { + childOffset += mainAxisUnit * paintExtentOf(child); + } + context.paintChild(child, childOffset); + } + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsNode.message(childCount > 0 + ? 'currently live children: ${indices.join(',')}' + : 'no children current live')); + } + + @override + List debugDescribeChildren() { + final List childList = []; + if (childCount > 0) { + for (final child in children) { + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + childList.add(child.toDiagnosticsNode( + name: 'child with index ${childParentData.index}')); + } + } + if (_keepAliveBucket.isNotEmpty) { + final List indices = _keepAliveBucket.keys.toList()..sort(); + for (final index in indices) { + childList.add(_keepAliveBucket[index].toDiagnosticsNode( + name: 'child with index $index (kept alive offstage)', + style: DiagnosticsTreeStyle.offstage, + )); + } + } + return childList; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/tile_container_render_object_mixin.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/tile_container_render_object_mixin.dart new file mode 100644 index 00000000..83e7f2e5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/rendering/tile_container_render_object_mixin.dart @@ -0,0 +1,115 @@ +import 'dart:collection'; + +import 'package:flutter/rendering.dart'; + +/// Generic mixin for render objects with a list of children. +/// +/// Provides a child model for a render object subclass that stores children +/// in a HashMap. +mixin TileContainerRenderObjectMixin on RenderObject { + final SplayTreeMap _childRenderObjects = + SplayTreeMap(); + + /// The number of children. + int get childCount => _childRenderObjects.length; + + Iterable get children => _childRenderObjects.values; + + Iterable get indices => _childRenderObjects.keys; + + /// Checks whether the given render object has the correct [runtimeType] to be + /// a child of this render object. + /// + /// Does nothing if assertions are disabled. + /// + /// Always returns true. + bool debugValidateChild(RenderObject child) { + assert(() { + if (child is! ChildType) { + throw FlutterError( + 'A $runtimeType expected a child of type $ChildType but received a ' + 'child of type ${child.runtimeType}.\n' + 'RenderObjects expect specific types of children because they ' + 'coordinate with their children during layout and paint. For ' + 'example, a RenderSliver cannot be the child of a RenderBox because ' + 'a RenderSliver does not understand the RenderBox layout protocol.\n' + '\n' + 'The $runtimeType that expected a $ChildType child was created by:\n' + ' $debugCreator\n' + '\n' + 'The ${child.runtimeType} that did not match the expected child type ' + 'was created by:\n' + ' ${child.debugCreator}\n'); + } + return true; + }()); + return true; + } + + ChildType operator [](int index) => _childRenderObjects[index]; + + void operator []=(int index, ChildType child) { + if (index < 0) { + throw ArgumentError(index); + } + _removeChild(_childRenderObjects[index]); + adoptChild(child); + _childRenderObjects[index] = child; + } + + void forEachChild(void Function(ChildType child) f) { + _childRenderObjects.values.forEach(f); + } + + /// Remove the child at the specified index from the child list. + void remove(int index) { + final child = _childRenderObjects.remove(index); + _removeChild(child); + } + + void _removeChild(ChildType child) { + if (child != null) { + // Remove the old child. + dropChild(child); + } + } + + /// Remove all their children from this render object's child list. + /// + /// More efficient than removing them individually. + void removeAll() { + _childRenderObjects.values.forEach(dropChild); + _childRenderObjects.clear(); + } + + @override + void attach(PipelineOwner owner) { + super.attach(owner); + _childRenderObjects.values.forEach((child) => child.attach(owner)); + } + + @override + void detach() { + super.detach(); + _childRenderObjects.values.forEach((child) => child.detach()); + } + + @override + void redepthChildren() { + _childRenderObjects.values.forEach(redepthChild); + } + + @override + void visitChildren(RenderObjectVisitor visitor) { + _childRenderObjects.values.forEach(visitor); + } + + @override + List debugDescribeChildren() { + final List children = []; + _childRenderObjects.forEach((index, child) => + children.add(child.toDiagnosticsNode(name: 'child $index'))); + return children; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/sliver.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/sliver.dart new file mode 100644 index 00000000..dc5e7f7a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/sliver.dart @@ -0,0 +1,578 @@ +import 'dart:collection'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:flutter_staggered_grid_view/src/rendering/sliver_staggered_grid.dart'; +import 'package:flutter_staggered_grid_view/src/rendering/sliver_variable_size_box_adaptor.dart'; +import 'package:flutter_staggered_grid_view/src/widgets/staggered_tile.dart'; + +/// A base class for sliver that have multiple variable size box children. +/// +/// Helps subclasses build their children lazily using a [SliverVariableSizeChildDelegate]. +abstract class SliverVariableSizeBoxAdaptorWidget + extends SliverWithKeepAliveWidget { + /// Initializes fields for subclasses. + const SliverVariableSizeBoxAdaptorWidget({ + Key key, + @required this.delegate, + }) : super(key: key); + + /// The delegate that provides the children for this widget. + /// + /// The children are constructed lazily using this widget to avoid creating + /// more children than are visible through the [Viewport]. + /// + /// See also: + /// + /// * [SliverChildBuilderDelegate] and [SliverChildListDelegate], which are + /// commonly used subclasses of [SliverChildDelegate] that use a builder + /// callback and an explicit child list, respectively. + final SliverChildDelegate delegate; + + @override + SliverVariableSizeBoxAdaptorElement createElement() => + SliverVariableSizeBoxAdaptorElement(this); + + @override + RenderSliverVariableSizeBoxAdaptor createRenderObject(BuildContext context); + + /// Returns an estimate of the max scroll extent for all the children. + /// + /// Subclasses should override this function if they have additional + /// information about their max scroll extent. + /// + /// This is used by [SliverMultiBoxAdaptorElement] to implement part of the + /// [RenderSliverBoxChildManager] API. + /// + /// The default implementation defers to [delegate] via its + /// [SliverChildDelegate.estimateMaxScrollOffset] method. + double estimateMaxScrollOffset( + SliverConstraints constraints, + int firstIndex, + int lastIndex, + double leadingScrollOffset, + double trailingScrollOffset, + ) { + assert(lastIndex >= firstIndex); + return delegate.estimateMaxScrollOffset( + firstIndex, + lastIndex, + leadingScrollOffset, + trailingScrollOffset, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add( + DiagnosticsProperty('delegate', delegate), + ); + } +} + +/// An element that lazily builds children for a [SliverVariableSizeBoxAdaptorWidget]. +/// +/// Implements [RenderSliverVariableSizeBoxChildManager], which lets this element manage +/// the children of subclasses of [RenderSliverVariableSizeBoxAdaptor]. +class SliverVariableSizeBoxAdaptorElement extends RenderObjectElement + implements RenderSliverVariableSizeBoxChildManager { + /// Creates an element that lazily builds children for the given widget. + SliverVariableSizeBoxAdaptorElement(SliverVariableSizeBoxAdaptorWidget widget) + : super(widget); + + @override + SliverVariableSizeBoxAdaptorWidget get widget => + super.widget as SliverVariableSizeBoxAdaptorWidget; + + @override + RenderSliverVariableSizeBoxAdaptor get renderObject => + super.renderObject as RenderSliverVariableSizeBoxAdaptor; + + @override + void update(covariant SliverVariableSizeBoxAdaptorWidget newWidget) { + final SliverVariableSizeBoxAdaptorWidget oldWidget = widget; + super.update(newWidget); + final SliverChildDelegate newDelegate = newWidget.delegate; + final SliverChildDelegate oldDelegate = oldWidget.delegate; + if (newDelegate != oldDelegate && + (newDelegate.runtimeType != oldDelegate.runtimeType || + newDelegate.shouldRebuild(oldDelegate))) { + performRebuild(); + } + } + + // We inf widgets at two different times: + // 1. When we ourselves are told to rebuild (see performRebuild). + // 2. When our render object needs a child (see createChild). + // In both cases, we cache the results of calling into our delegate to get the widget, + // so that if we do case 2 r, we don't call the builder again. + // Any time we do case 1, though, we reset the cache. + + final Map _childWidgets = HashMap(); + final SplayTreeMap _childElements = + SplayTreeMap(); + + @override + void performRebuild() { + _childWidgets.clear(); // Reset the cache, as described above. + super.performRebuild(); + assert(_currentlyUpdatingChildIndex == null); + try { + int firstIndex; + int lastIndex; + if (_childElements.isEmpty) { + firstIndex = 0; + lastIndex = 0; + } else if (_didUnderflow) { + firstIndex = _childElements.firstKey(); + lastIndex = _childElements.lastKey() + 1; + } else { + firstIndex = _childElements.firstKey(); + lastIndex = _childElements.lastKey(); + } + + for (int index = firstIndex; index <= lastIndex; ++index) { + _currentlyUpdatingChildIndex = index; + final Element newChild = + updateChild(_childElements[index], _build(index), index); + if (newChild != null) { + _childElements[index] = newChild; + } else { + _childElements.remove(index); + } + } + } finally { + _currentlyUpdatingChildIndex = null; + } + } + + Widget _build(int index) { + return _childWidgets.putIfAbsent( + index, () => widget.delegate.build(this, index)); + } + + @override + void createChild(int index) { + assert(_currentlyUpdatingChildIndex == null); + owner.buildScope(this, () { + Element newChild; + try { + _currentlyUpdatingChildIndex = index; + newChild = updateChild(_childElements[index], _build(index), index); + } finally { + _currentlyUpdatingChildIndex = null; + } + if (newChild != null) { + _childElements[index] = newChild; + } else { + _childElements.remove(index); + } + }); + } + + @override + Element updateChild(Element child, Widget newWidget, dynamic newSlot) { + final oldParentData = child?.renderObject.parentData + as SliverVariableSizeBoxAdaptorParentData; + final Element newChild = super.updateChild(child, newWidget, newSlot); + final newParentData = newChild?.renderObject.parentData + as SliverVariableSizeBoxAdaptorParentData; + + // set keepAlive to true in order to popu the cache + if (newParentData != null) { + newParentData.keepAlive = true; + } + + // Preserve the old layoutOffset if the renderObject was swapped out. + if (oldParentData != newParentData && + oldParentData != null && + newParentData != null) { + newParentData.layoutOffset = oldParentData.layoutOffset; + } + + return newChild; + } + + @override + void forgetChild(Element child) { + assert(child.slot != null); + assert(_childElements.containsKey(child.slot)); + _childElements.remove(child.slot); + super.forgetChild(child); + } + + @override + void removeChild(RenderBox child) { + final int index = renderObject.indexOf(child); + assert(_currentlyUpdatingChildIndex == null); + assert(index >= 0); + owner.buildScope(this, () { + assert(_childElements.containsKey(index)); + try { + _currentlyUpdatingChildIndex = index; + final Element result = updateChild(_childElements[index], null, index); + assert(result == null); + } finally { + _currentlyUpdatingChildIndex = null; + } + _childElements.remove(index); + assert(!_childElements.containsKey(index)); + }); + } + + double _extrapoMaxScrollOffset( + int firstIndex, + int lastIndex, + double leadingScrollOffset, + double trailingScrollOffset, + ) { + final int childCount = widget.delegate.estimatedChildCount; + if (childCount == null) { + return double.infinity; + } + if (lastIndex == childCount - 1) { + return trailingScrollOffset; + } + final int reifiedCount = lastIndex - firstIndex + 1; + final double averageExtent = + (trailingScrollOffset - leadingScrollOffset) / reifiedCount; + final int remainingCount = childCount - lastIndex - 1; + return trailingScrollOffset + averageExtent * remainingCount; + } + + @override + double estimateMaxScrollOffset( + SliverConstraints constraints, { + int firstIndex, + int lastIndex, + double leadingScrollOffset, + double trailingScrollOffset, + }) { + return widget.estimateMaxScrollOffset( + constraints, + firstIndex, + lastIndex, + leadingScrollOffset, + trailingScrollOffset, + ) ?? + _extrapoMaxScrollOffset( + firstIndex, + lastIndex, + leadingScrollOffset, + trailingScrollOffset, + ); + } + + @override + int get childCount => widget.delegate.estimatedChildCount ?? 0; + + @override + void didStartLayout() { + assert(debugAssertChildListLocked()); + } + + @override + void didFinishLayout() { + assert(debugAssertChildListLocked()); + final int firstIndex = _childElements.firstKey() ?? 0; + final int lastIndex = _childElements.lastKey() ?? 0; + widget.delegate.didFinishLayout(firstIndex, lastIndex); + } + + int _currentlyUpdatingChildIndex; + + @override + bool debugAssertChildListLocked() { + assert(_currentlyUpdatingChildIndex == null); + return true; + } + + @override + void didAdoptChild(RenderBox child) { + assert(_currentlyUpdatingChildIndex != null); + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + childParentData.index = _currentlyUpdatingChildIndex; + } + + bool _didUnderflow = false; + + @override + void setDidUnderflow(bool value) { + _didUnderflow = value; + } + + @override + void insertRenderObjectChild(covariant RenderBox child, int slot) { + assert(_currentlyUpdatingChildIndex == slot); + assert(renderObject.debugValidateChild(child)); + renderObject[_currentlyUpdatingChildIndex] = child; + assert(() { + final childParentData = + child.parentData as SliverVariableSizeBoxAdaptorParentData; + assert(slot == childParentData.index); + return true; + }()); + } + + @override + void moveRenderObjectChild( + covariant RenderObject child, + covariant Object oldSlot, + covariant Object newSlot, + ) { + assert(false); + } + + @override + void removeRenderObjectChild( + covariant RenderObject child, + covariant Object slot, + ) { + assert(_currentlyUpdatingChildIndex != null); + renderObject.remove(_currentlyUpdatingChildIndex); + } + + @override + void visitChildren(ElementVisitor visitor) { + // The toList() is to make a copy so that the underlying list can be modified by + // the visitor: + _childElements.values.toList().forEach(visitor); + } + + @override + void debugVisitOnstageChildren(ElementVisitor visitor) { + _childElements.values.where((Element child) { + final parentData = + child.renderObject.parentData as SliverMultiBoxAdaptorParentData; + double itemExtent; + switch (renderObject.constraints.axis) { + case Axis.horizontal: + itemExtent = child.renderObject.paintBounds.width; + break; + case Axis.vertical: + itemExtent = child.renderObject.paintBounds.height; + break; + } + + return parentData.layoutOffset < + renderObject.constraints.scrollOffset + + renderObject.constraints.remainingPaintExtent && + parentData.layoutOffset + itemExtent > + renderObject.constraints.scrollOffset; + }).forEach(visitor); + } +} + +/// A sliver that places multiple box children in a two dimensional arrangement. +/// +/// [SliverStaggeredGrid] places its children in arbitrary positions determined by +/// [gridDelegate]. Each child is forced to have the size specified by the +/// [gridDelegate]. +/// +/// The main axis direction of a grid is the direction in which it scrolls; the +/// cross axis direction is the orthogonal direction. +/// +/// ## Sample code +/// +/// This example, which would be inserted into a [CustomScrollView.slivers] +/// list, shows 8 boxes: +/// +/// ```dart +///SliverStaggeredGrid.count( +/// crossAxisCount: 4, +/// mainAxisSpacing: 4.0, +/// crossAxisSpacing: 4.0, +/// children: const [ +/// const Text('1'), +/// const Text('2'), +/// const Text('3'), +/// const Text('4'), +/// const Text('5'), +/// const Text('6'), +/// const Text('7'), +/// const Text('8'), +/// ], +/// staggeredTiles: const [ +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// ], +///) +/// ``` +/// +/// See also: +/// +/// * [SliverList], which places its children in a linear array. +/// * [SliverFixedExtentList], which places its children in a linear +/// array with a fixed extent in the main axis. +/// * [SliverPrototypeExtentList], which is similar to [SliverFixedExtentList] +/// except that it uses a prototype list item instead of a pixel value to define +/// the main axis extent of each item. +class SliverStaggeredGrid extends SliverVariableSizeBoxAdaptorWidget { + /// Creates a sliver that places multiple box children in a two dimensional + /// arrangement. + const SliverStaggeredGrid({ + Key key, + @required SliverChildDelegate delegate, + @required this.gridDelegate, + }) : super(key: key, delegate: delegate); + + /// Creates a sliver that places multiple box children in a two dimensional + /// arrangement with a fixed number of tiles in the cross axis. + /// + /// Uses a [SliverStaggeredGridDelegateWithFixedCrossAxisCount] as the [gridDelegate], + /// and a [SliverVariableSizeChildListDelegate] as the [delegate]. + /// + /// See also: + /// + /// * [StaggeredGridView.count], the equivalent constructor for [StaggeredGridView] widgets. + SliverStaggeredGrid.count({ + Key key, + @required int crossAxisCount, + double mainAxisSpacing = 0.0, + double crossAxisSpacing = 0.0, + List children = const [], + List staggeredTiles = const [], + }) : gridDelegate = SliverStaggeredGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileBuilder: (i) => staggeredTiles[i], + staggeredTileCount: staggeredTiles.length, + ), + super( + key: key, + delegate: SliverChildListDelegate( + children, + ), + ); + + /// Creates a sliver that builds multiple box children in a two dimensional + /// arrangement with a fixed number of tiles in the cross axis. + /// + /// This constructor is appropriate for grid views with a large (or infinite) + /// number of children because the builder is called only for those children + /// that are actually visible. + /// + /// Uses a [SliverStaggeredGridDelegateWithFixedCrossAxisCount] as the + /// [gridDelegate], and a [SliverVariableSizeChildBuilderDelegate] as the [delegate]. + /// + /// See also: + /// + /// * [StaggeredGridView.countBuilder], the equivalent constructor for + /// [StaggeredGridView] widgets. + SliverStaggeredGrid.countBuilder({ + Key key, + @required int crossAxisCount, + @required IndexedStaggeredTileBuilder staggeredTileBuilder, + @required IndexedWidgetBuilder itemBuilder, + @required int itemCount, + double mainAxisSpacing = 0, + double crossAxisSpacing = 0, + }) : gridDelegate = SliverStaggeredGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileBuilder: staggeredTileBuilder, + staggeredTileCount: itemCount, + ), + super( + key: key, + delegate: SliverChildBuilderDelegate( + itemBuilder, + childCount: itemCount, + ), + ); + + /// Creates a sliver that places multiple box children in a two dimensional + /// arrangement with tiles that each have a maximum cross-axis extent. + /// + /// Uses a [SliverStaggeredGridDelegateWithMaxCrossAxisExtent] as the [gridDelegate], + /// and a [SliverVariableSizeChildListDelegate] as the [delegate]. + /// + /// See also: + /// + /// * [StaggeredGridView.extent], the equivalent constructor for [StaggeredGridView] widgets. + SliverStaggeredGrid.extent({ + Key key, + @required double maxCrossAxisExtent, + double mainAxisSpacing = 0, + double crossAxisSpacing = 0, + List children = const [], + List staggeredTiles = const [], + }) : gridDelegate = SliverStaggeredGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: maxCrossAxisExtent, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileBuilder: (i) => staggeredTiles[i], + staggeredTileCount: staggeredTiles.length, + ), + super( + key: key, + delegate: SliverChildListDelegate( + children, + ), + ); + + /// Creates a sliver that builds multiple box children in a two dimensional + /// arrangement with tiles that each have a maximum cross-axis extent. + /// + /// This constructor is appropriate for grid views with a large (or infinite) + /// number of children because the builder is called only for those children + /// that are actually visible. + /// + /// Uses a [SliverStaggeredGridDelegateWithMaxCrossAxisExtent] as the + /// [gridDelegate], and a [SliverVariableSizeChildBuilderDelegate] as the [delegate]. + /// + /// See also: + /// + /// * [StaggeredGridView.extentBuilder], the equivalent constructor for + /// [StaggeredGridView] widgets. + SliverStaggeredGrid.extentBuilder({ + Key key, + @required double maxCrossAxisExtent, + @required IndexedStaggeredTileBuilder staggeredTileBuilder, + @required IndexedWidgetBuilder itemBuilder, + @required int itemCount, + double mainAxisSpacing = 0, + double crossAxisSpacing = 0, + }) : gridDelegate = SliverStaggeredGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: maxCrossAxisExtent, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileBuilder: staggeredTileBuilder, + staggeredTileCount: itemCount, + ), + super( + key: key, + delegate: SliverChildBuilderDelegate( + itemBuilder, + childCount: itemCount, + ), + ); + + /// The delegate that controls the size and position of the children. + final SliverStaggeredGridDelegate gridDelegate; + + @override + RenderSliverStaggeredGrid createRenderObject(BuildContext context) { + final element = context as SliverVariableSizeBoxAdaptorElement; + return RenderSliverStaggeredGrid( + childManager: element, gridDelegate: gridDelegate); + } + + @override + void updateRenderObject( + BuildContext context, RenderSliverStaggeredGrid renderObject) { + renderObject.gridDelegate = gridDelegate; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/staggered_grid_view.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/staggered_grid_view.dart new file mode 100644 index 00000000..64adb67b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/staggered_grid_view.dart @@ -0,0 +1,507 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:flutter_staggered_grid_view/src/widgets/sliver.dart'; +import 'package:flutter_staggered_grid_view/src/widgets/staggered_tile.dart'; +import 'package:flutter_staggered_grid_view/src/rendering/sliver_staggered_grid.dart'; + +/// A scrollable, 2D array of widgets with variable sizes. +/// +/// The main axis direction of a grid is the direction in which it scrolls (the +/// [scrollDirection]). +/// +/// The most commonly used grid layouts are [StaggeredGridView.count], which +/// creates a layout with a fixed number of tiles in the cross axis, and +/// [StaggeredGridView.extent], which creates a layout with tiles that have a maximum +/// cross-axis extent. A custom [SliverStaggeredGridDelegate] can produce an +/// arbitrary 2D arrangement of children. +/// +/// To create a grid with a large (or infinite) number of children, use the +/// [StaggeredGridView.builder] constructor with either a +/// [SliverStaggeredGridDelegateWithFixedCrossAxisCount] or a +/// [SliverStaggeredGridDelegateWithMaxCrossAxisExtent] for the [gridDelegate]. +/// You can also use the [StaggeredGridView.countBuilder] or +/// [StaggeredGridView.extentBuilder] constructors. +/// +/// To use a custom [SliverVariableSizeChildDelegate], use [StaggeredGridView.custom]. +/// +/// To create a linear array of children, use a [ListView]. +/// +/// To control the initial scroll offset of the scroll view, provide a +/// [controller] with its [ScrollController.initialScrollOffset] property set. +/// +/// ### Sample code +/// +/// Here are two brief snippets showing a [StaggeredGridView] and its equivalent using +/// [CustomScrollView]: +/// +/// ```dart +/// StaggeredGridView.count( +/// primary: false, +/// crossAxisCount: 4, +/// mainAxisSpacing: 4.0, +/// crossAxisSpacing: 4.0, +/// children: const [ +/// const Text('1'), +/// const Text('2'), +/// const Text('3'), +/// const Text('4'), +/// const Text('5'), +/// const Text('6'), +/// const Text('7'), +/// const Text('8'), +/// ], +/// staggeredTiles: const [ +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// ], +/// ) +/// ``` +/// +/// ```dart +/// CustomScrollView( +/// primary: false, +/// slivers: [ +/// SliverStaggeredGrid.count( +/// crossAxisCount: 4, +/// mainAxisSpacing: 4.0, +/// crossAxisSpacing: 4.0, +/// children: const [ +/// const Text('1'), +/// const Text('2'), +/// const Text('3'), +/// const Text('4'), +/// const Text('5'), +/// const Text('6'), +/// const Text('7'), +/// const Text('8'), +/// ], +/// staggeredTiles: const [ +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// const StaggeredTile.count(2, 2), +/// const StaggeredTile.count(2, 1), +/// ], +/// ) +/// ], +/// ) +/// ``` +/// +/// See also: +/// +/// * [SingleChildScrollView], which is a scrollable widget that has a single +/// child. +/// * [ListView], which is scrollable, linear list of widgets. +/// * [PageView], which is a scrolling list of child widgets that are each the +/// size of the viewport. +/// * [CustomScrollView], which is a scrollable widget that creates custom +/// scroll effects using slivers. +/// * [SliverStaggeredGridDelegateWithFixedCrossAxisCount], which creates a +/// layout with a fixed number of tiles in the cross axis. +/// * [SliverStaggeredGridDelegateWithMaxCrossAxisExtent], which creates a +/// layout with tiles that have a maximum cross-axis extent. +/// * [ScrollNotification] and [NotificationListener], which can be used to watch +/// the scroll position without using a [ScrollController]. +class StaggeredGridView extends BoxScrollView { + /// Creates a scrollable, 2D array of widgets with a custom + /// [SliverStaggeredGridDelegate]. + /// + /// The [gridDelegate] argument must not be null. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addRepaintBoundaries] property. Both must not be + /// null. + StaggeredGridView({ + Key key, + Axis scrollDirection = Axis.vertical, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + @required this.gridDelegate, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + List children = const [], + String restorationId, + }) : childrenDelegate = SliverChildListDelegate( + children, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + ), + super( + key: key, + scrollDirection: scrollDirection, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + restorationId: restorationId, + ); + + /// Creates a scrollable, 2D array of widgets that are created on demand. + /// + /// This constructor is appropriate for grid views with a large (or infinite) + /// number of children because the builder is called only for those children + /// that are actually visible. + /// + /// Providing a non-null [itemCount] improves the ability of the + /// [SliverStaggeredGridDelegate] to estimate the maximum scroll extent. + /// + /// [itemBuilder] will be called only with indices greater than or equal to + /// zero and less than [itemCount]. + /// + /// The [gridDelegate] argument must not be null. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverVariableSizeChildBuilderDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverVariableSizeChildBuilderDelegate.addRepaintBoundaries] property. Both must not + /// be null. + StaggeredGridView.builder({ + Key key, + Axis scrollDirection = Axis.vertical, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + @required this.gridDelegate, + @required IndexedWidgetBuilder itemBuilder, + int itemCount, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + String restorationId, + }) : childrenDelegate = SliverChildBuilderDelegate( + itemBuilder, + childCount: itemCount, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + ), + super( + key: key, + scrollDirection: scrollDirection, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + restorationId: restorationId, + ); + + /// Creates a scrollable, 2D array of widgets with both a custom + /// [SliverStaggeredGridDelegate] and a custom [SliverVariableSizeChildDelegate]. + /// + /// To use an [IndexedWidgetBuilder] callback to build children, either use + /// a [SliverVariableSizeChildBuilderDelegate] or use the + /// [SliverStaggeredGridDelegate.builder] constructor. + /// + /// The [gridDelegate] and [childrenDelegate] arguments must not be null. + const StaggeredGridView.custom({ + Key key, + Axis scrollDirection = Axis.vertical, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + String restorationId, + @required this.gridDelegate, + @required this.childrenDelegate, + }) : super( + key: key, + scrollDirection: scrollDirection, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + restorationId: restorationId, + ); + + /// Creates a scrollable, 2D array of widgets of variable sizes with a fixed + /// number of tiles in the cross axis. + /// + /// Uses a [SliverStaggeredGridDelegateWithFixedCrossAxisCount] as the + /// [gridDelegate]. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addRepaintBoundaries] property. Both must not be + /// null. + /// + /// See also: + /// + /// * [SliverGrid.count], the equivalent constructor for [SliverGrid]. + StaggeredGridView.count({ + Key key, + Axis scrollDirection = Axis.vertical, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + @required int crossAxisCount, + double mainAxisSpacing = 0.0, + double crossAxisSpacing = 0.0, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + List children = const [], + List staggeredTiles = const [], + String restorationId, + }) : gridDelegate = SliverStaggeredGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileBuilder: (i) => staggeredTiles[i], + staggeredTileCount: staggeredTiles.length, + ), + childrenDelegate = SliverChildListDelegate( + children, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + ), + super( + key: key, + scrollDirection: scrollDirection, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + restorationId: restorationId, + ); + + /// Creates a scrollable, 2D array of widgets of variable sizes with a fixed + /// number of tiles in the cross axis that are created on demand. + /// + /// This constructor is appropriate for grid views with a large (or infinite) + /// number of children because the builder is called only for those children + /// that are actually visible. + /// + /// Uses a [SliverStaggeredGridDelegateWithFixedCrossAxisCount] as the + /// [gridDelegate]. + /// + /// Providing a non-null [itemCount] improves the ability of the + /// [SliverStaggeredGridDelegate] to estimate the maximum scroll extent. + /// + /// [itemBuilder] and [staggeredTileBuilder] will be called only with + /// indices greater than or equal to + /// zero and less than [itemCount]. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addRepaintBoundaries] property. Both must not be + /// null. + StaggeredGridView.countBuilder({ + Key key, + Axis scrollDirection = Axis.vertical, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + @required int crossAxisCount, + @required IndexedWidgetBuilder itemBuilder, + @required IndexedStaggeredTileBuilder staggeredTileBuilder, + int itemCount, + double mainAxisSpacing = 0.0, + double crossAxisSpacing = 0.0, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + String restorationId, + }) : gridDelegate = SliverStaggeredGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileBuilder: staggeredTileBuilder, + staggeredTileCount: itemCount, + ), + childrenDelegate = SliverChildBuilderDelegate( + itemBuilder, + childCount: itemCount, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + ), + super( + key: key, + scrollDirection: scrollDirection, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + restorationId: restorationId, + ); + + /// Creates a scrollable, 2D array of widgets of variable sizes with tiles + /// that each have a maximum cross-axis extent. + /// + /// Uses a [SliverGridDelegateWithMaxCrossAxisExtent] as the [gridDelegate]. + /// + /// Providing a non-null [itemCount] improves the ability of the + /// [SliverStaggeredGridDelegate] to estimate the maximum scroll extent. + /// + /// [itemBuilder] and [staggeredTileBuilder] will be called only with + /// indices greater than or equal to + /// zero and less than [itemCount]. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addRepaintBoundaries] property. Both must not be + /// null. + /// + /// See also: + /// + /// * [SliverGrid.extent], the equivalent constructor for [SliverGrid]. + StaggeredGridView.extent({ + Key key, + Axis scrollDirection = Axis.vertical, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + @required double maxCrossAxisExtent, + double mainAxisSpacing = 0.0, + double crossAxisSpacing = 0.0, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + List children = const [], + List staggeredTiles = const [], + String restorationId, + }) : gridDelegate = SliverStaggeredGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: maxCrossAxisExtent, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileBuilder: (i) => staggeredTiles[i], + staggeredTileCount: staggeredTiles.length, + ), + childrenDelegate = SliverChildListDelegate( + children, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + ), + super( + key: key, + scrollDirection: scrollDirection, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + restorationId: restorationId, + ); + + /// Creates a scrollable, 2D array of widgets of variable sizes with tiles + /// that each have a maximum cross-axis extent that are created on demand. + /// + /// This constructor is appropriate for grid views with a large (or infinite) + /// number of children because the builder is called only for those children + /// that are actually visible. + /// + /// Uses a [SliverGridDelegateWithMaxCrossAxisExtent] as the [gridDelegate]. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverVariableSizeChildListDelegate.addRepaintBoundaries] property. Both must not be + /// null. + /// + /// See also: + /// + /// * [SliverGrid.extent], the equivalent constructor for [SliverGrid]. + StaggeredGridView.extentBuilder({ + Key key, + Axis scrollDirection = Axis.vertical, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + @required double maxCrossAxisExtent, + @required IndexedWidgetBuilder itemBuilder, + @required IndexedStaggeredTileBuilder staggeredTileBuilder, + int itemCount, + double mainAxisSpacing = 0.0, + double crossAxisSpacing = 0.0, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + String restorationId, + }) : gridDelegate = SliverStaggeredGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: maxCrossAxisExtent, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + staggeredTileBuilder: staggeredTileBuilder, + staggeredTileCount: itemCount, + ), + childrenDelegate = SliverChildBuilderDelegate( + itemBuilder, + childCount: itemCount, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + ), + super( + key: key, + scrollDirection: scrollDirection, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + restorationId: restorationId, + ); + + /// A delegate that controls the layout of the children within the + /// [StaggeredGridView]. + /// + /// The [StaggeredGridView] and [StaggeredGridView.custom] constructors let you specify this + /// delegate explicitly. The other constructors create a [gridDelegate] + /// implicitly. + final SliverStaggeredGridDelegate gridDelegate; + + /// A delegate that provides the children for the [StaggeredGridView]. + /// + /// The [StaggeredGridView.custom] constructor lets you specify this delegate + /// explicitly. The other constructors create a [childrenDelegate] that wraps + /// the given child list. + final SliverChildDelegate childrenDelegate; + + @override + Widget buildChildLayout(BuildContext context) { + return SliverStaggeredGrid( + delegate: childrenDelegate, + gridDelegate: gridDelegate, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/staggered_tile.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/staggered_tile.dart new file mode 100644 index 00000000..6810a57d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/lib/src/widgets/staggered_tile.dart @@ -0,0 +1,46 @@ +/// Holds the dimensions of a [StaggeredGridView]'s tile. +/// +/// A [StaggeredTile] always overlaps an exact number of cells in the cross +/// axis of a [StaggeredGridView]. +/// The main axis extent can either be a number of pixels or a number of +/// cells to overlap. +class StaggeredTile { + /// Creates a [StaggeredTile] with the given [crossAxisCellCount] and + /// [mainAxisCellCount]. + /// + /// The main axis extent of this tile will be the length of + /// [mainAxisCellCount] cells (inner spacings included). + const StaggeredTile.count(this.crossAxisCellCount, this.mainAxisCellCount) + : assert(crossAxisCellCount >= 0), + assert(mainAxisCellCount != null && mainAxisCellCount >= 0), + mainAxisExtent = null; + + /// Creates a [StaggeredTile] with the given [crossAxisCellCount] and + /// [mainAxisExtent]. + /// + /// This tile will have a fixed main axis extent. + const StaggeredTile.extent(this.crossAxisCellCount, this.mainAxisExtent) + : assert(crossAxisCellCount >= 0), + assert(mainAxisExtent != null && mainAxisExtent >= 0), + mainAxisCellCount = null; + + /// Creates a [StaggeredTile] with the given [crossAxisCellCount] that + /// fit its main axis extent to its content. + /// + /// This tile will have a fixed main axis extent. + const StaggeredTile.fit(this.crossAxisCellCount) + : assert(crossAxisCellCount >= 0), + mainAxisExtent = null, + mainAxisCellCount = null; + + /// The number of cells occupied in the cross axis. + final int crossAxisCellCount; + + /// The number of cells occupied in the main axis. + final double mainAxisCellCount; + + /// The number of pixels occupied in the main axis. + final double mainAxisExtent; + + bool get fitContent => mainAxisCellCount == null && mainAxisExtent == null; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/main.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/main.dart new file mode 100644 index 00000000..394f0105 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/main.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +import 'routes.dart'; + +void main() => runApp(StaggerApp()); + +class StaggerApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'StaggeredGridView Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + routes: routes, + ); + } + + @override + High getHigh() => High(toStringShort(), "text"); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/main_issue_21.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/main_issue_21.dart new file mode 100644 index 00000000..b64d400d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/main_issue_21.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'StaggeredGridView Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyScreen(), + ); + } +} + +class MyScreen extends StatefulWidget { + @override + _MyScreenState createState() => _MyScreenState(); +} + +class _MyScreenState extends State { + int _count = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: StaggeredTest(_count, _count), + floatingActionButton: FloatingActionButton( + onPressed: () { + setState(() { + _count++; + }); + }, + child: const Icon(Icons.add), + ), + ); + } +} + +class GridTest extends StatelessWidget { + const GridTest(this.count, this.value); + final int count; + final int value; + + @override + Widget build(BuildContext context) { + return GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 2, + mainAxisSpacing: 2, + ), + itemCount: count, + itemBuilder: (context, index) { + return Container( + color: Colors.blue, + child: Text('$value'), + ); + }, + ); + } +} + +class StaggeredTest extends StatelessWidget { + const StaggeredTest(this.count, this.value); + final int count; + final int value; + + @override + Widget build(BuildContext context) { + return StaggeredGridView.countBuilder( + itemCount: count, + crossAxisCount: 3, + crossAxisSpacing: 2, + mainAxisSpacing: 2, + addAutomaticKeepAlives: false, + staggeredTileBuilder: (index) => const StaggeredTile.extent(1, 30), + itemBuilder: (context, index) { + return Container( + color: Colors.green, + child: Text('$value'), + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/main_issue_23.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/main_issue_23.dart new file mode 100644 index 00000000..13ecf21f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/main_issue_23.dart @@ -0,0 +1,148 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'StaggeredGridView Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: BlocProvider( + bloc: SimpleBloc(), + child: MyScreen(), + ), + ); + } +} + +class MyScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: StreamBuilder( + stream: BlocProvider.of(context).counter, + initialData: 0, + builder: (context, snapshot) => + StaggeredTest(snapshot.data, snapshot.data), + ), + floatingActionButton: FloatingActionButton( + onPressed: BlocProvider.of(context).increment, + child: const Icon(Icons.add), + ), + ); + } +} + +class GridTest extends StatelessWidget { + GridTest(this.count, this.value); + final int count; + final int value; + + @override + Widget build(BuildContext context) { + return GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 2, + mainAxisSpacing: 2, + ), + itemCount: count, + itemBuilder: (context, index) { + return Container( + color: Colors.blue, + child: Text('$value'), + ); + }, + ); + } +} + +class StaggeredTest extends StatelessWidget { + const StaggeredTest(this.count, this.value); + final int count; + final int value; + + @override + Widget build(BuildContext context) { + return StaggeredGridView.countBuilder( + itemCount: count, + crossAxisCount: 3, + crossAxisSpacing: 2, + mainAxisSpacing: 2, + addAutomaticKeepAlives: false, + staggeredTileBuilder: (index) => const StaggeredTile.extent(1, 30), + itemBuilder: (context, index) { + return Container( + color: Colors.green, + child: Text('$value'), + ); + }, + ); + } +} + +abstract class Disposable { + void dispose(); +} + +class SimpleBloc implements Disposable { + factory SimpleBloc() { + return SimpleBloc._(StreamController()); + } + + SimpleBloc._(this._counterController) + : counter = _counterController.stream.asBroadcastStream() { + _counter = 0; + } + + final StreamController _counterController; + final Stream counter; + int _counter; + + void dispose() { + _counterController.close(); + } + + void increment() { + _counter++; + _counterController.sink.add(_counter); + } +} + +class BlocProvider extends StatefulWidget { + const BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + }) : super(key: key); + + final T bloc; + final Widget child; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + static T of(BuildContext context) { + final provider = context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } +} + +class _BlocProviderState extends State> { + @override + void dispose() { + widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/routes.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/routes.dart new file mode 100644 index 00000000..3bde11b2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/routes.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; + +import 'example_1.dart'; +import 'example_2.dart'; +import 'example_3.dart'; +import 'example_4.dart'; +import 'example_5.dart'; +import 'example_6.dart'; +import 'example_7.dart'; +import 'example_8.dart'; +import 'example_tests.dart'; +import 'home.dart'; +import 'spannable_count_count_page.dart'; +import 'spannable_count_extent_page.dart'; +import 'spannable_extent_count_page.dart'; +import 'spannable_extent_extent_page.dart'; +import 'staggered_count_count_page.dart'; +import 'staggered_count_extent_page.dart'; +import 'staggered_extent_count_page.dart'; +import 'staggered_extent_extent_page.dart'; + +const String homeRoute = '/'; + +const String staggeredCountCountRoute = '/staggered_count_count'; +const String staggeredExtentCountRoute = '/staggered_extent_count'; +const String staggeredCountExtentRoute = '/staggered_count_extent'; +const String staggeredExtentExtentRoute = '/staggered_extent_extent'; + +const String spannableCountCountRoute = '/spannable_count_count'; +const String spannableExtentCountRoute = '/spannable_extent_count'; +const String spannableCountExtentRoute = '/spannable_count_extent'; +const String spannableExtentExtentRoute = '/spannable_extent_extent'; + +const String example01 = '/example_01'; +const String example02 = '/example_02'; +const String example03 = '/example_03'; +const String example04 = '/example_04'; +const String example05 = '/example_05'; +const String example06 = '/example_06'; +const String example07 = '/example_07'; +const String example08 = '/example_08'; +const String exampleTests = '/example_tests'; + +Map routes = { + homeRoute: (BuildContext context) => Home(), + staggeredCountCountRoute: (BuildContext context) => StaggeredCountCountPage(), + staggeredExtentCountRoute: (BuildContext context) => + StaggeredExtentCountPage(), + staggeredCountExtentRoute: (BuildContext context) => + StaggeredCountExtentPage(), + staggeredExtentExtentRoute: (BuildContext context) => + StaggeredExtentExtentPage(), + spannableCountCountRoute: (BuildContext context) => SpannableCountCountPage(), + spannableExtentCountRoute: (BuildContext context) => + SpannableExtentCountPage(), + spannableCountExtentRoute: (BuildContext context) => + SpannableCountExtentPage(), + spannableExtentExtentRoute: (BuildContext context) => + SpannableExtentExtentPage(), + example01: (BuildContext context) => Example01(), + example02: (BuildContext context) => Example02(), + example03: (BuildContext context) => Example03(), + example04: (BuildContext context) => Example04(), + example05: (BuildContext context) => Example05(), + example06: (BuildContext context) => Example06(), + example07: (BuildContext context) => Example07(), + example08: (BuildContext context) => Example08(), + exampleTests: (BuildContext context) => ExampleTests(), +}; diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_count_count_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_count_count_page.dart new file mode 100644 index 00000000..115b94f0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_count_count_page.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'staggered_grid_view_page.dart'; + +const List _tiles = [ + StaggeredTile.count(2, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(4, 1), + StaggeredTile.count(4, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 4), + StaggeredTile.count(1, 3), + StaggeredTile.count(1, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), +]; + +class SpannableCountCountPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return const StaggeredGridViewPage.count( + title: 'Spannable (Count, Count)', crossAxisCount: 4, tiles: _tiles); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_count_extent_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_count_extent_page.dart new file mode 100644 index 00000000..52442ce6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_count_extent_page.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'staggered_grid_view_page.dart'; + +const List _tiles = [ + StaggeredTile.extent(2, 50), + StaggeredTile.extent(1, 180), + StaggeredTile.extent(1, 160), + StaggeredTile.extent(3, 140), + StaggeredTile.extent(1, 120), + StaggeredTile.extent(4, 130), + StaggeredTile.extent(1, 50), + StaggeredTile.extent(2, 60), + StaggeredTile.extent(1, 130), + StaggeredTile.extent(3, 140), + StaggeredTile.extent(1, 60), + StaggeredTile.extent(1, 150), +]; + +class SpannableCountExtentPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return const StaggeredGridViewPage.count( + title: 'Spannable (Count, Extent)', crossAxisCount: 4, tiles: _tiles); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_extent_count_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_extent_count_page.dart new file mode 100644 index 00000000..af40ca43 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_extent_count_page.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'staggered_grid_view_page.dart'; + +const List _tiles = [ + StaggeredTile.count(2, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(4, 1), + StaggeredTile.count(4, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 4), + StaggeredTile.count(1, 3), + StaggeredTile.count(1, 2), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1), +]; + +class SpannableExtentCountPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return const StaggeredGridViewPage.extent( + title: 'Spannable (Extent, Count)', + maxCrossAxisExtent: 75, + tiles: _tiles); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_extent_extent_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_extent_extent_page.dart new file mode 100644 index 00000000..dbe6baa3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/spannable_extent_extent_page.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'staggered_grid_view_page.dart'; + +const List _tiles = [ + StaggeredTile.extent(2, 50), + StaggeredTile.extent(1, 180), + StaggeredTile.extent(1, 160), + StaggeredTile.extent(3, 140), + StaggeredTile.extent(1, 120), + StaggeredTile.extent(4, 130), + StaggeredTile.extent(1, 50), + StaggeredTile.extent(2, 60), + StaggeredTile.extent(1, 130), + StaggeredTile.extent(3, 140), + StaggeredTile.extent(1, 60), + StaggeredTile.extent(1, 150), +]; + +class SpannableExtentExtentPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return const StaggeredGridViewPage.extent( + title: 'Spannable (Extent, Extent)', + maxCrossAxisExtent: 75, + tiles: _tiles); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_count_count_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_count_count_page.dart new file mode 100644 index 00000000..6a8ba379 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_count_count_page.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'staggered_grid_view_page.dart'; + +const List _tiles = [ + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), +]; + +class StaggeredCountCountPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return const StaggeredGridViewPage.count( + title: 'Staggered (Count, Count)', crossAxisCount: 2, tiles: _tiles); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_count_extent_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_count_extent_page.dart new file mode 100644 index 00000000..b89cdae9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_count_extent_page.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'staggered_grid_view_page.dart'; + +const List _tiles = [ + StaggeredTile.extent(1, 50), + StaggeredTile.extent(1, 180), + StaggeredTile.extent(1, 160), + StaggeredTile.extent(1, 140), + StaggeredTile.extent(1, 120), + StaggeredTile.extent(1, 130), + StaggeredTile.extent(1, 50), + StaggeredTile.extent(1, 60), + StaggeredTile.extent(1, 130), + StaggeredTile.extent(1, 140), + StaggeredTile.extent(1, 60), + StaggeredTile.extent(1, 150), +]; + +class StaggeredCountExtentPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return const StaggeredGridViewPage.count( + title: 'Staggered (Count, Extent)', crossAxisCount: 2, tiles: _tiles); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_extent_count_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_extent_count_page.dart new file mode 100644 index 00000000..c0478069 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_extent_count_page.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'staggered_grid_view_page.dart'; + +const List _tiles = [ + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), + StaggeredTile.count(1, 1.5), + StaggeredTile.count(1, 1), +]; + +class StaggeredExtentCountPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return const StaggeredGridViewPage.extent( + title: 'Staggered (Extent, Count)', + maxCrossAxisExtent: 150, + tiles: _tiles); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_extent_extent_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_extent_extent_page.dart new file mode 100644 index 00000000..4e71459d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_extent_extent_page.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'staggered_grid_view_page.dart'; + +const List _tiles = [ + StaggeredTile.extent(1, 50), + StaggeredTile.extent(1, 180), + StaggeredTile.extent(1, 160), + StaggeredTile.extent(1, 140), + StaggeredTile.extent(1, 120), + StaggeredTile.extent(1, 130), + StaggeredTile.extent(1, 50), + StaggeredTile.extent(1, 60), + StaggeredTile.extent(1, 130), + StaggeredTile.extent(1, 140), + StaggeredTile.extent(1, 60), + StaggeredTile.extent(1, 150), +]; + +class StaggeredExtentExtentPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return const StaggeredGridViewPage.extent( + title: 'Staggered (Extent, Extent)', + maxCrossAxisExtent: 150, + tiles: _tiles); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_grid_view_page.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_grid_view_page.dart new file mode 100644 index 00000000..85e191ea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/staggered_grid_view_page.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; +import 'tile_widget.dart'; + +class StaggeredGridViewPage extends StatelessWidget { + const StaggeredGridViewPage.count({ + @required this.title, + @required this.crossAxisCount, + @required this.tiles, + this.mainAxisSpacing = 4, + this.crossAxisSpacing = 4, + }) : _staggeredGridViewMode = _StaggeredGridViewMode.count, + maxCrossAxisExtent = null; + + const StaggeredGridViewPage.extent({ + @required this.title, + @required this.maxCrossAxisExtent, + @required this.tiles, + this.mainAxisSpacing = 4, + this.crossAxisSpacing = 4, + }) : _staggeredGridViewMode = _StaggeredGridViewMode.extent, + crossAxisCount = null; + + static const EdgeInsetsGeometry padding = EdgeInsets.symmetric(horizontal: 4); + + final String title; + final List tiles; + final int crossAxisCount; + final double mainAxisSpacing; + final double crossAxisSpacing; + final double maxCrossAxisExtent; + final _StaggeredGridViewMode _staggeredGridViewMode; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Padding( + padding: const EdgeInsets.only(top: 4), + child: _buildStaggeredGridView(context))); + } + + Widget _buildStaggeredGridView(BuildContext context) { + switch (_staggeredGridViewMode) { + case _StaggeredGridViewMode.count: + return StaggeredGridView.countBuilder( + crossAxisCount: crossAxisCount, + itemCount: tiles.length, + itemBuilder: _getChild, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + padding: padding, + staggeredTileBuilder: _getStaggeredTile, + ); + default: + return StaggeredGridView.extentBuilder( + maxCrossAxisExtent: maxCrossAxisExtent, + itemCount: tiles.length, + itemBuilder: _getChild, + mainAxisSpacing: mainAxisSpacing, + crossAxisSpacing: crossAxisSpacing, + padding: padding, + staggeredTileBuilder: _getStaggeredTile, + ); + } + } + + StaggeredTile _getStaggeredTile(int i) { + return i >= tiles.length ? null : tiles[i]; + } + + TileWidget _getChild(BuildContext context, int index) { + return TileWidget(key: ObjectKey(index), index: index); + } +} + +enum _StaggeredGridViewMode { count, extent } diff --git a/FlutterHelper/flutter_helper/lib/samples/staggerd/tile_widget.dart b/FlutterHelper/flutter_helper/lib/samples/staggerd/tile_widget.dart new file mode 100644 index 00000000..4003fb7d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/staggerd/tile_widget.dart @@ -0,0 +1,24 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class TileWidget extends StatelessWidget { + const TileWidget( + {Key key, @required this.index, this.backgroundColor = Colors.green}) + : super(key: key); + + final int index; + final Color backgroundColor; + + @override + Widget build(BuildContext context) { + return Container( + color: backgroundColor, + child: Center( + child: CircleAvatar( + backgroundColor: Colors.white, + child: Text('$index'), + )), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/step_touch/main.dart b/FlutterHelper/flutter_helper/lib/samples/step_touch/main.dart new file mode 100644 index 00000000..7b3b4a92 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/step_touch/main.dart @@ -0,0 +1,111 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/samples/step_touch/src/stepper.dart'; + +void main() => runApp( + MaterialApp( + theme: ThemeData( + scaffoldBackgroundColor: const Color(0xFF6D72FF), + ), + home: StepTouchApp(), + ), + ); + +class StepTouchApp extends StatefulWidget with HighMixin{ + @override + _StepTouchAppState createState() => _StepTouchAppState(); + + @override + High getHigh() => High(toStringShort(), """ + import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/samples/step_touch/src/stepper.dart'; + +void main() => runApp( + MaterialApp( + theme: ThemeData( + scaffoldBackgroundColor: const Color(0xFF6D72FF), + ), + home: StepTouchApp(), + ), + ); + +class StepTouchApp extends StatefulWidget with HighMixin{ + @override + _StepTouchAppState createState() => _StepTouchAppState(); + + @override + High getHigh() => High(toStringShort(), """ + """); +} + +class _StepTouchAppState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: StepperTouch( + initialValue: 0, + direction: Axis.vertical, + withSpring: false, + onChanged: (int value) => print('new value value'), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: StepperTouch( + initialValue: 0, + onChanged: (int value) => print('new value value'), + ), + ), + ], + ), + ), + ), + ); + } +} + + """); +} + +class _StepTouchAppState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: StepperTouch( + initialValue: 0, + direction: Axis.vertical, + withSpring: false, + onChanged: (int value) => print('new value $value'), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: StepperTouch( + initialValue: 0, + onChanged: (int value) => print('new value $value'), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/step_touch/src/stepper.dart b/FlutterHelper/flutter_helper/lib/samples/step_touch/src/stepper.dart new file mode 100644 index 00000000..ea89e2d1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/step_touch/src/stepper.dart @@ -0,0 +1,200 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/physics.dart'; + +/// the concept of the widget inspired +/// from [Nikolay Kuchkarov](https://dribbble.com/shots/3368130-Stepper-Touch). +/// i extended the functionality to be more useful in real world applications +class StepperTouch extends StatefulWidget { + const StepperTouch({ + Key key, + this.initialValue, + this.onChanged, + this.direction = Axis.horizontal, + this.withSpring = true, + this.counterColor = const Color(0xFF6D72FF), + this.dragButtonColor = Colors.white, + this.buttonsColor = Colors.white, + }) : super(key: key); + + /// the orientation of the stepper its horizontal or vertical. + final Axis direction; + + /// the initial value of the stepper + final int initialValue; + + /// called whenever the value of the stepper changed + final ValueChanged onChanged; + + /// if you want a springSimulation to happens the the user let go the stepper + /// defaults to true + final bool withSpring; + + final Color counterColor; + final Color dragButtonColor; + final Color buttonsColor; + + @override + _Stepper2State createState() => _Stepper2State(); +} + +class _Stepper2State extends State + with SingleTickerProviderStateMixin { + AnimationController _controller; + Animation _animation; + int _value; + double _startAnimationPosX; + double _startAnimationPosY; + + @override + void initState() { + super.initState(); + _value = widget.initialValue ?? 0; + _controller = + AnimationController(vsync: this, lowerBound: -0.5, upperBound: 0.5); + _controller.value = 0.0; + _controller.addListener(() {}); + + if (widget.direction == Axis.horizontal) { + _animation = Tween(begin: Offset(0.0, 0.0), end: Offset(1.5, 0.0)) + .animate(_controller); + } else { + _animation = Tween(begin: Offset(0.0, 0.0), end: Offset(0.0, 1.5)) + .animate(_controller); + } + } + + @override + void dispose() { + _controller?.dispose(); + super.dispose(); + } + + @override + void didUpdateWidget(oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.direction == Axis.horizontal) { + _animation = Tween(begin: Offset(0.0, 0.0), end: Offset(1.5, 0.0)) + .animate(_controller); + } else { + _animation = Tween(begin: Offset(0.0, 0.0), end: Offset(0.0, 1.5)) + .animate(_controller); + } + } + + @override + Widget build(BuildContext context) { + return FittedBox( + child: Container( + width: widget.direction == Axis.horizontal ? 280.0 : 120.0, + height: widget.direction == Axis.horizontal ? 120.0 : 280.0, + child: Material( + type: MaterialType.canvas, + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.circular(60.0), + color: Colors.white.withOpacity(0.2), + child: Stack( + alignment: Alignment.center, + children: [ + Positioned( + left: widget.direction == Axis.horizontal ? 10.0 : null, + bottom: widget.direction == Axis.horizontal ? null : 10.0, + child: + Icon(Icons.remove, size: 40.0, color: widget.buttonsColor), + ), + Positioned( + right: widget.direction == Axis.horizontal ? 10.0 : null, + top: widget.direction == Axis.horizontal ? null : 10.0, + child: Icon(Icons.add, size: 40.0, color: widget.buttonsColor), + ), + GestureDetector( + onHorizontalDragStart: _onPanStart, + onHorizontalDragUpdate: _onPanUpdate, + onHorizontalDragEnd: _onPanEnd, + child: SlideTransition( + position: _animation, + child: Material( + color: widget.dragButtonColor, + shape: const CircleBorder(), + elevation: 5.0, + child: Center( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 500), + transitionBuilder: + (Widget child, Animation animation) { + return ScaleTransition( + child: child, scale: animation); + }, + child: Text( + '$_value', + key: ValueKey(_value), + style: TextStyle( + color: widget.counterColor, fontSize: 56.0), + ), + ), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } + + double offsetFromGlobalPos(Offset globalPosition) { + RenderBox box = context.findRenderObject() as RenderBox; + Offset local = box.globalToLocal(globalPosition); + _startAnimationPosX = ((local.dx * 0.75) / box.size.width) - 0.4; + _startAnimationPosY = ((local.dy * 0.75) / box.size.height) - 0.4; + if (widget.direction == Axis.horizontal) { + return ((local.dx * 0.75) / box.size.width) - 0.4; + } else { + return ((local.dy * 0.75) / box.size.height) - 0.4; + } + } + + void _onPanStart(DragStartDetails details) { + _controller.stop(); + _controller.value = offsetFromGlobalPos(details.globalPosition); + } + + void _onPanUpdate(DragUpdateDetails details) { + _controller.value = offsetFromGlobalPos(details.globalPosition); + } + + void _onPanEnd(DragEndDetails details) { + _controller.stop(); + bool isHor = widget.direction == Axis.horizontal; + bool changed = false; + if (_controller.value <= -0.20) { + setState(() => isHor ? _value-- : _value++); + changed = true; + } else if (_controller.value >= 0.20) { + setState(() => isHor ? _value++ : _value--); + changed = true; + } + if (widget.withSpring) { + final SpringDescription _kDefaultSpring = + new SpringDescription.withDampingRatio( + mass: 0.9, + stiffness: 250.0, + ratio: 0.6, + ); + if (widget.direction == Axis.horizontal) { + _controller.animateWith( + SpringSimulation(_kDefaultSpring, _startAnimationPosX, 0.0, 0.0)); + } else { + _controller.animateWith( + SpringSimulation(_kDefaultSpring, _startAnimationPosY, 0.0, 0.0)); + } + } else { + _controller.animateTo(0.0, + curve: Curves.bounceOut, duration: Duration(milliseconds: 500)); + } + + if (changed && widget.onChanged != null) { + widget.onChanged(_value); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/step_touch/stepper_touch.dart b/FlutterHelper/flutter_helper/lib/samples/step_touch/stepper_touch.dart new file mode 100644 index 00000000..0fe5fa2b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/step_touch/stepper_touch.dart @@ -0,0 +1,3 @@ +library stepper_touch; + +export 'src/stepper.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/calendar_builders.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/calendar_builders.dart new file mode 100644 index 00000000..b97355bc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/calendar_builders.dart @@ -0,0 +1,99 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/widgets.dart'; + +import '../shared/utils.dart' show DayBuilder, FocusedDayBuilder; + +/// Signature for a function that creates a single event marker for a given `day`. +/// Contains a single `event` associated with that `day`. +typedef SingleMarkerBuilder = Widget Function( + BuildContext context, DateTime day, T event); + +/// Signature for a function that creates an event marker for a given `day`. +/// Contains a list of `events` associated with that `day`. +typedef MarkerBuilder = Widget Function( + BuildContext context, DateTime day, List events); + +/// Signature for a function that creates a background highlight for a given `day`. +/// +/// Used for highlighting current range selection. +/// Contains a value determining if the given `day` falls within the selected range. +typedef HighlightBuilder = Widget Function( + BuildContext context, DateTime day, bool isWithinRange); + +/// Class containing all custom builders for `TableCalendar`. +class CalendarBuilders { + /// Custom builder for day cells, with a priority over any other builder. + final FocusedDayBuilder prioritizedBuilder; + + /// Custom builder for a day cell that matches the current day. + final FocusedDayBuilder todayBuilder; + + /// Custom builder for day cells that are currently marked as selected by `selectedDayPredicate`. + final FocusedDayBuilder selectedBuilder; + + /// Custom builder for a day cell that is the start of current range selection. + final FocusedDayBuilder rangeStartBuilder; + + /// Custom builder for a day cell that is the end of current range selection. + final FocusedDayBuilder rangeEndBuilder; + + /// Custom builder for day cells that fall within the currently selected range. + final FocusedDayBuilder withinRangeBuilder; + + /// Custom builder for day cells, of which the `day.month` is different than `focusedDay.month`. + /// This will affect day cells that do not match the currently focused month. + final FocusedDayBuilder outsideBuilder; + + /// Custom builder for day cells that have been disabled. + /// + /// This refers to dates disabled by returning false in `enabledDayPredicate`, + /// as well as dates that are outside of the bounds set up by `firstDay` and `lastDay`. + final FocusedDayBuilder disabledBuilder; + + /// Custom builder for day cells that are marked as holidays by `holidayPredicate`. + final FocusedDayBuilder holidayBuilder; + + /// Custom builder for day cells that do not match any other builder. + final FocusedDayBuilder defaultBuilder; + + /// Custom builder for background highlight of range selection. + /// If `isWithinRange` is true, then `day` is within the selected range. + final HighlightBuilder rangeHighlightBuilder; + + /// Custom builder for a single event marker. Each of those will be displayed in a `Row` above of the day cell. + /// You can adjust markers' position with `CalendarStyle` properties. + /// + /// If `singleMarkerBuilder` is not specified, a default event marker will be displayed (customizable with `CalendarStyle`). + final SingleMarkerBuilder singleMarkerBuilder; + + /// Custom builder for event markers. Use to provide your own marker UI for each day cell. + /// Using `markerBuilder` will override `singleMarkerBuilder` and default event markers. + final MarkerBuilder markerBuilder; + + /// Custom builder for days of the week labels (Mon, Tue, Wed, etc.). + final DayBuilder dowBuilder; + + /// Use to customize header's title using different widget + final DayBuilder headerTitleBuilder; + + /// Creates `CalendarBuilders` for `TableCalendar` widget. + const CalendarBuilders({ + this.prioritizedBuilder, + this.todayBuilder, + this.selectedBuilder, + this.rangeStartBuilder, + this.rangeEndBuilder, + this.withinRangeBuilder, + this.outsideBuilder, + this.disabledBuilder, + this.holidayBuilder, + this.defaultBuilder, + this.rangeHighlightBuilder, + this.singleMarkerBuilder, + this.markerBuilder, + this.dowBuilder, + this.headerTitleBuilder, + }); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/calendar_style.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/calendar_style.dart new file mode 100644 index 00000000..088225b7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/calendar_style.dart @@ -0,0 +1,228 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/widgets.dart'; + +/// Class containing styling and configuration for `TableCalendar`'s content. +class CalendarStyle { + /// Maximum amount of single event marker dots to be displayed. + final int markersMaxCount; + + /// Specifies if event markers rendered for a day cell can overflow cell's boundaries. + /// * `true` - Event markers will be drawn over the cell boundaries + /// * `false` - Event markers will be clipped if they are too big + final bool canMarkersOverflow; + + /// Determines if single event marker dots should be aligned automatically with `markersAnchor`. + /// If `false`, `markersOffset` will be used instead. + final bool markersAutoAligned; + + /// Specifies the anchor point of single event markers if `markersAutoAligned` is `true`. + /// A value of `0.5` will center the markers at the bottom edge of day cell's decoration. + /// + /// Includes `cellMargin` for calculations. + final double markersAnchor; + + /// The size of single event marker dot. + /// + /// By default `markerSizeScale` is used. To use `markerSize` instead, simply provide a non-null value. + final double markerSize; + + /// Proportion of single event marker dot size in relation to day cell size. + /// + /// Includes `cellMargin` for calculations. + final double markerSizeScale; + + /// `PositionedOffset` for event markers. Allows to specify `top`, `bottom`, `start` and `end`. + final PositionedOffset markersOffset; + + /// General `Alignment` for event markers. + /// Will have no effect on markers if `markersAutoAligned` or `markersOffset` is used. + final AlignmentGeometry markersAlignment; + + /// Decoration of single event markers. Affects each marker dot. + final Decoration markerDecoration; + + /// Margin of single event markers. Affects each marker dot. + final EdgeInsets markerMargin; + + /// Margin of each individual day cell. + final EdgeInsets cellMargin; + + /// Proportion of range selection highlight size in relation to day cell size. + /// + /// Includes `cellMargin` for calculations. + final double rangeHighlightScale; + + /// Color of range selection highlight. + final Color rangeHighlightColor; + + /// Determines if day cells that do not match the currently focused month should be visible. + /// + /// Affects only `CalendarFormat.month`. + final bool outsideDaysVisible; + + /// Determines if a day cell that matches the current day should be highlighted. + final bool isTodayHighlighted; + + /// TextStyle for a day cell that matches the current day. + final TextStyle todayTextStyle; + + /// Decoration for a day cell that matches the current day. + final Decoration todayDecoration; + + /// TextStyle for day cells that are currently marked as selected by `selectedDayPredicate`. + final TextStyle selectedTextStyle; + + /// Decoration for day cells that are currently marked as selected by `selectedDayPredicate`. + final Decoration selectedDecoration; + + /// TextStyle for a day cell that is the start of current range selection. + final TextStyle rangeStartTextStyle; + + /// Decoration for a day cell that is the start of current range selection. + final Decoration rangeStartDecoration; + + /// TextStyle for a day cell that is the end of current range selection. + final TextStyle rangeEndTextStyle; + + /// Decoration for a day cell that is the end of current range selection. + final Decoration rangeEndDecoration; + + /// TextStyle for day cells that fall within the currently selected range. + final TextStyle withinRangeTextStyle; + + /// Decoration for day cells that fall within the currently selected range. + final Decoration withinRangeDecoration; + + /// TextStyle for day cells, of which the `day.month` is different than `focusedDay.month`. + /// This will affect day cells that do not match the currently focused month. + final TextStyle outsideTextStyle; + + /// Decoration for day cells, of which the `day.month` is different than `focusedDay.month`. + /// This will affect day cells that do not match the currently focused month. + final Decoration outsideDecoration; + + /// TextStyle for day cells that have been disabled. + /// + /// This refers to dates disabled by returning false in `enabledDayPredicate`, + /// as well as dates that are outside of the bounds set up by `firstDay` and `lastDay`. + final TextStyle disabledTextStyle; + + /// Decoration for day cells that have been disabled. + /// + /// This refers to dates disabled by returning false in `enabledDayPredicate`, + /// as well as dates that are outside of the bounds set up by `firstDay` and `lastDay`. + final Decoration disabledDecoration; + + /// TextStyle for day cells that are marked as holidays by `holidayPredicate`. + final TextStyle holidayTextStyle; + + /// Decoration for day cells that are marked as holidays by `holidayPredicate`. + final Decoration holidayDecoration; + + /// TextStyle for day cells that match `weekendDay` list. + final TextStyle weekendTextStyle; + + /// Decoration for day cells that match `weekendDay` list. + final Decoration weekendDecoration; + + /// TextStyle for day cells that do not match any other styles. + final TextStyle defaultTextStyle; + + /// Decoration for day cells that do not match any other styles. + final Decoration defaultDecoration; + + /// Decoration for each interior row of day cells. + final Decoration rowDecoration; + + /// Creates a `CalendarStyle` used by `TableCalendar` widget. + const CalendarStyle({ + this.isTodayHighlighted = true, + this.canMarkersOverflow = true, + this.outsideDaysVisible = true, + this.markersAutoAligned = true, + this.markerSize, + this.markerSizeScale = 0.2, + this.markersAnchor = 0.7, + this.rangeHighlightScale = 1.0, + this.markerMargin = const EdgeInsets.symmetric(horizontal: 0.3), + this.markersAlignment = Alignment.bottomCenter, + this.markersMaxCount = 4, + this.cellMargin = const EdgeInsets.all(6.0), + this.markersOffset = const PositionedOffset(), + this.rangeHighlightColor = const Color(0xFFBBDDFF), + this.markerDecoration = const BoxDecoration( + color: const Color(0xFF263238), + shape: BoxShape.circle, + ), + this.todayTextStyle = const TextStyle( + color: const Color(0xFFFAFAFA), + fontSize: 16.0, + ), // + this.todayDecoration = const BoxDecoration( + color: const Color(0xFF9FA8DA), + shape: BoxShape.circle, + ), + this.selectedTextStyle = const TextStyle( + color: const Color(0xFFFAFAFA), + fontSize: 16.0, + ), + this.selectedDecoration = const BoxDecoration( + color: const Color(0xFF5C6BC0), + shape: BoxShape.circle, + ), + this.rangeStartTextStyle = const TextStyle( + color: const Color(0xFFFAFAFA), + fontSize: 16.0, + ), + this.rangeStartDecoration = const BoxDecoration( + color: const Color(0xFF6699FF), + shape: BoxShape.circle, + ), + this.rangeEndTextStyle = const TextStyle( + color: const Color(0xFFFAFAFA), + fontSize: 16.0, + ), + this.rangeEndDecoration = const BoxDecoration( + color: const Color(0xFF6699FF), + shape: BoxShape.circle, + ), + this.withinRangeTextStyle = const TextStyle(), + this.withinRangeDecoration = const BoxDecoration(shape: BoxShape.circle), + this.outsideTextStyle = const TextStyle(color: const Color(0xFFAEAEAE)), + this.outsideDecoration = const BoxDecoration(shape: BoxShape.circle), + this.disabledTextStyle = const TextStyle(color: const Color(0xFFBFBFBF)), + this.disabledDecoration = const BoxDecoration(shape: BoxShape.circle), + this.holidayTextStyle = const TextStyle(color: const Color(0xFF5C6BC0)), + this.holidayDecoration = const BoxDecoration( + border: const Border.fromBorderSide( + const BorderSide(color: const Color(0xFF9FA8DA), width: 1.4), + ), + shape: BoxShape.circle, + ), + this.weekendTextStyle = const TextStyle(color: const Color(0xFF5A5A5A)), + this.weekendDecoration = const BoxDecoration(shape: BoxShape.circle), + this.defaultTextStyle = const TextStyle(), + this.defaultDecoration = const BoxDecoration(shape: BoxShape.circle), + this.rowDecoration = const BoxDecoration(), + }); +} + +/// Helper class containing data for internal `Positioned` widget. +class PositionedOffset { + /// Distance from the top edge. + final double top; + + /// Distance from the bottom edge. + final double bottom; + + /// Distance from the leading edge. + final double start; + + /// Distance from the trailing edge. + final double end; + + /// Creates a `PositionedOffset`. Values are set to `null` by default. + const PositionedOffset({this.top, this.bottom, this.start, this.end}); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/days_of_week_style.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/days_of_week_style.dart new file mode 100644 index 00000000..99785fe9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/days_of_week_style.dart @@ -0,0 +1,36 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/widgets.dart'; + +import '../shared/utils.dart' show TextFormatter; + +/// Class containing styling for `TableCalendar`'s days of week panel. +class DaysOfWeekStyle { + /// Use to customize days of week panel text (e.g. with different `DateFormat`). + /// You can use `String` transformations to further customize the text. + /// Defaults to simple `'E'` format (i.e. Mon, Tue, Wed, etc.). + /// + /// Example usage: + /// ```dart + /// dowTextFormatter: (date, locale) => DateFormat.E(locale).format(date)[0], + /// ``` + final TextFormatter dowTextFormatter; + + /// Decoration for the top row of the table + final Decoration decoration; + + /// Style for weekdays on the top of calendar. + final TextStyle weekdayStyle; + + /// Style for weekend days on the top of calendar. + final TextStyle weekendStyle; + + /// Creates a `DaysOfWeekStyle` used by `TableCalendar` widget. + const DaysOfWeekStyle({ + this.dowTextFormatter, + this.decoration = const BoxDecoration(), + this.weekdayStyle = const TextStyle(color: const Color(0xFF4F4F4F)), + this.weekendStyle = const TextStyle(color: const Color(0xFF6A6A6A)), + }); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/header_style.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/header_style.dart new file mode 100644 index 00000000..65e84f77 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/customization/header_style.dart @@ -0,0 +1,108 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; + +import '../shared/utils.dart' show TextFormatter; + +/// Class containing styling and configuration of `TableCalendar`'s header. +class HeaderStyle { + /// Responsible for making title Text centered. + final bool titleCentered; + + /// Responsible for FormatButton visibility. + final bool formatButtonVisible; + + /// Controls the text inside FormatButton. + /// * `true` - the button will show next CalendarFormat + /// * `false` - the button will show current CalendarFormat + final bool formatButtonShowsNext; + + /// Use to customize header's title text (e.g. with different `DateFormat`). + /// You can use `String` transformations to further customize the text. + /// Defaults to simple `'yMMMM'` format (i.e. January 2019, February 2019, March 2019, etc.). + /// + /// Example usage: + /// ```dart + /// titleTextFormatter: (date, locale) => DateFormat.yM(locale).format(date), + /// ``` + final TextFormatter titleTextFormatter; + + /// Style for title Text (month-year) displayed in header. + final TextStyle titleTextStyle; + + /// Style for FormatButton `Text`. + final TextStyle formatButtonTextStyle; + + /// Background `Decoration` for FormatButton. + final Decoration formatButtonDecoration; + + /// Internal padding of the whole header. + final EdgeInsets headerPadding; + + /// External margin of the whole header. + final EdgeInsets headerMargin; + + /// Internal padding of FormatButton. + final EdgeInsets formatButtonPadding; + + /// Internal padding of left chevron. + /// Determines how much of ripple animation is visible during taps. + final EdgeInsets leftChevronPadding; + + /// Internal padding of right chevron. + /// Determines how much of ripple animation is visible during taps. + final EdgeInsets rightChevronPadding; + + /// External margin of left chevron. + final EdgeInsets leftChevronMargin; + + /// External margin of right chevron. + final EdgeInsets rightChevronMargin; + + /// Widget used for left chevron. + /// + /// Tapping on it will navigate to previous calendar page. + final Widget leftChevronIcon; + + /// Widget used for right chevron. + /// + /// Tapping on it will navigate to next calendar page. + final Widget rightChevronIcon; + + /// Determines left chevron's visibility. + final bool leftChevronVisible; + + /// Determines right chevron's visibility. + final bool rightChevronVisible; + + /// Decoration of the header. + final Decoration decoration; + + /// Creates a `HeaderStyle` used by `TableCalendar` widget. + const HeaderStyle({ + this.titleCentered = false, + this.formatButtonVisible = true, + this.formatButtonShowsNext = true, + this.titleTextFormatter, + this.titleTextStyle = const TextStyle(fontSize: 17.0), + this.formatButtonTextStyle = const TextStyle(), + this.formatButtonDecoration = const BoxDecoration( + border: const Border.fromBorderSide(BorderSide()), + borderRadius: const BorderRadius.all(Radius.circular(12.0)), + ), + this.headerMargin = const EdgeInsets.all(0.0), + this.headerPadding = const EdgeInsets.symmetric(vertical: 8.0), + this.formatButtonPadding = + const EdgeInsets.symmetric(horizontal: 10.0, vertical: 4.0), + this.leftChevronPadding = const EdgeInsets.all(12.0), + this.rightChevronPadding = const EdgeInsets.all(12.0), + this.leftChevronMargin = const EdgeInsets.symmetric(horizontal: 8.0), + this.rightChevronMargin = const EdgeInsets.symmetric(horizontal: 8.0), + this.leftChevronIcon = const Icon(Icons.chevron_left), + this.rightChevronIcon = const Icon(Icons.chevron_right), + this.leftChevronVisible = true, + this.rightChevronVisible = true, + this.decoration = const BoxDecoration(), + }); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/shared/utils.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/shared/utils.dart new file mode 100644 index 00000000..d5f49b44 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/shared/utils.dart @@ -0,0 +1,54 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/widgets.dart'; + +/// Signature for a function that creates a widget for a given `day`. +typedef DayBuilder = Widget Function(BuildContext context, DateTime day); + +/// Signature for a function that creates a widget for a given `day`. +/// Additionally, contains the currently focused day. +typedef FocusedDayBuilder = Widget Function( + BuildContext context, DateTime day, DateTime focusedDay); + +/// Signature for a function returning text that can be localized and formatted with `DateFormat`. +typedef TextFormatter = String Function(DateTime date, dynamic locale); + +/// Gestures available for the calendar. +enum AvailableGestures { none, verticalSwipe, horizontalSwipe, all } + +/// Formats that the calendar can display. +enum CalendarFormat { month, twoWeeks, week } + +/// Days of the week that the calendar can start with. +enum StartingDayOfWeek { + monday, + tuesday, + wednesday, + thursday, + friday, + saturday, + sunday, +} + +/// Returns a numerical value associated with given `weekday`. +/// +/// Returns 1 for `StartingDayOfWeek.monday`, all the way to 7 for `StartingDayOfWeek.sunday`. +int getWeekdayNumber(StartingDayOfWeek weekday) { + return StartingDayOfWeek.values.indexOf(weekday) + 1; +} + +/// Returns `date` in UTC format, without its time part. +DateTime normalizeDate(DateTime date) { + return DateTime.utc(date.year, date.month, date.day); +} + +/// Checks if two DateTime objects are the same day. +/// Returns `false` if either of them is null. +bool isSameDay(DateTime a, DateTime b) { + if (a == null || b == null) { + return false; + } + + return a.year == b.year && a.month == b.month && a.day == b.day; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/table_calendar.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/table_calendar.dart new file mode 100644 index 00000000..7cf865e9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/table_calendar.dart @@ -0,0 +1,736 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:math'; + +import 'package:flutter/widgets.dart'; +import 'package:intl/intl.dart'; +import 'package:simple_gesture_detector/simple_gesture_detector.dart'; + +import 'customization/calendar_builders.dart'; +import 'customization/calendar_style.dart'; +import 'customization/days_of_week_style.dart'; +import 'customization/header_style.dart'; +import 'shared/utils.dart'; +import 'table_calendar_base.dart'; +import 'widgets/calendar_header.dart'; +import 'widgets/cell_content.dart'; + +/// Signature for `onDaySelected` callback. Contains the selected day and focused day. +typedef OnDaySelected = void Function( + DateTime selectedDay, DateTime focusedDay); + +/// Signature for `onRangeSelected` callback. +/// Contains start and end of the selected range, as well as currently focused day. +typedef OnRangeSelected = void Function( + DateTime start, DateTime end, DateTime focusedDay); + +/// Modes that range selection can operate in. +enum RangeSelectionMode { disabled, toggledOff, toggledOn, enforced } + +/// Highly customizable, feature-packed Flutter calendar with gestures, animations and multiple formats. +class TableCalendar extends StatefulWidget { + /// Locale to format `TableCalendar` dates with, for example: `'en_US'`. + /// + /// If nothing is provided, a default locale will be used. + final dynamic locale; + + /// The start of the selected day range. + final DateTime rangeStartDay; + + /// The end of the selected day range. + final DateTime rangeEndDay; + + /// DateTime that determines which days are currently visible and focused. + final DateTime focusedDay; + + /// The first active day of `TableCalendar`. + /// Blocks swiping to days before it. + /// + /// Days before it will use `disabledStyle` and trigger `onDisabledDayTapped` callback. + final DateTime firstDay; + + /// The last active day of `TableCalendar`. + /// Blocks swiping to days after it. + /// + /// Days after it will use `disabledStyle` and trigger `onDisabledDayTapped` callback. + final DateTime lastDay; + + /// DateTime that will be treated as today. Defaults to `DateTime.now()`. + /// + /// Overriding this property might be useful for testing. + final DateTime currentDay; + + /// List of days treated as weekend days. + /// Use built-in `DateTime` weekday constants (e.g. `DateTime.monday`) instead of `int` literals (e.g. `1`). + final List weekendDays; + + /// Specifies `TableCalendar`'s current format. + final CalendarFormat calendarFormat; + + /// `Map` of `CalendarFormat`s and `String` names associated with them. + /// Those `CalendarFormat`s will be used by internal logic to manage displayed format. + /// + /// To ensure proper vertical swipe behavior, `CalendarFormat`s should be in descending order (i.e. from biggest to smallest). + /// + /// For example: + /// ```dart + /// availableCalendarFormats: const { + /// CalendarFormat.month: 'Month', + /// CalendarFormat.week: 'Week', + /// } + /// ``` + final Map availableCalendarFormats; + + /// Determines the visibility of calendar header. + final bool headerVisible; + + /// Determines the visibility of the row of days of the week. + final bool daysOfWeekVisible; + + /// When set to true, tapping on an outside day in `CalendarFormat.month` format + /// will jump to the calendar page of the tapped month. + final bool pageJumpingEnabled; + + /// When set to true, updating the `focusedDay` will display a scrolling animation + /// if the currently visible calendar page is changed. + final bool pageAnimationEnabled; + + /// When set to true, `CalendarFormat.month` will always display six weeks, + /// even if the content would fit in less. + final bool sixWeekMonthsEnforced; + + /// When set to true, `TableCalendar` will fill available height. + final bool shouldFillViewport; + + /// Used for setting the height of `TableCalendar`'s rows. + final double rowHeight; + + /// Used for setting the height of `TableCalendar`'s days of week row. + final double daysOfWeekHeight; + + /// Specifies the duration of size animation that takes place whenever `calendarFormat` is changed. + final Duration formatAnimationDuration; + + /// Specifies the curve of size animation that takes place whenever `calendarFormat` is changed. + final Curve formatAnimationCurve; + + /// Specifies the duration of scrolling animation that takes place whenever the visible calendar page is changed. + final Duration pageAnimationDuration; + + /// Specifies the curve of scrolling animation that takes place whenever the visible calendar page is changed. + final Curve pageAnimationCurve; + + /// `TableCalendar` will start weeks with provided day. + /// + /// Use `StartingDayOfWeek.monday` for Monday - Sunday week format. + /// Use `StartingDayOfWeek.sunday` for Sunday - Saturday week format. + final StartingDayOfWeek startingDayOfWeek; + + /// `HitTestBehavior` for every day cell inside `TableCalendar`. + final HitTestBehavior dayHitTestBehavior; + + /// Specifies swipe gestures available to `TableCalendar`. + /// If `AvailableGestures.none` is used, the calendar will only be interactive via buttons. + final AvailableGestures availableGestures; + + /// Configuration for vertical swipe detector. + final SimpleSwipeConfig simpleSwipeConfig; + + /// Style for `TableCalendar`'s header. + final HeaderStyle headerStyle; + + /// Style for days of week displayed between `TableCalendar`'s header and content. + final DaysOfWeekStyle daysOfWeekStyle; + + /// Style for `TableCalendar`'s content. + final CalendarStyle calendarStyle; + + /// Set of custom builders for `TableCalendar` to work with. + /// Use those to fully tailor the UI. + final CalendarBuilders calendarBuilders; + + /// Current mode of range selection. + /// + /// * `RangeSelectionMode.disabled` - range selection is always off. + /// * `RangeSelectionMode.toggledOff` - range selection is currently off, can be toggled by longpressing a day cell. + /// * `RangeSelectionMode.toggledOn` - range selection is currently on, can be toggled by longpressing a day cell. + /// * `RangeSelectionMode.enforced` - range selection is always on. + final RangeSelectionMode rangeSelectionMode; + + /// Function that assigns a list of events to a specified day. + final List Function(DateTime day) eventLoader; + + /// Function deciding whether given day should be enabled or not. + /// If `false` is returned, this day will be disabled. + final bool Function(DateTime day) enabledDayPredicate; + + /// Function deciding whether given day should be marked as selected. + final bool Function(DateTime day) selectedDayPredicate; + + /// Function deciding whether given day is treated as a holiday. + final bool Function(DateTime day) holidayPredicate; + + /// Called whenever a day range gets selected. + final OnRangeSelected onRangeSelected; + + /// Called whenever any day gets tapped. + final OnDaySelected onDaySelected; + + /// Called whenever any day gets long pressed. + final OnDaySelected onDayLongPressed; + + /// Called whenever any disabled day gets tapped. + final void Function(DateTime day) onDisabledDayTapped; + + /// Called whenever any disabled day gets long pressed. + final void Function(DateTime day) onDisabledDayLongPressed; + + /// Called whenever header gets tapped. + final void Function(DateTime focusedDay) onHeaderTapped; + + /// Called whenever header gets long pressed. + final void Function(DateTime focusedDay) onHeaderLongPressed; + + /// Called whenever currently visible calendar page is changed. + final void Function(DateTime focusedDay) onPageChanged; + + /// Called whenever `calendarFormat` is changed. + final void Function(CalendarFormat format) onFormatChanged; + + /// Called when the calendar is created. Exposes its PageController. + final void Function(PageController pageController) onCalendarCreated; + + /// Creates a `TableCalendar` widget. + TableCalendar({ + Key key, + @required DateTime focusedDay, + @required DateTime firstDay, + @required DateTime lastDay, + DateTime currentDay, + this.locale, + this.rangeStartDay, + this.rangeEndDay, + this.weekendDays = const [DateTime.saturday, DateTime.sunday], + this.calendarFormat = CalendarFormat.month, + this.availableCalendarFormats = const { + CalendarFormat.month: 'Month', + CalendarFormat.twoWeeks: '2 weeks', + CalendarFormat.week: 'Week', + }, + this.headerVisible = true, + this.daysOfWeekVisible = true, + this.pageJumpingEnabled = false, + this.pageAnimationEnabled = true, + this.sixWeekMonthsEnforced = false, + this.shouldFillViewport = false, + this.rowHeight = 52.0, + this.daysOfWeekHeight = 16.0, + this.formatAnimationDuration = const Duration(milliseconds: 200), + this.formatAnimationCurve = Curves.linear, + this.pageAnimationDuration = const Duration(milliseconds: 300), + this.pageAnimationCurve = Curves.easeOut, + this.startingDayOfWeek = StartingDayOfWeek.sunday, + this.dayHitTestBehavior = HitTestBehavior.opaque, + this.availableGestures = AvailableGestures.all, + this.simpleSwipeConfig = const SimpleSwipeConfig( + verticalThreshold: 25.0, + swipeDetectionBehavior: SwipeDetectionBehavior.continuousDistinct, + ), + this.headerStyle = const HeaderStyle(), + this.daysOfWeekStyle = const DaysOfWeekStyle(), + this.calendarStyle = const CalendarStyle(), + this.calendarBuilders = const CalendarBuilders(), + this.rangeSelectionMode = RangeSelectionMode.toggledOff, + this.eventLoader, + this.enabledDayPredicate, + this.selectedDayPredicate, + this.holidayPredicate, + this.onRangeSelected, + this.onDaySelected, + this.onDayLongPressed, + this.onDisabledDayTapped, + this.onDisabledDayLongPressed, + this.onHeaderTapped, + this.onHeaderLongPressed, + this.onPageChanged, + this.onFormatChanged, + this.onCalendarCreated, + }) : assert(availableCalendarFormats.keys.contains(calendarFormat)), + assert(availableCalendarFormats.length <= CalendarFormat.values.length), + assert(weekendDays.isNotEmpty + ? weekendDays.every( + (day) => day >= DateTime.monday && day <= DateTime.sunday) + : true), + focusedDay = normalizeDate(focusedDay), + firstDay = normalizeDate(firstDay), + lastDay = normalizeDate(lastDay), + currentDay = currentDay ?? DateTime.now(), + super(key: key); + + @override + _TableCalendarState createState() => _TableCalendarState(); +} + +class _TableCalendarState extends State> { + PageController _pageController; + ValueNotifier _focusedDay; + RangeSelectionMode _rangeSelectionMode; + DateTime _firstSelectedDay; + + @override + void initState() { + super.initState(); + _focusedDay = ValueNotifier(widget.focusedDay); + _rangeSelectionMode = widget.rangeSelectionMode; + } + + @override + void didUpdateWidget(TableCalendar oldWidget) { + super.didUpdateWidget(oldWidget); + + if (_focusedDay.value != widget.focusedDay) { + _focusedDay.value = widget.focusedDay; + } + + if (_rangeSelectionMode != widget.rangeSelectionMode) { + _rangeSelectionMode = widget.rangeSelectionMode; + } + + if (widget.rangeStartDay == null && widget.rangeEndDay == null) { + _firstSelectedDay = null; + } + } + + @override + void dispose() { + _focusedDay.dispose(); + super.dispose(); + } + + bool get _isRangeSelectionToggleable => + _rangeSelectionMode == RangeSelectionMode.toggledOn || + _rangeSelectionMode == RangeSelectionMode.toggledOff; + + bool get _isRangeSelectionOn => + _rangeSelectionMode == RangeSelectionMode.toggledOn || + _rangeSelectionMode == RangeSelectionMode.enforced; + + bool get _shouldBlockOutsideDays => + !widget.calendarStyle.outsideDaysVisible && + widget.calendarFormat == CalendarFormat.month; + + void _swipeCalendarFormat(SwipeDirection direction) { + if (widget.onFormatChanged != null) { + final formats = widget.availableCalendarFormats.keys.toList(); + + final isSwipeUp = direction == SwipeDirection.up; + int id = formats.indexOf(widget.calendarFormat); + + // Order of CalendarFormats must be from biggest to smallest, + // e.g.: [month, twoWeeks, week] + if (isSwipeUp) { + id = min(formats.length - 1, id + 1); + } else { + id = max(0, id - 1); + } + + widget.onFormatChanged(formats[id]); + } + } + + void _onDayTapped(DateTime day) { + final isOutside = day.month != _focusedDay.value.month; + if (isOutside && _shouldBlockOutsideDays) { + return; + } + + if (_isDayDisabled(day)) { + return widget.onDisabledDayTapped?.call(day); + } + + _updateFocusOnTap(day); + + if (_isRangeSelectionOn && widget.onRangeSelected != null) { + if (_firstSelectedDay == null) { + _firstSelectedDay = day; + widget.onRangeSelected(_firstSelectedDay, null, _focusedDay.value); + } else { + if (day.isAfter(_firstSelectedDay)) { + widget.onRangeSelected(_firstSelectedDay, day, _focusedDay.value); + _firstSelectedDay = null; + } else if (day.isBefore(_firstSelectedDay)) { + widget.onRangeSelected(day, _firstSelectedDay, _focusedDay.value); + _firstSelectedDay = null; + } + } + } else { + widget.onDaySelected?.call(day, _focusedDay.value); + } + } + + void _onDayLongPressed(DateTime day) { + final isOutside = day.month != _focusedDay.value.month; + if (isOutside && _shouldBlockOutsideDays) { + return; + } + + if (_isDayDisabled(day)) { + return widget.onDisabledDayLongPressed?.call(day); + } + + if (widget.onDayLongPressed != null) { + _updateFocusOnTap(day); + return widget.onDayLongPressed(day, _focusedDay.value); + } + + if (widget.onRangeSelected != null) { + if (_isRangeSelectionToggleable) { + _updateFocusOnTap(day); + _toggleRangeSelection(); + + if (_isRangeSelectionOn) { + _firstSelectedDay = day; + widget.onRangeSelected(_firstSelectedDay, null, _focusedDay.value); + } else { + _firstSelectedDay = null; + widget.onDaySelected?.call(day, _focusedDay.value); + } + } + } + } + + void _updateFocusOnTap(DateTime day) { + if (widget.pageJumpingEnabled) { + _focusedDay.value = day; + return; + } + + if (widget.calendarFormat == CalendarFormat.month) { + if (_isBeforeMonth(day, _focusedDay.value)) { + _focusedDay.value = _firstDayOfMonth(_focusedDay.value); + } else if (_isAfterMonth(day, _focusedDay.value)) { + _focusedDay.value = _lastDayOfMonth(_focusedDay.value); + } else { + _focusedDay.value = day; + } + } else { + _focusedDay.value = day; + } + } + + void _toggleRangeSelection() { + if (_rangeSelectionMode == RangeSelectionMode.toggledOn) { + _rangeSelectionMode = RangeSelectionMode.toggledOff; + } else { + _rangeSelectionMode = RangeSelectionMode.toggledOn; + } + } + + void _onLeftChevronTap() { + _pageController.previousPage( + duration: widget.pageAnimationDuration, + curve: widget.pageAnimationCurve, + ); + } + + void _onRightChevronTap() { + _pageController.nextPage( + duration: widget.pageAnimationDuration, + curve: widget.pageAnimationCurve, + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + if (widget.headerVisible) + ValueListenableBuilder( + valueListenable: _focusedDay, + builder: (context, value, _) { + return CalendarHeader( + headerTitleBuilder: widget.calendarBuilders.headerTitleBuilder, + focusedMonth: value, + onLeftChevronTap: _onLeftChevronTap, + onRightChevronTap: _onRightChevronTap, + onHeaderTap: () => widget.onHeaderTapped?.call(value), + onHeaderLongPress: () => + widget.onHeaderLongPressed?.call(value), + headerStyle: widget.headerStyle, + availableCalendarFormats: widget.availableCalendarFormats, + calendarFormat: widget.calendarFormat, + locale: widget.locale, + onFormatButtonTap: (format) { + assert( + widget.onFormatChanged != null, + 'Using `FormatButton` without providing `onFormatChanged` will have no effect.', + ); + + widget.onFormatChanged?.call(format); + }, + ); + }, + ), + Flexible( + flex: widget.shouldFillViewport ? 1 : 0, + child: TableCalendarBase( + onCalendarCreated: (pageController) { + _pageController = pageController; + widget.onCalendarCreated?.call(pageController); + }, + focusedDay: _focusedDay.value, + calendarFormat: widget.calendarFormat, + availableGestures: widget.availableGestures, + firstDay: widget.firstDay, + lastDay: widget.lastDay, + startingDayOfWeek: widget.startingDayOfWeek, + dowDecoration: widget.daysOfWeekStyle.decoration, + rowDecoration: widget.calendarStyle.rowDecoration, + dowVisible: widget.daysOfWeekVisible, + dowHeight: widget.daysOfWeekHeight, + rowHeight: widget.rowHeight, + formatAnimationDuration: widget.formatAnimationDuration, + formatAnimationCurve: widget.formatAnimationCurve, + pageAnimationEnabled: widget.pageAnimationEnabled, + pageAnimationDuration: widget.pageAnimationDuration, + pageAnimationCurve: widget.pageAnimationCurve, + availableCalendarFormats: widget.availableCalendarFormats, + simpleSwipeConfig: widget.simpleSwipeConfig, + sixWeekMonthsEnforced: widget.sixWeekMonthsEnforced, + onVerticalSwipe: _swipeCalendarFormat, + onPageChanged: (focusedDay) { + _focusedDay.value = focusedDay; + widget.onPageChanged?.call(focusedDay); + }, + dowBuilder: (BuildContext context, DateTime day) { + Widget dowCell = + widget.calendarBuilders.dowBuilder?.call(context, day); + + if (dowCell == null) { + final weekdayString = widget.daysOfWeekStyle.dowTextFormatter + ?.call(day, widget.locale) ?? + DateFormat.E(widget.locale).format(day); + + final isWeekend = + _isWeekend(day, weekendDays: widget.weekendDays); + + dowCell = Center( + child: Text( + weekdayString, + style: isWeekend + ? widget.daysOfWeekStyle.weekendStyle + : widget.daysOfWeekStyle.weekdayStyle, + ), + ); + } + + return dowCell; + }, + dayBuilder: (context, day, focusedMonth) { + return GestureDetector( + behavior: widget.dayHitTestBehavior, + onTap: () => _onDayTapped(day), + onLongPress: () => _onDayLongPressed(day), + child: _buildCell(day, focusedMonth), + ); + }, + ), + ), + ], + ); + } + + Widget _buildCell(DateTime day, DateTime focusedDay) { + final isOutside = day.month != focusedDay.month; + + if (isOutside && _shouldBlockOutsideDays) { + return Container(); + } + + return LayoutBuilder( + builder: (context, constraints) { + final shorterSide = constraints.maxHeight > constraints.maxWidth + ? constraints.maxWidth + : constraints.maxHeight; + + final children = []; + + final isWithinRange = widget.rangeStartDay != null && + widget.rangeEndDay != null && + _isWithinRange(day, widget.rangeStartDay, widget.rangeEndDay); + + final isRangeStart = isSameDay(day, widget.rangeStartDay); + final isRangeEnd = isSameDay(day, widget.rangeEndDay); + + Widget rangeHighlight = widget.calendarBuilders.rangeHighlightBuilder + ?.call(context, day, isWithinRange); + + if (rangeHighlight == null) { + if (isWithinRange) { + rangeHighlight = Center( + child: Container( + margin: EdgeInsetsDirectional.only( + start: isRangeStart ? constraints.maxWidth * 0.5 : 0.0, + end: isRangeEnd ? constraints.maxWidth * 0.5 : 0.0, + ), + height: + (shorterSide - widget.calendarStyle.cellMargin.vertical) * + widget.calendarStyle.rangeHighlightScale, + color: widget.calendarStyle.rangeHighlightColor, + ), + ); + } + } + + if (rangeHighlight != null) { + children.add(rangeHighlight); + } + + final isToday = isSameDay(day, widget.currentDay); + final isDisabled = _isDayDisabled(day); + final isWeekend = _isWeekend(day, weekendDays: widget.weekendDays); + + Widget content = CellContent( + day: day, + focusedDay: focusedDay, + calendarStyle: widget.calendarStyle, + calendarBuilders: widget.calendarBuilders, + isTodayHighlighted: widget.calendarStyle.isTodayHighlighted, + isToday: isToday, + isSelected: widget.selectedDayPredicate?.call(day) ?? false, + isRangeStart: isRangeStart, + isRangeEnd: isRangeEnd, + isWithinRange: isWithinRange, + isOutside: isOutside, + isDisabled: isDisabled, + isWeekend: isWeekend, + isHoliday: widget.holidayPredicate?.call(day) ?? false, + ); + + children.add(content); + + if (!isDisabled) { + final events = widget.eventLoader?.call(day) ?? []; + Widget markerWidget = + widget.calendarBuilders.markerBuilder?.call(context, day, events); + + if (events.isNotEmpty && markerWidget == null) { + final center = constraints.maxHeight / 2; + + final markerSize = widget.calendarStyle.markerSize ?? + (shorterSide - widget.calendarStyle.cellMargin.vertical) * + widget.calendarStyle.markerSizeScale; + + final markerAutoAlignmentTop = center + + (shorterSide - widget.calendarStyle.cellMargin.vertical) / 2 - + (markerSize * widget.calendarStyle.markersAnchor); + + markerWidget = PositionedDirectional( + top: widget.calendarStyle.markersAutoAligned + ? markerAutoAlignmentTop + : widget.calendarStyle.markersOffset.top, + bottom: widget.calendarStyle.markersAutoAligned + ? null + : widget.calendarStyle.markersOffset.bottom, + start: widget.calendarStyle.markersAutoAligned + ? null + : widget.calendarStyle.markersOffset.start, + end: widget.calendarStyle.markersAutoAligned + ? null + : widget.calendarStyle.markersOffset.end, + child: Row( + mainAxisSize: MainAxisSize.min, + children: events + .take(widget.calendarStyle.markersMaxCount) + .map((event) => _buildSingleMarker(day, event, markerSize)) + .toList(), + ), + ); + } + + if (markerWidget != null) { + children.add(markerWidget); + } + } + + return Stack( + alignment: widget.calendarStyle.markersAlignment, + children: children, + clipBehavior: widget.calendarStyle.canMarkersOverflow + ? Clip.none + : Clip.hardEdge, + ); + }, + ); + } + + Widget _buildSingleMarker(DateTime day, T event, double markerSize) { + return widget.calendarBuilders.singleMarkerBuilder + ?.call(context, day, event) ?? + Container( + width: markerSize, + height: markerSize, + margin: widget.calendarStyle.markerMargin, + decoration: widget.calendarStyle.markerDecoration, + ); + } + + bool _isWithinRange(DateTime day, DateTime start, DateTime end) { + if (isSameDay(day, start) || isSameDay(day, end)) { + return true; + } + + if (day.isAfter(start) && day.isBefore(end)) { + return true; + } + + return false; + } + + bool _isDayDisabled(DateTime day) { + return day.isBefore(widget.firstDay) || + day.isAfter(widget.lastDay) || + !_isDayAvailable(day); + } + + bool _isDayAvailable(DateTime day) { + return widget.enabledDayPredicate == null + ? true + : widget.enabledDayPredicate(day); + } + + DateTime _firstDayOfMonth(DateTime month) { + return DateTime.utc(month.year, month.month, 1); + } + + DateTime _lastDayOfMonth(DateTime month) { + final date = month.month < 12 + ? DateTime.utc(month.year, month.month + 1, 1) + : DateTime.utc(month.year + 1, 1, 1); + return date.subtract(const Duration(days: 1)); + } + + bool _isBeforeMonth(DateTime day, DateTime month) { + if (day.year == month.year) { + return day.month < month.month; + } else { + return day.isBefore(month); + } + } + + bool _isAfterMonth(DateTime day, DateTime month) { + if (day.year == month.year) { + return day.month > month.month; + } else { + return day.isAfter(month); + } + } + + bool _isWeekend( + DateTime day, { + List weekendDays = const [DateTime.saturday, DateTime.sunday], + }) { + return weekendDays.contains(day.weekday); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/table_calendar_base.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/table_calendar_base.dart new file mode 100644 index 00000000..279bb9b4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/table_calendar_base.dart @@ -0,0 +1,337 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; +import 'package:simple_gesture_detector/simple_gesture_detector.dart'; + +import 'shared/utils.dart'; +import 'widgets/calendar_core.dart'; + +class TableCalendarBase extends StatefulWidget { + final DateTime firstDay; + final DateTime lastDay; + final DateTime focusedDay; + final CalendarFormat calendarFormat; + final DayBuilder dowBuilder; + final FocusedDayBuilder dayBuilder; + final double dowHeight; + final double rowHeight; + final bool sixWeekMonthsEnforced; + final bool dowVisible; + final Decoration dowDecoration; + final Decoration rowDecoration; + final Duration formatAnimationDuration; + final Curve formatAnimationCurve; + final bool pageAnimationEnabled; + final Duration pageAnimationDuration; + final Curve pageAnimationCurve; + final StartingDayOfWeek startingDayOfWeek; + final AvailableGestures availableGestures; + final SimpleSwipeConfig simpleSwipeConfig; + final Map availableCalendarFormats; + final SwipeCallback onVerticalSwipe; + final void Function(DateTime focusedDay) onPageChanged; + final void Function(PageController pageController) onCalendarCreated; + + TableCalendarBase({ + Key key, + @required this.firstDay, + @required this.lastDay, + @required this.focusedDay, + this.calendarFormat = CalendarFormat.month, + this.dowBuilder, + @required this.dayBuilder, + this.dowHeight, + @required this.rowHeight, + this.sixWeekMonthsEnforced = false, + this.dowVisible = true, + this.dowDecoration, + this.rowDecoration, + this.formatAnimationDuration = const Duration(milliseconds: 200), + this.formatAnimationCurve = Curves.linear, + this.pageAnimationEnabled = true, + this.pageAnimationDuration = const Duration(milliseconds: 300), + this.pageAnimationCurve = Curves.easeOut, + this.startingDayOfWeek = StartingDayOfWeek.sunday, + this.availableGestures = AvailableGestures.all, + this.simpleSwipeConfig = const SimpleSwipeConfig( + verticalThreshold: 25.0, + swipeDetectionBehavior: SwipeDetectionBehavior.continuousDistinct, + ), + this.availableCalendarFormats = const { + CalendarFormat.month: 'Month', + CalendarFormat.twoWeeks: '2 weeks', + CalendarFormat.week: 'Week', + }, + this.onVerticalSwipe, + this.onPageChanged, + this.onCalendarCreated, + }) : assert(!dowVisible || (dowHeight != null && dowBuilder != null)), + assert(isSameDay(focusedDay, firstDay) || focusedDay.isAfter(firstDay)), + assert(isSameDay(focusedDay, lastDay) || focusedDay.isBefore(lastDay)), + super(key: key); + + @override + _TableCalendarBaseState createState() => _TableCalendarBaseState(); +} + +class _TableCalendarBaseState extends State + with SingleTickerProviderStateMixin { + ValueNotifier _pageHeight; + PageController _pageController; + DateTime _focusedDay; + int _previousIndex; + bool _pageCallbackDisabled; + + @override + void initState() { + super.initState(); + _focusedDay = widget.focusedDay; + + final rowCount = _getRowCount(widget.calendarFormat, _focusedDay); + _pageHeight = ValueNotifier(_getPageHeight(rowCount)); + + final initialPage = _calculateFocusedPage( + widget.calendarFormat, widget.firstDay, _focusedDay); + + _pageController = PageController(initialPage: initialPage); + widget.onCalendarCreated?.call(_pageController); + + _previousIndex = initialPage; + _pageCallbackDisabled = false; + } + + @override + void didUpdateWidget(TableCalendarBase oldWidget) { + super.didUpdateWidget(oldWidget); + + if (_focusedDay != widget.focusedDay || + widget.calendarFormat != oldWidget.calendarFormat || + widget.startingDayOfWeek != oldWidget.startingDayOfWeek) { + final shouldAnimate = _focusedDay != widget.focusedDay; + + _focusedDay = widget.focusedDay; + _updatePage(shouldAnimate: shouldAnimate); + } + + if (widget.rowHeight != oldWidget.rowHeight || + widget.dowHeight != oldWidget.dowHeight || + widget.dowVisible != oldWidget.dowVisible || + widget.sixWeekMonthsEnforced != oldWidget.sixWeekMonthsEnforced) { + final rowCount = _getRowCount(widget.calendarFormat, _focusedDay); + _pageHeight.value = _getPageHeight(rowCount); + } + } + + @override + void dispose() { + _pageController.dispose(); + _pageHeight.dispose(); + super.dispose(); + } + + bool get _canScrollHorizontally => + widget.availableGestures == AvailableGestures.all || + widget.availableGestures == AvailableGestures.horizontalSwipe; + + bool get _canScrollVertically => + widget.availableGestures == AvailableGestures.all || + widget.availableGestures == AvailableGestures.verticalSwipe; + + void _updatePage({bool shouldAnimate = false}) { + final currentIndex = _calculateFocusedPage( + widget.calendarFormat, widget.firstDay, _focusedDay); + + final endIndex = _calculateFocusedPage( + widget.calendarFormat, widget.firstDay, widget.lastDay); + + if (currentIndex != _previousIndex || + currentIndex == 0 || + currentIndex == endIndex) { + _pageCallbackDisabled = true; + } + + if (shouldAnimate && widget.pageAnimationEnabled) { + if ((currentIndex - _previousIndex).abs() > 1) { + final jumpIndex = + currentIndex > _previousIndex ? currentIndex - 1 : currentIndex + 1; + + _pageController.jumpToPage(jumpIndex); + } + + _pageController.animateToPage( + currentIndex, + duration: widget.pageAnimationDuration, + curve: widget.pageAnimationCurve, + ); + } else { + _pageController.jumpToPage(currentIndex); + } + + _previousIndex = currentIndex; + final rowCount = _getRowCount(widget.calendarFormat, _focusedDay); + _pageHeight.value = _getPageHeight(rowCount); + + _pageCallbackDisabled = false; + } + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return SimpleGestureDetector( + onVerticalSwipe: _canScrollVertically ? widget.onVerticalSwipe : null, + swipeConfig: widget.simpleSwipeConfig, + child: ValueListenableBuilder( + valueListenable: _pageHeight, + builder: (context, value, child) { + final height = + constraints.hasBoundedHeight ? constraints.maxHeight : value; + + return AnimatedSize( + vsync: this, + duration: widget.formatAnimationDuration, + curve: widget.formatAnimationCurve, + alignment: Alignment.topCenter, + child: SizedBox( + height: height, + child: child, + ), + ); + }, + child: CalendarCore( + constraints: constraints, + pageController: _pageController, + scrollPhysics: _canScrollHorizontally + ? PageScrollPhysics() + : NeverScrollableScrollPhysics(), + firstDay: widget.firstDay, + lastDay: widget.lastDay, + startingDayOfWeek: widget.startingDayOfWeek, + calendarFormat: widget.calendarFormat, + previousIndex: _previousIndex, + focusedDay: _focusedDay, + sixWeekMonthsEnforced: widget.sixWeekMonthsEnforced, + dowVisible: widget.dowVisible, + dowHeight: widget.dowHeight, + rowHeight: widget.rowHeight, + dowDecoration: widget.dowDecoration, + rowDecoration: widget.rowDecoration, + onPageChanged: (index, focusedMonth) { + if (!_pageCallbackDisabled) { + if (!isSameDay(_focusedDay, focusedMonth)) { + _focusedDay = focusedMonth; + } + + if (widget.calendarFormat == CalendarFormat.month && + !widget.sixWeekMonthsEnforced && + !constraints.hasBoundedHeight) { + final rowCount = _getRowCount( + widget.calendarFormat, + focusedMonth, + ); + _pageHeight.value = _getPageHeight(rowCount); + } + + _previousIndex = index; + widget.onPageChanged?.call(focusedMonth); + } + + _pageCallbackDisabled = false; + }, + dowBuilder: widget.dowBuilder, + dayBuilder: widget.dayBuilder, + ), + ), + ); + }, + ); + } + + double _getPageHeight(int rowCount) { + final dowHeight = widget.dowVisible ? widget.dowHeight : 0.0; + return dowHeight + rowCount * widget.rowHeight; + } + + int _calculateFocusedPage( + CalendarFormat format, DateTime startDay, DateTime focusedDay) { + switch (format) { + case CalendarFormat.month: + return _getMonthCount(startDay, focusedDay); + case CalendarFormat.twoWeeks: + return _getTwoWeekCount(startDay, focusedDay); + case CalendarFormat.week: + return _getWeekCount(startDay, focusedDay); + default: + return _getMonthCount(startDay, focusedDay); + } + } + + int _getMonthCount(DateTime first, DateTime last) { + final yearDif = last.year - first.year; + final monthDif = last.month - first.month; + + return yearDif * 12 + monthDif; + } + + int _getWeekCount(DateTime first, DateTime last) { + return last.difference(_firstDayOfWeek(first)).inDays ~/ 7; + } + + int _getTwoWeekCount(DateTime first, DateTime last) { + return last.difference(_firstDayOfWeek(first)).inDays ~/ 14; + } + + int _getRowCount(CalendarFormat format, DateTime focusedDay) { + if (format == CalendarFormat.twoWeeks) { + return 2; + } else if (format == CalendarFormat.week) { + return 1; + } else if (widget.sixWeekMonthsEnforced) { + return 6; + } + + final first = _firstDayOfMonth(focusedDay); + final daysBefore = _getDaysBefore(first); + final firstToDisplay = first.subtract(Duration(days: daysBefore)); + + final last = _lastDayOfMonth(focusedDay); + final daysAfter = _getDaysAfter(last); + final lastToDisplay = last.add(Duration(days: daysAfter)); + + return (lastToDisplay.difference(firstToDisplay).inDays + 1) ~/ 7; + } + + int _getDaysBefore(DateTime firstDay) { + return (firstDay.weekday + 7 - getWeekdayNumber(widget.startingDayOfWeek)) % + 7; + } + + int _getDaysAfter(DateTime lastDay) { + int invertedStartingWeekday = + 8 - getWeekdayNumber(widget.startingDayOfWeek); + + int daysAfter = 7 - ((lastDay.weekday + invertedStartingWeekday) % 7); + if (daysAfter == 7) { + daysAfter = 0; + } + + return daysAfter; + } + + DateTime _firstDayOfWeek(DateTime week) { + final daysBefore = _getDaysBefore(week); + return week.subtract(Duration(days: daysBefore)); + } + + DateTime _firstDayOfMonth(DateTime month) { + return DateTime.utc(month.year, month.month, 1); + } + + DateTime _lastDayOfMonth(DateTime month) { + final date = month.month < 12 + ? DateTime.utc(month.year, month.month + 1, 1) + : DateTime.utc(month.year + 1, 1, 1); + return date.subtract(const Duration(days: 1)); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_core.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_core.dart new file mode 100644 index 00000000..0112a506 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_core.dart @@ -0,0 +1,302 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; + +import '../shared/utils.dart'; +import 'calendar_page.dart'; + +typedef _OnCalendarPageChanged = void Function( + int pageIndex, DateTime focusedDay); + +class CalendarCore extends StatelessWidget { + final DateTime focusedDay; + final DateTime firstDay; + final DateTime lastDay; + final CalendarFormat calendarFormat; + final DayBuilder dowBuilder; + final FocusedDayBuilder dayBuilder; + final bool sixWeekMonthsEnforced; + final bool dowVisible; + final Decoration dowDecoration; + final Decoration rowDecoration; + final double dowHeight; + final double rowHeight; + final BoxConstraints constraints; + final int previousIndex; + final StartingDayOfWeek startingDayOfWeek; + final PageController pageController; + final ScrollPhysics scrollPhysics; + final _OnCalendarPageChanged onPageChanged; + + const CalendarCore({ + Key key, + this.dowBuilder, + @required this.dayBuilder, + @required this.onPageChanged, + @required this.firstDay, + @required this.lastDay, + @required this.constraints, + this.dowHeight, + this.rowHeight, + this.startingDayOfWeek = StartingDayOfWeek.sunday, + this.calendarFormat = CalendarFormat.month, + this.pageController, + this.focusedDay, + this.previousIndex, + this.sixWeekMonthsEnforced = false, + this.dowVisible = true, + this.dowDecoration, + this.rowDecoration, + this.scrollPhysics, + }) : assert(!dowVisible || (dowHeight != null && dowBuilder != null)), + super(key: key); + + @override + Widget build(BuildContext context) { + return PageView.builder( + controller: pageController, + physics: scrollPhysics, + itemCount: _getPageCount(calendarFormat, firstDay, lastDay), + itemBuilder: (context, index) { + final baseDay = _getBaseDay(calendarFormat, index); + final visibleRange = _getVisibleRange(calendarFormat, baseDay); + final visibleDays = _daysInRange(visibleRange.start, visibleRange.end); + + final actualDowHeight = dowVisible ? dowHeight : 0.0; + final constrainedRowHeight = constraints.hasBoundedHeight + ? (constraints.maxHeight - actualDowHeight) / + _getRowCount(calendarFormat, baseDay) + : null; + + return CalendarPage( + visibleDays: visibleDays, + dowVisible: dowVisible, + dowDecoration: dowDecoration, + rowDecoration: rowDecoration, + dowBuilder: (context, day) { + return SizedBox( + height: dowHeight, + child: dowBuilder?.call(context, day), + ); + }, + dayBuilder: (context, day) { + DateTime baseDay; + final previousFocusedDay = focusedDay; + if (previousFocusedDay == null || previousIndex == null) { + baseDay = _getBaseDay(calendarFormat, index); + } else { + baseDay = + _getFocusedDay(calendarFormat, previousFocusedDay, index); + } + + return SizedBox( + height: constrainedRowHeight ?? rowHeight, + child: dayBuilder(context, day, baseDay), + ); + }, + ); + }, + onPageChanged: (index) { + DateTime baseDay; + final previousFocusedDay = focusedDay; + if (previousFocusedDay == null || previousIndex == null) { + baseDay = _getBaseDay(calendarFormat, index); + } else { + baseDay = _getFocusedDay(calendarFormat, previousFocusedDay, index); + } + + return onPageChanged(index, baseDay); + }, + ); + } + + int _getPageCount(CalendarFormat format, DateTime first, DateTime last) { + switch (format) { + case CalendarFormat.month: + return _getMonthCount(first, last) + 1; + case CalendarFormat.twoWeeks: + return _getTwoWeekCount(first, last) + 1; + case CalendarFormat.week: + return _getWeekCount(first, last) + 1; + default: + return _getMonthCount(first, last) + 1; + } + } + + int _getMonthCount(DateTime first, DateTime last) { + final yearDif = last.year - first.year; + final monthDif = last.month - first.month; + + return yearDif * 12 + monthDif; + } + + int _getWeekCount(DateTime first, DateTime last) { + return last.difference(_firstDayOfWeek(first)).inDays ~/ 7; + } + + int _getTwoWeekCount(DateTime first, DateTime last) { + return last.difference(_firstDayOfWeek(first)).inDays ~/ 14; + } + + DateTime _getFocusedDay( + CalendarFormat format, DateTime prevFocusedDay, int pageIndex) { + if (pageIndex == previousIndex) { + return prevFocusedDay; + } + + final pageDif = pageIndex - previousIndex; + DateTime day; + + switch (format) { + case CalendarFormat.month: + day = DateTime.utc(prevFocusedDay.year, prevFocusedDay.month + pageDif); + break; + case CalendarFormat.twoWeeks: + day = DateTime.utc(prevFocusedDay.year, prevFocusedDay.month, + prevFocusedDay.day + pageDif * 14); + break; + case CalendarFormat.week: + day = DateTime.utc(prevFocusedDay.year, prevFocusedDay.month, + prevFocusedDay.day + pageDif * 7); + break; + } + + if (day.isBefore(firstDay)) { + day = firstDay; + } else if (day.isAfter(lastDay)) { + day = lastDay; + } + + return day; + } + + DateTime _getBaseDay(CalendarFormat format, int pageIndex) { + DateTime day; + + switch (format) { + case CalendarFormat.month: + day = DateTime.utc(firstDay.year, firstDay.month + pageIndex); + break; + case CalendarFormat.twoWeeks: + day = DateTime.utc( + firstDay.year, firstDay.month, firstDay.day + pageIndex * 14); + break; + case CalendarFormat.week: + day = DateTime.utc( + firstDay.year, firstDay.month, firstDay.day + pageIndex * 7); + break; + } + + if (day.isBefore(firstDay)) { + day = firstDay; + } else if (day.isAfter(lastDay)) { + day = lastDay; + } + + return day; + } + + DateTimeRange _getVisibleRange(CalendarFormat format, DateTime focusedDay) { + switch (format) { + case CalendarFormat.month: + return _daysInMonth(focusedDay); + case CalendarFormat.twoWeeks: + return _daysInTwoWeeks(focusedDay); + case CalendarFormat.week: + return _daysInWeek(focusedDay); + default: + return _daysInMonth(focusedDay); + } + } + + DateTimeRange _daysInWeek(DateTime focusedDay) { + final daysBefore = _getDaysBefore(focusedDay); + final firstToDisplay = focusedDay.subtract(Duration(days: daysBefore)); + final lastToDisplay = firstToDisplay.add(const Duration(days: 7)); + return DateTimeRange(start: firstToDisplay, end: lastToDisplay); + } + + DateTimeRange _daysInTwoWeeks(DateTime focusedDay) { + final daysBefore = _getDaysBefore(focusedDay); + final firstToDisplay = focusedDay.subtract(Duration(days: daysBefore)); + final lastToDisplay = firstToDisplay.add(const Duration(days: 14)); + return DateTimeRange(start: firstToDisplay, end: lastToDisplay); + } + + DateTimeRange _daysInMonth(DateTime focusedDay) { + final first = _firstDayOfMonth(focusedDay); + final daysBefore = _getDaysBefore(first); + final firstToDisplay = first.subtract(Duration(days: daysBefore)); + + if (sixWeekMonthsEnforced) { + final end = firstToDisplay.add(const Duration(days: 42)); + return DateTimeRange(start: firstToDisplay, end: end); + } + + final last = _lastDayOfMonth(focusedDay); + final daysAfter = _getDaysAfter(last); + final lastToDisplay = last.add(Duration(days: daysAfter)); + + return DateTimeRange(start: firstToDisplay, end: lastToDisplay); + } + + List _daysInRange(DateTime first, DateTime last) { + final dayCount = last.difference(first).inDays + 1; + return List.generate( + dayCount, + (index) => DateTime.utc(first.year, first.month, first.day + index), + ); + } + + DateTime _firstDayOfWeek(DateTime week) { + final daysBefore = _getDaysBefore(week); + return week.subtract(Duration(days: daysBefore)); + } + + DateTime _firstDayOfMonth(DateTime month) { + return DateTime.utc(month.year, month.month, 1); + } + + DateTime _lastDayOfMonth(DateTime month) { + final date = month.month < 12 + ? DateTime.utc(month.year, month.month + 1, 1) + : DateTime.utc(month.year + 1, 1, 1); + return date.subtract(const Duration(days: 1)); + } + + int _getRowCount(CalendarFormat format, DateTime focusedDay) { + if (format == CalendarFormat.twoWeeks) { + return 2; + } else if (format == CalendarFormat.week) { + return 1; + } else if (sixWeekMonthsEnforced) { + return 6; + } + + final first = _firstDayOfMonth(focusedDay); + final daysBefore = _getDaysBefore(first); + final firstToDisplay = first.subtract(Duration(days: daysBefore)); + + final last = _lastDayOfMonth(focusedDay); + final daysAfter = _getDaysAfter(last); + final lastToDisplay = last.add(Duration(days: daysAfter)); + + return (lastToDisplay.difference(firstToDisplay).inDays + 1) ~/ 7; + } + + int _getDaysBefore(DateTime firstDay) { + return (firstDay.weekday + 7 - getWeekdayNumber(startingDayOfWeek)) % 7; + } + + int _getDaysAfter(DateTime lastDay) { + int invertedStartingWeekday = 8 - getWeekdayNumber(startingDayOfWeek); + + int daysAfter = 7 - ((lastDay.weekday + invertedStartingWeekday) % 7); + if (daysAfter == 7) { + daysAfter = 0; + } + + return daysAfter; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_header.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_header.dart new file mode 100644 index 00000000..8908c42c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_header.dart @@ -0,0 +1,98 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/widgets.dart'; +import 'package:intl/intl.dart'; + +import '../customization/header_style.dart'; +import '../shared/utils.dart' show CalendarFormat, DayBuilder; +import 'custom_icon_button.dart'; +import 'format_button.dart'; + +class CalendarHeader extends StatelessWidget { + final dynamic locale; + final DateTime focusedMonth; + final CalendarFormat calendarFormat; + final HeaderStyle headerStyle; + final VoidCallback onLeftChevronTap; + final VoidCallback onRightChevronTap; + final VoidCallback onHeaderTap; + final VoidCallback onHeaderLongPress; + final ValueChanged onFormatButtonTap; + final Map availableCalendarFormats; + final DayBuilder headerTitleBuilder; + + const CalendarHeader({ + Key key, + this.locale, + @required this.focusedMonth, + @required this.calendarFormat, + @required this.headerStyle, + @required this.onLeftChevronTap, + @required this.onRightChevronTap, + @required this.onHeaderTap, + @required this.onHeaderLongPress, + @required this.onFormatButtonTap, + @required this.availableCalendarFormats, + this.headerTitleBuilder, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final text = headerStyle.titleTextFormatter?.call(focusedMonth, locale) ?? + DateFormat.yMMMM(locale).format(focusedMonth); + + return Container( + decoration: headerStyle.decoration, + margin: headerStyle.headerMargin, + padding: headerStyle.headerPadding, + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + if (headerStyle.leftChevronVisible) + CustomIconButton( + icon: headerStyle.leftChevronIcon, + onTap: onLeftChevronTap, + margin: headerStyle.leftChevronMargin, + padding: headerStyle.leftChevronPadding, + ), + Expanded( + child: headerTitleBuilder?.call(context, focusedMonth) ?? + GestureDetector( + onTap: onHeaderTap, + onLongPress: onHeaderLongPress, + child: Text( + text, + style: headerStyle.titleTextStyle, + textAlign: headerStyle.titleCentered + ? TextAlign.center + : TextAlign.start, + ), + ), + ), + if (headerStyle.formatButtonVisible && + availableCalendarFormats.length > 1) + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: FormatButton( + onTap: onFormatButtonTap, + availableCalendarFormats: availableCalendarFormats, + calendarFormat: calendarFormat, + decoration: headerStyle.formatButtonDecoration, + padding: headerStyle.formatButtonPadding, + textStyle: headerStyle.formatButtonTextStyle, + showsNextFormat: headerStyle.formatButtonShowsNext, + ), + ), + if (headerStyle.rightChevronVisible) + CustomIconButton( + icon: headerStyle.rightChevronIcon, + onTap: onRightChevronTap, + margin: headerStyle.rightChevronMargin, + padding: headerStyle.rightChevronPadding, + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_page.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_page.dart new file mode 100644 index 00000000..fed45cc5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/calendar_page.dart @@ -0,0 +1,58 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/widgets.dart'; + +class CalendarPage extends StatelessWidget { + final Widget Function(BuildContext context, DateTime day) dowBuilder; + final Widget Function(BuildContext context, DateTime day) dayBuilder; + final List visibleDays; + final Decoration dowDecoration; + final Decoration rowDecoration; + final bool dowVisible; + + const CalendarPage({ + Key key, + @required this.visibleDays, + this.dowBuilder, + @required this.dayBuilder, + this.dowDecoration, + this.rowDecoration, + this.dowVisible = true, + }) : assert(!dowVisible || dowBuilder != null), + super(key: key); + + @override + Widget build(BuildContext context) { + return Table( + children: [ + if (dowVisible) _buildDaysOfWeek(context), + ..._buildCalendarDays(context), + ], + ); + } + + TableRow _buildDaysOfWeek(BuildContext context) { + return TableRow( + decoration: dowDecoration, + children: List.generate( + 7, + (index) => dowBuilder(context, visibleDays[index]), + ).toList(), + ); + } + + List _buildCalendarDays(BuildContext context) { + final rowAmount = visibleDays.length ~/ 7; + + return List.generate(rowAmount, (index) => index * 7) + .map((index) => TableRow( + decoration: rowDecoration, + children: List.generate( + 7, + (id) => dayBuilder(context, visibleDays[index + id]), + ), + )) + .toList(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/cell_content.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/cell_content.dart new file mode 100644 index 00000000..4b779466 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/cell_content.dart @@ -0,0 +1,150 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/widgets.dart'; + +import '../customization/calendar_builders.dart'; +import '../customization/calendar_style.dart'; + +class CellContent extends StatelessWidget { + final DateTime day; + final DateTime focusedDay; + final bool isTodayHighlighted; + final bool isToday; + final bool isSelected; + final bool isRangeStart; + final bool isRangeEnd; + final bool isWithinRange; + final bool isOutside; + final bool isDisabled; + final bool isHoliday; + final bool isWeekend; + final CalendarStyle calendarStyle; + final CalendarBuilders calendarBuilders; + + const CellContent({ + Key key, + @required this.day, + @required this.focusedDay, + @required this.calendarStyle, + @required this.calendarBuilders, + @required this.isTodayHighlighted, + @required this.isToday, + @required this.isSelected, + @required this.isRangeStart, + @required this.isRangeEnd, + @required this.isWithinRange, + @required this.isOutside, + @required this.isDisabled, + @required this.isHoliday, + @required this.isWeekend, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + Widget cell = + calendarBuilders.prioritizedBuilder?.call(context, day, focusedDay); + + if (cell != null) { + return cell; + } + + final text = '${day.day}'; + final margin = calendarStyle.cellMargin; + final duration = const Duration(milliseconds: 250); + + if (isDisabled) { + cell = calendarBuilders.disabledBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: calendarStyle.disabledDecoration, + alignment: Alignment.center, + child: Text(text, style: calendarStyle.disabledTextStyle), + ); + } else if (isSelected) { + cell = calendarBuilders.selectedBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: calendarStyle.selectedDecoration, + alignment: Alignment.center, + child: Text(text, style: calendarStyle.selectedTextStyle), + ); + } else if (isRangeStart) { + cell = + calendarBuilders.rangeStartBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: calendarStyle.rangeStartDecoration, + alignment: Alignment.center, + child: Text(text, style: calendarStyle.rangeStartTextStyle), + ); + } else if (isRangeEnd) { + cell = calendarBuilders.rangeEndBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: calendarStyle.rangeEndDecoration, + alignment: Alignment.center, + child: Text(text, style: calendarStyle.rangeEndTextStyle), + ); + } else if (isToday && isTodayHighlighted) { + cell = calendarBuilders.todayBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: calendarStyle.todayDecoration, + alignment: Alignment.center, + child: Text(text, style: calendarStyle.todayTextStyle), + ); + } else if (isHoliday) { + cell = calendarBuilders.holidayBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: calendarStyle.holidayDecoration, + alignment: Alignment.center, + child: Text(text, style: calendarStyle.holidayTextStyle), + ); + } else if (isWithinRange) { + cell = + calendarBuilders.withinRangeBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: calendarStyle.withinRangeDecoration, + alignment: Alignment.center, + child: Text(text, style: calendarStyle.withinRangeTextStyle), + ); + } else if (isOutside) { + cell = calendarBuilders.outsideBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: calendarStyle.outsideDecoration, + alignment: Alignment.center, + child: Text(text, style: calendarStyle.outsideTextStyle), + ); + } else { + cell = calendarBuilders.defaultBuilder?.call(context, day, focusedDay) ?? + AnimatedContainer( + duration: duration, + margin: margin, + decoration: isWeekend + ? calendarStyle.weekendDecoration + : calendarStyle.defaultDecoration, + alignment: Alignment.center, + child: Text( + text, + style: isWeekend + ? calendarStyle.weekendTextStyle + : calendarStyle.defaultTextStyle, + ), + ); + } + + return cell; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/custom_icon_button.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/custom_icon_button.dart new file mode 100644 index 00000000..f01d2893 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/custom_icon_button.dart @@ -0,0 +1,34 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; + +class CustomIconButton extends StatelessWidget { + final Widget icon; + final VoidCallback onTap; + final EdgeInsets margin; + final EdgeInsets padding; + + const CustomIconButton({ + Key key, + @required this.icon, + @required this.onTap, + this.margin = const EdgeInsets.all(0.0), + this.padding = const EdgeInsets.all(8.0), + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: margin, + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(100.0), + child: Padding( + padding: padding, + child: icon, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/format_button.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/format_button.dart new file mode 100644 index 00000000..6f1664e2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/src/widgets/format_button.dart @@ -0,0 +1,54 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; + +import '../shared/utils.dart' show CalendarFormat; + +class FormatButton extends StatelessWidget { + final CalendarFormat calendarFormat; + final ValueChanged onTap; + final TextStyle textStyle; + final Decoration decoration; + final EdgeInsets padding; + final bool showsNextFormat; + final Map availableCalendarFormats; + + const FormatButton({ + Key key, + @required this.calendarFormat, + @required this.onTap, + @required this.textStyle, + @required this.decoration, + @required this.padding, + @required this.showsNextFormat, + @required this.availableCalendarFormats, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => onTap(_nextFormat()), + child: Container( + decoration: decoration, + padding: padding, + child: Text( + _formatButtonText, + style: textStyle, + ), + ), + ); + } + + String get _formatButtonText => showsNextFormat + ? availableCalendarFormats[_nextFormat()] + : availableCalendarFormats[calendarFormat]; + + CalendarFormat _nextFormat() { + final formats = availableCalendarFormats.keys.toList(); + int id = formats.indexOf(calendarFormat); + id = (id + 1) % formats.length; + + return formats[id]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/table_calendar.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/table_calendar.dart new file mode 100644 index 00000000..4115dc30 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/lib/table_calendar.dart @@ -0,0 +1,10 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +export 'src/customization/calendar_builders.dart'; +export 'src/customization/calendar_style.dart'; +export 'src/customization/days_of_week_style.dart'; +export 'src/customization/header_style.dart'; +export 'src/shared/utils.dart'; +export 'src/table_calendar.dart'; +export 'src/table_calendar_base.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/main.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/main.dart new file mode 100644 index 00000000..c6532841 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/main.dart @@ -0,0 +1,92 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; +import 'package:intl/date_symbol_data_local.dart'; + +import 'pages/basics_example.dart'; +import 'pages/complex_example.dart'; +import 'pages/events_example.dart'; +import 'pages/multi_example.dart'; +import 'pages/range_example.dart'; + +void main() { + initializeDateFormatting().then((_) => runApp(TableCanlendarApp())); +} + +class TableCanlendarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'TableCalendar Example', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: StartPage(), + ); + } +} + +class StartPage extends StatefulWidget { + @override + _StartPageState createState() => _StartPageState(); +} + +class _StartPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('TableCalendar Example'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 20.0), + ElevatedButton( + child: Text('Basics'), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (_) => TableBasicsExample()), + ), + ), + const SizedBox(height: 12.0), + ElevatedButton( + child: Text('Range Selection'), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (_) => TableRangeExample()), + ), + ), + const SizedBox(height: 12.0), + ElevatedButton( + child: Text('Events'), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (_) => TableEventsExample()), + ), + ), + const SizedBox(height: 12.0), + ElevatedButton( + child: Text('Multiple Selection'), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (_) => TableMultiExample()), + ), + ), + const SizedBox(height: 12.0), + ElevatedButton( + child: Text('Complex'), + onPressed: () => Navigator.push( + context, + MaterialPageRoute(builder: (_) => TableComplexExample()), + ), + ), + const SizedBox(height: 20.0), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/basics_example.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/basics_example.dart new file mode 100644 index 00000000..ecc98347 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/basics_example.dart @@ -0,0 +1,62 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/table_calendar/lib/table_calendar.dart'; + +import '../utils.dart'; + +class TableBasicsExample extends StatefulWidget { + @override + _TableBasicsExampleState createState() => _TableBasicsExampleState(); +} + +class _TableBasicsExampleState extends State { + CalendarFormat _calendarFormat = CalendarFormat.month; + DateTime _focusedDay = DateTime.now(); + DateTime _selectedDay; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('TableCalendar - Basics'), + ), + body: TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: _focusedDay, + calendarFormat: _calendarFormat, + selectedDayPredicate: (day) { + // Use `selectedDayPredicate` to determine which day is currently selected. + // If this returns true, then `day` will be marked as selected. + + // Using `isSameDay` is recommended to disregard + // the time-part of compared DateTime objects. + return isSameDay(_selectedDay, day); + }, + onDaySelected: (selectedDay, focusedDay) { + if (!isSameDay(_selectedDay, selectedDay)) { + // Call `setState()` when updating the selected day + setState(() { + _selectedDay = selectedDay; + _focusedDay = focusedDay; + }); + } + }, + onFormatChanged: (format) { + if (_calendarFormat != format) { + // Call `setState()` when updating calendar format + setState(() { + _calendarFormat = format; + }); + } + }, + onPageChanged: (focusedDay) { + // No need to call `setState()` here + _focusedDay = focusedDay; + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/complex_example.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/complex_example.dart new file mode 100644 index 00000000..f90c8902 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/complex_example.dart @@ -0,0 +1,254 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:collection'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/table_calendar/lib/table_calendar.dart'; +import 'package:intl/intl.dart'; + +import '../utils.dart'; + +class TableComplexExample extends StatefulWidget { + @override + _TableComplexExampleState createState() => _TableComplexExampleState(); +} + +class _TableComplexExampleState extends State { + PageController _pageController; + ValueNotifier> _selectedEvents; + final ValueNotifier _focusedDay = ValueNotifier(DateTime.now()); + final Set _selectedDays = LinkedHashSet( + equals: isSameDay, + hashCode: getHashCode, + ); + CalendarFormat _calendarFormat = CalendarFormat.month; + RangeSelectionMode _rangeSelectionMode = RangeSelectionMode.toggledOff; + DateTime _rangeStart; + DateTime _rangeEnd; + + @override + void initState() { + super.initState(); + + _selectedDays.add(_focusedDay.value); + _selectedEvents = ValueNotifier(_getEventsForDay(_focusedDay.value)); + } + + @override + void dispose() { + _focusedDay.dispose(); + _selectedEvents.dispose(); + super.dispose(); + } + + bool get canClearSelection => + _selectedDays.isNotEmpty || _rangeStart != null || _rangeEnd != null; + + List _getEventsForDay(DateTime day) { + return kEvents[day] ?? []; + } + + List _getEventsForDays(Iterable days) { + return [ + for (final d in days) ..._getEventsForDay(d), + ]; + } + + List _getEventsForRange(DateTime start, DateTime end) { + final days = daysInRange(start, end); + return _getEventsForDays(days); + } + + void _onDaySelected(DateTime selectedDay, DateTime focusedDay) { + setState(() { + if (_selectedDays.contains(selectedDay)) { + _selectedDays.remove(selectedDay); + } else { + _selectedDays.add(selectedDay); + } + + _focusedDay.value = focusedDay; + _rangeStart = null; + _rangeEnd = null; + _rangeSelectionMode = RangeSelectionMode.toggledOff; + }); + + _selectedEvents.value = _getEventsForDays(_selectedDays); + } + + void _onRangeSelected(DateTime start, DateTime end, DateTime focusedDay) { + setState(() { + _focusedDay.value = focusedDay; + _rangeStart = start; + _rangeEnd = end; + _selectedDays.clear(); + _rangeSelectionMode = RangeSelectionMode.toggledOn; + }); + + if (start != null && end != null) { + _selectedEvents.value = _getEventsForRange(start, end); + } else if (start != null) { + _selectedEvents.value = _getEventsForDay(start); + } else if (end != null) { + _selectedEvents.value = _getEventsForDay(end); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('TableCalendar - Complex'), + ), + body: Column( + children: [ + ValueListenableBuilder( + valueListenable: _focusedDay, + builder: (context, value, _) { + return _CalendarHeader( + focusedDay: value, + clearButtonVisible: canClearSelection, + onTodayButtonTap: () { + setState(() => _focusedDay.value = DateTime.now()); + }, + onClearButtonTap: () { + setState(() { + _rangeStart = null; + _rangeEnd = null; + _selectedDays.clear(); + _selectedEvents.value = []; + }); + }, + onLeftArrowTap: () { + _pageController.previousPage( + duration: Duration(milliseconds: 300), + curve: Curves.easeOut, + ); + }, + onRightArrowTap: () { + _pageController.nextPage( + duration: Duration(milliseconds: 300), + curve: Curves.easeOut, + ); + }, + ); + }, + ), + TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: _focusedDay.value, + headerVisible: false, + selectedDayPredicate: (day) => _selectedDays.contains(day), + rangeStartDay: _rangeStart, + rangeEndDay: _rangeEnd, + calendarFormat: _calendarFormat, + rangeSelectionMode: _rangeSelectionMode, + eventLoader: _getEventsForDay, + holidayPredicate: (day) { + // Every 20th day of the month will be treated as a holiday + return day.day == 20; + }, + onDaySelected: _onDaySelected, + onRangeSelected: _onRangeSelected, + onCalendarCreated: (controller) => _pageController = controller, + onPageChanged: (focusedDay) => _focusedDay.value = focusedDay, + onFormatChanged: (format) { + if (_calendarFormat != format) { + setState(() => _calendarFormat = format); + } + }, + ), + const SizedBox(height: 8.0), + Expanded( + child: ValueListenableBuilder>( + valueListenable: _selectedEvents, + builder: (context, value, _) { + return ListView.builder( + itemCount: value.length, + itemBuilder: (context, index) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 4.0, + ), + decoration: BoxDecoration( + border: Border.all(), + borderRadius: BorderRadius.circular(12.0), + ), + child: ListTile( + onTap: () => print('${value[index]}'), + title: Text('${value[index]}'), + ), + ); + }, + ); + }, + ), + ), + ], + ), + ); + } +} + +class _CalendarHeader extends StatelessWidget { + final DateTime focusedDay; + final VoidCallback onLeftArrowTap; + final VoidCallback onRightArrowTap; + final VoidCallback onTodayButtonTap; + final VoidCallback onClearButtonTap; + final bool clearButtonVisible; + + const _CalendarHeader({ + Key key, + @required this.focusedDay, + @required this.onLeftArrowTap, + @required this.onRightArrowTap, + @required this.onTodayButtonTap, + @required this.onClearButtonTap, + @required this.clearButtonVisible, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final headerText = DateFormat.yMMM().format(focusedDay); + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + children: [ + const SizedBox(width: 16.0), + SizedBox( + width: 120.0, + child: Text( + headerText, + style: TextStyle(fontSize: 26.0), + ), + ), + IconButton( + icon: Icon(Icons.calendar_today, size: 20.0), + visualDensity: VisualDensity.compact, + onPressed: onTodayButtonTap, + ), + if (clearButtonVisible) + IconButton( + icon: Icon(Icons.clear, size: 20.0), + visualDensity: VisualDensity.compact, + onPressed: onClearButtonTap, + ), + const Spacer(), + IconButton( + icon: Icon(Icons.chevron_left), + onPressed: onLeftArrowTap, + ), + IconButton( + icon: Icon(Icons.chevron_right), + onPressed: onRightArrowTap, + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/events_example.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/events_example.dart new file mode 100644 index 00000000..f74ea068 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/events_example.dart @@ -0,0 +1,152 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/table_calendar/lib/table_calendar.dart'; + +import '../utils.dart'; + +class TableEventsExample extends StatefulWidget { + @override + _TableEventsExampleState createState() => _TableEventsExampleState(); +} + +class _TableEventsExampleState extends State { + ValueNotifier> _selectedEvents; + CalendarFormat _calendarFormat = CalendarFormat.month; + RangeSelectionMode _rangeSelectionMode = RangeSelectionMode + .toggledOff; // Can be toggled on/off by longpressing a date + DateTime _focusedDay = DateTime.now(); + DateTime _selectedDay; + DateTime _rangeStart; + DateTime _rangeEnd; + + @override + void initState() { + super.initState(); + + _selectedDay = _focusedDay; + _selectedEvents = ValueNotifier(_getEventsForDay(_selectedDay)); + } + + @override + void dispose() { + _selectedEvents.dispose(); + super.dispose(); + } + + List _getEventsForDay(DateTime day) { + // Implementation example + return kEvents[day] ?? []; + } + + List _getEventsForRange(DateTime start, DateTime end) { + // Implementation example + final days = daysInRange(start, end); + + return [ + for (final d in days) ..._getEventsForDay(d), + ]; + } + + void _onDaySelected(DateTime selectedDay, DateTime focusedDay) { + if (!isSameDay(_selectedDay, selectedDay)) { + setState(() { + _selectedDay = selectedDay; + _focusedDay = focusedDay; + _rangeStart = null; // Important to clean those + _rangeEnd = null; + _rangeSelectionMode = RangeSelectionMode.toggledOff; + }); + + _selectedEvents.value = _getEventsForDay(selectedDay); + } + } + + void _onRangeSelected(DateTime start, DateTime end, DateTime focusedDay) { + setState(() { + _selectedDay = null; + _focusedDay = focusedDay; + _rangeStart = start; + _rangeEnd = end; + _rangeSelectionMode = RangeSelectionMode.toggledOn; + }); + + // `start` or `end` could be null + if (start != null && end != null) { + _selectedEvents.value = _getEventsForRange(start, end); + } else if (start != null) { + _selectedEvents.value = _getEventsForDay(start); + } else if (end != null) { + _selectedEvents.value = _getEventsForDay(end); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('TableCalendar - Events'), + ), + body: Column( + children: [ + TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: _focusedDay, + selectedDayPredicate: (day) => isSameDay(_selectedDay, day), + rangeStartDay: _rangeStart, + rangeEndDay: _rangeEnd, + calendarFormat: _calendarFormat, + rangeSelectionMode: _rangeSelectionMode, + eventLoader: _getEventsForDay, + startingDayOfWeek: StartingDayOfWeek.monday, + calendarStyle: CalendarStyle( + // Use `CalendarStyle` to customize the UI + outsideDaysVisible: false, + ), + onDaySelected: _onDaySelected, + onRangeSelected: _onRangeSelected, + onFormatChanged: (format) { + if (_calendarFormat != format) { + setState(() { + _calendarFormat = format; + }); + } + }, + onPageChanged: (focusedDay) { + _focusedDay = focusedDay; + }, + ), + const SizedBox(height: 8.0), + Expanded( + child: ValueListenableBuilder>( + valueListenable: _selectedEvents, + builder: (context, value, _) { + return ListView.builder( + itemCount: value.length, + itemBuilder: (context, index) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 4.0, + ), + decoration: BoxDecoration( + border: Border.all(), + borderRadius: BorderRadius.circular(12.0), + ), + child: ListTile( + onTap: () => print('${value[index]}'), + title: Text('${value[index]}'), + ), + ); + }, + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/multi_example.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/multi_example.dart new file mode 100644 index 00000000..449278da --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/multi_example.dart @@ -0,0 +1,132 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:collection'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/table_calendar/lib/table_calendar.dart'; + +import '../utils.dart'; + +class TableMultiExample extends StatefulWidget { + @override + _TableMultiExampleState createState() => _TableMultiExampleState(); +} + +class _TableMultiExampleState extends State { + final ValueNotifier> _selectedEvents = ValueNotifier([]); + + // Using a `LinkedHashSet` is recommended due to equality comparison override + final Set _selectedDays = LinkedHashSet( + equals: isSameDay, + hashCode: getHashCode, + ); + + CalendarFormat _calendarFormat = CalendarFormat.month; + DateTime _focusedDay = DateTime.now(); + + @override + void dispose() { + _selectedEvents.dispose(); + super.dispose(); + } + + List _getEventsForDay(DateTime day) { + // Implementation example + return kEvents[day] ?? []; + } + + List _getEventsForDays(Set days) { + // Implementation example + // Note that days are in selection order (same applies to events) + return [ + for (final d in days) ..._getEventsForDay(d), + ]; + } + + void _onDaySelected(DateTime selectedDay, DateTime focusedDay) { + setState(() { + _focusedDay = focusedDay; + // Update values in a Set + if (_selectedDays.contains(selectedDay)) { + _selectedDays.remove(selectedDay); + } else { + _selectedDays.add(selectedDay); + } + }); + + _selectedEvents.value = _getEventsForDays(_selectedDays); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('TableCalendar - Multi'), + ), + body: Column( + children: [ + TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: _focusedDay, + calendarFormat: _calendarFormat, + eventLoader: _getEventsForDay, + startingDayOfWeek: StartingDayOfWeek.monday, + selectedDayPredicate: (day) { + // Use values from Set to mark multiple days as selected + return _selectedDays.contains(day); + }, + onDaySelected: _onDaySelected, + onFormatChanged: (format) { + if (_calendarFormat != format) { + setState(() { + _calendarFormat = format; + }); + } + }, + onPageChanged: (focusedDay) { + _focusedDay = focusedDay; + }, + ), + ElevatedButton( + child: Text('Clear selection'), + onPressed: () { + setState(() { + _selectedDays.clear(); + _selectedEvents.value = []; + }); + }, + ), + const SizedBox(height: 8.0), + Expanded( + child: ValueListenableBuilder>( + valueListenable: _selectedEvents, + builder: (context, value, _) { + return ListView.builder( + itemCount: value.length, + itemBuilder: (context, index) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 4.0, + ), + decoration: BoxDecoration( + border: Border.all(), + borderRadius: BorderRadius.circular(12.0), + ), + child: ListTile( + onTap: () => print('${value[index]}'), + title: Text('${value[index]}'), + ), + ); + }, + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/range_example.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/range_example.dart new file mode 100644 index 00000000..95c0e51d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/pages/range_example.dart @@ -0,0 +1,71 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/table_calendar/lib/table_calendar.dart'; + +import '../utils.dart'; + +class TableRangeExample extends StatefulWidget { + @override + _TableRangeExampleState createState() => _TableRangeExampleState(); +} + +class _TableRangeExampleState extends State { + CalendarFormat _calendarFormat = CalendarFormat.month; + RangeSelectionMode _rangeSelectionMode = RangeSelectionMode + .toggledOn; // Can be toggled on/off by longpressing a date + DateTime _focusedDay = DateTime.now(); + DateTime _selectedDay; + DateTime _rangeStart; + DateTime _rangeEnd; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('TableCalendar - Range'), + ), + body: TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: _focusedDay, + selectedDayPredicate: (day) => isSameDay(_selectedDay, day), + rangeStartDay: _rangeStart, + rangeEndDay: _rangeEnd, + calendarFormat: _calendarFormat, + rangeSelectionMode: _rangeSelectionMode, + onDaySelected: (selectedDay, focusedDay) { + if (!isSameDay(_selectedDay, selectedDay)) { + setState(() { + _selectedDay = selectedDay; + _focusedDay = focusedDay; + _rangeStart = null; // Important to clean those + _rangeEnd = null; + _rangeSelectionMode = RangeSelectionMode.toggledOff; + }); + } + }, + onRangeSelected: (start, end, focusedDay) { + setState(() { + _selectedDay = null; + _focusedDay = focusedDay; + _rangeStart = start; + _rangeEnd = end; + _rangeSelectionMode = RangeSelectionMode.toggledOn; + }); + }, + onFormatChanged: (format) { + if (_calendarFormat != format) { + setState(() { + _calendarFormat = format; + }); + } + }, + onPageChanged: (focusedDay) { + _focusedDay = focusedDay; + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_calendar/utils.dart b/FlutterHelper/flutter_helper/lib/samples/table_calendar/utils.dart new file mode 100644 index 00000000..a80150c9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_calendar/utils.dart @@ -0,0 +1,53 @@ +// Copyright 2019 Aleksander Woźniak +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:collection'; + +import 'lib/table_calendar.dart'; + + +/// Example event class. +class Event { + final String title; + + const Event(this.title); + + @override + String toString() => title; +} + +/// Example events. +/// +/// Using a [LinkedHashMap] is highly recommended if you decide to use a map. +final kEvents = LinkedHashMap>( + equals: isSameDay, + hashCode: getHashCode, +)..addAll(_kEventSource); + +final _kEventSource = Map.fromIterable(List.generate(50, (index) => index), + key: (item) => DateTime.utc(kFirstDay.year, kFirstDay.month, item * 5), + value: (item) => List.generate( + item % 4 + 1, (index) => Event('Event $item | ${index + 1}'))) + ..addAll({ + kToday: [ + Event('Today\'s Event 1'), + Event('Today\'s Event 2'), + ], + }); + +int getHashCode(DateTime key) { + return key.day * 1000000 + key.month * 10000 + key.year; +} + +/// Returns a list of [DateTime] objects from [first] to [last], inclusive. +List daysInRange(DateTime first, DateTime last) { + final dayCount = last.difference(first).inDays + 1; + return List.generate( + dayCount, + (index) => DateTime.utc(first.year, first.month, first.day + index), + ); +} + +final kToday = DateTime.now(); +final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); +final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlanner.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlanner.dart new file mode 100644 index 00000000..2b09e517 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlanner.dart @@ -0,0 +1,341 @@ +import 'package:flutter/material.dart'; +import 'TimePlannerStyle.dart'; + +import 'TimePlannerTask.dart'; +import 'TimePlannerTime.dart'; +import 'TimePlannerTitle.dart'; +import 'config/GlobalConfig.dart' as Config; + +/// Time planner widget +class TimePlanner extends StatefulWidget { + /// Time start from this, it will start from 1 + final int startHour; + + /// Time end at this hour, max value is 24 + final int endHour; + + /// Create days from here, each day is a TimePlannerTitle. + /// + /// you should create at least one day + final List headers; + + /// List of widgets on time planner + final List tasks; + + /// Style of time planner + final TimePlannerStyle style; + + /// When widget loaded scroll to current time with an animation. Default is true + final bool currentTimeAnimation; + + /// Time planner widget + const TimePlanner({ + Key key, + @required this.startHour, + @required this.endHour, + @required this.headers, + this.tasks, + this.style, + this.currentTimeAnimation, + }) : super(key: key); + @override + _TimePlannerState createState() => _TimePlannerState(); +} + +class _TimePlannerState extends State { + ScrollController mainHorizontalController = ScrollController(); + ScrollController mainVerticalController = ScrollController(); + ScrollController dayHorizontalController = ScrollController(); + ScrollController timeVerticalController = ScrollController(); + TimePlannerStyle style = TimePlannerStyle(); + List tasks = []; + bool isAnimated = true; + + /// check input value for rules + void _checkInputValue() { + if (widget.startHour > widget.endHour) { + throw FlutterError("Start hour sholud be lower than end hour"); + } else if (widget.startHour < 1) { + throw FlutterError("Start hour sholud be larger than 1"); + } else if (widget.endHour > 24) { + throw FlutterError("Start hour sholud be lower than 24"); + } else if (widget.headers.isEmpty) { + throw FlutterError("header can\'t be empty"); + } + } + + /// create local style + void _convertToLocalStyle() { + style.backgroundColor = widget.style?.backgroundColor ?? null; + style.cellHeight = widget.style?.cellHeight ?? 80; + style.cellWidth = widget.style?.cellWidth ?? 90; + style.dividerColor = widget.style?.dividerColor ?? null; + style.showScrollBar = widget.style?.showScrollBar ?? false; + } + + /// store input data to static values + void _initData() { + _checkInputValue(); + _convertToLocalStyle(); + Config.cellHeight = style.cellHeight; + Config.cellWidth = style.cellWidth; + Config.totalHours = (widget.endHour - widget.startHour).toDouble(); + Config.totalDays = widget.headers.length; + Config.startHour = widget.startHour; + isAnimated = widget.currentTimeAnimation; + tasks = widget.tasks ?? []; + } + + @override + void initState() { + _initData(); + super.initState(); + Future.delayed(Duration.zero).then((_) { + int hour = DateTime.now().hour; + if (hour > widget.startHour) { + double scrollOffset = + (hour - widget.startHour) * Config.cellHeight.toDouble(); + mainVerticalController.animateTo(scrollOffset, + duration: Duration(milliseconds: 800), curve: Curves.easeOutCirc); + timeVerticalController.animateTo(scrollOffset, + duration: Duration(milliseconds: 800), curve: Curves.easeOutCirc); + } + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + mainHorizontalController.addListener(() { + dayHorizontalController.jumpTo(mainHorizontalController.offset); + }); + mainVerticalController.addListener(() { + timeVerticalController.jumpTo(mainVerticalController.offset); + }); + return GestureDetector( + child: Container( + color: style.backgroundColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + SingleChildScrollView( + controller: dayHorizontalController, + scrollDirection: Axis.horizontal, + physics: NeverScrollableScrollPhysics(), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 60, + ), + for (int i = 0; i < Config.totalDays; i++) widget.headers[i], + ], + ), + ), + Container( + height: 1, + color: style.dividerColor ?? Theme.of(context).primaryColor, + ), + Expanded( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SingleChildScrollView( + physics: NeverScrollableScrollPhysics(), + controller: timeVerticalController, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + //first number is start hour and secound number is end hour + for (int i = widget.startHour; + i <= widget.endHour; + i++) + TimePlannerTime( + time: i.toString() + ':00', + ), + ], + ), + Container( + height: (Config.totalHours * Config.cellHeight) + 80, + width: 1, + color: style.dividerColor ?? + Theme.of(context).primaryColor, + ), + ], + ), + ), + Expanded( + child: buildMainBody(), + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget buildMainBody() { + if (style.showScrollBar) { + return Scrollbar( + controller: mainVerticalController, + child: SingleChildScrollView( + controller: mainVerticalController, + child: Scrollbar( + controller: mainHorizontalController, + child: SingleChildScrollView( + controller: mainHorizontalController, + scrollDirection: Axis.horizontal, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: (Config.totalHours * Config.cellHeight) + 80, + width: + (Config.totalDays * Config.cellWidth).toDouble(), + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (var i = 0; i < Config.totalHours; i++) + Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: + (Config.cellHeight - 1).toDouble(), + ), + Divider( + height: 1, + ), + ], + ) + ], + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + for (var i = 0; i < Config.totalDays; i++) + Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: + (Config.cellWidth - 1).toDouble(), + ), + Container( + width: 1, + height: (Config.totalHours * + Config.cellHeight) + + Config.cellHeight, + color: Colors.black12, + ) + ], + ) + ], + ), + for (int i = 0; i < tasks.length; i++) tasks[i], + ], + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } + return SingleChildScrollView( + controller: mainVerticalController, + child: SingleChildScrollView( + controller: mainHorizontalController, + scrollDirection: Axis.horizontal, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: (Config.totalHours * Config.cellHeight) + 80, + width: (Config.totalDays * Config.cellWidth).toDouble(), + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (var i = 0; i < Config.totalHours; i++) + Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: (Config.cellHeight - 1).toDouble(), + ), + Divider( + height: 1, + ), + ], + ) + ], + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + for (var i = 0; i < Config.totalDays; i++) + Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: (Config.cellWidth - 1).toDouble(), + ), + Container( + width: 1, + height: + (Config.totalHours * Config.cellHeight) + + Config.cellHeight, + color: Colors.black12, + ) + ], + ) + ], + ), + for (int i = 0; i < tasks.length; i++) tasks[i], + ], + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerDateTime.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerDateTime.dart new file mode 100644 index 00000000..900c389c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerDateTime.dart @@ -0,0 +1,15 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +class TimePlannerDateTime { + /// Day index from 0, this index dependence on your time planner header + int day; + + /// Task will be begin at this hour + int hour; + + /// Task will be begin at this minutes + int minutes; + + TimePlannerDateTime( + {@required this.day, @required this.hour, @required this.minutes}); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerStyle.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerStyle.dart new file mode 100644 index 00000000..e8332125 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerStyle.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +class TimePlannerStyle { + /// Height of each cell in time planner, default is 90. + int cellHeight; + + /// Width of each cell in time planner, default is 80. + int cellWidth; + + /// Colors of main divider (under the title and next to hours) + Color dividerColor; + + /// Background colors of time planner + Color backgroundColor; + + /// Show horizontal and vertical [scrollBar] on time planner, default is false. + bool showScrollBar; + + TimePlannerStyle( + {this.cellHeight, + this.cellWidth, + this.dividerColor, + this.backgroundColor, + this.showScrollBar}); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTask.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTask.dart new file mode 100644 index 00000000..5a61d1f3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTask.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; + +import 'TimePlannerDateTime.dart'; +import 'config/GlobalConfig.dart' as Config; + +/// Widget that show on time planner as the tasks +class TimePlannerTask extends StatelessWidget { + /// Minutes duration of task or object + final int minutesDuration; + + /// Days duration of task or object, default is 1 + final int daysDuration; + + /// When this task will be happen + final TimePlannerDateTime dateTime; + + /// Background color of task + final Color color; + + /// This will be happen when user tap on task, for example show a dialog or navigate to other page + final Function onTap; + + /// Show this child on the task + /// + /// Typically an [Text]. + final Widget child; + + /// Widget that show on time planner as the tasks + const TimePlannerTask({ + Key key, + @required this.minutesDuration, + @required this.dateTime, + this.daysDuration, + this.color, + this.onTap, + this.child, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Positioned( + top: ((Config.cellHeight * (dateTime.hour - Config.startHour)) + + ((dateTime.minutes * Config.cellHeight) / 60)) + .toDouble(), + left: Config.cellWidth * dateTime.day.toDouble(), + child: Material( + elevation: 3, + borderRadius: BorderRadius.all(Radius.circular(8.0)), + child: Stack( + children: [ + InkWell( + onTap: onTap as void Function() ?? () {}, + child: Container( + height: ((minutesDuration.toDouble() * Config.cellHeight) / + 60), //60 minutes + width: (Config.cellWidth.toDouble() * + (daysDuration >= 1 ? daysDuration : 1)), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + color: color ?? Theme.of(context).primaryColor), + child: Center( + child: child, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTime.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTime.dart new file mode 100644 index 00000000..faefa588 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTime.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'config/GlobalConfig.dart' as Config; + +/// Show the hour for each row of time planner +class TimePlannerTime extends StatelessWidget { + /// Text it will be show as hour + final String time; + + /// Show the hour for each row of time planner + const TimePlannerTime({ + Key key, + this.time, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: Config.cellHeight.toDouble() - 1, + width: 60, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 0.0, vertical: 0.0), + child: Center(child: Text(time)), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTitle.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTitle.dart new file mode 100644 index 00000000..3ae93128 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/TimePlannerTitle.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'config/GlobalConfig.dart' as Config; + +/// Title widget for time planner +class TimePlannerTitle extends StatelessWidget { + /// Title of each day, typically is name of the day for example sunday + /// + /// but you can set any things here + final String title; + + /// Text style for title + final TextStyle titleStyle; + + /// Date of each day like 03/21/2021 but you can leave it empty or write other things + final String date; + + /// Text style for date text + final TextStyle dateStyle; + + /// Title widget for time planner + const TimePlannerTitle({ + Key key, + @required this.title, + this.date, + this.titleStyle, + this.dateStyle, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: 50, + width: Config.cellWidth.toDouble(), + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + title, + style: titleStyle ?? TextStyle(fontWeight: FontWeight.w600), + ), + SizedBox( + height: 3, + ), + Text( + date ?? '', + style: dateStyle ?? TextStyle(color: Colors.grey, fontSize: 12), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/config/GlobalConfig.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/config/GlobalConfig.dart new file mode 100644 index 00000000..de711653 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/src/config/GlobalConfig.dart @@ -0,0 +1,9 @@ +///static values for time planner + +library timeplanner.config; + +int cellHeight; +int cellWidth; +double totalHours; +int totalDays; +int startHour; diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/time_planner.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/time_planner.dart new file mode 100644 index 00000000..3b3613cf --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/lib/time_planner.dart @@ -0,0 +1,7 @@ +library time_planner; + +export 'src/TimePlanner.dart'; +export 'src/TimePlannerTitle.dart'; +export 'src/TimePlannerTask.dart'; +export 'src/TimePlannerDateTime.dart'; +export 'src/TimePlannerStyle.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/table_planner/main.dart b/FlutterHelper/flutter_helper/lib/samples/table_planner/main.dart new file mode 100644 index 00000000..bf8f4997 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/table_planner/main.dart @@ -0,0 +1,182 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'lib/time_planner.dart'; + +void main() { + runApp(TablePlanneryApp()); +} + +class TablePlanneryApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Time planner Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: MyHomePage(title: 'Time planner'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, @required this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + List tasks = []; + + void _addObject(BuildContext context) { + List colors = [ + Colors.purple, + Colors.blue, + Colors.green, + Colors.orange, + Colors.lime[600] + ]; + + setState(() { + tasks.add( + TimePlannerTask( + color: colors[Random().nextInt(colors.length)], + dateTime: TimePlannerDateTime( + day: Random().nextInt(14), + hour: Random().nextInt(18) + 6, + minutes: Random().nextInt(60)), + minutesDuration: Random().nextInt(90) + 30, + daysDuration: Random().nextInt(4) + 1, + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('You click on time planner object'))); + }, + child: Text( + 'this is a test', + style: TextStyle(color: Colors.grey[350], fontSize: 12), + ), + ), + ); + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Random task added to time planner!'))); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + centerTitle: true, + ), + body: Center( + child: TimePlanner( + startHour: 6, + endHour: 24, + headers: [ + TimePlannerTitle( + date: "3/10/2021", + title: "sunday", + ), + TimePlannerTitle( + date: "3/11/2021", + title: "monday", + ), + TimePlannerTitle( + date: "3/12/2021", + title: "tuesday", + ), + TimePlannerTitle( + date: "3/13/2021", + title: "wednesday", + ), + TimePlannerTitle( + date: "3/14/2021", + title: "thursday", + ), + TimePlannerTitle( + date: "3/15/2021", + title: "friday", + ), + TimePlannerTitle( + date: "3/16/2021", + title: "saturday", + ), + TimePlannerTitle( + date: "3/17/2021", + title: "sunday", + ), + TimePlannerTitle( + date: "3/18/2021", + title: "monday", + ), + TimePlannerTitle( + date: "3/19/2021", + title: "tuesday", + ), + TimePlannerTitle( + date: "3/20/2021", + title: "wednesday", + ), + TimePlannerTitle( + date: "3/21/2021", + title: "thursday", + ), + TimePlannerTitle( + date: "3/22/2021", + title: "friday", + ), + TimePlannerTitle( + date: "3/23/2021", + title: "saturday", + ), + TimePlannerTitle( + date: "3/24/2021", + title: "tuesday", + ), + TimePlannerTitle( + date: "3/25/2021", + title: "wednesday", + ), + TimePlannerTitle( + date: "3/26/2021", + title: "thursday", + ), + TimePlannerTitle( + date: "3/27/2021", + title: "friday", + ), + TimePlannerTitle( + date: "3/28/2021", + title: "saturday", + ), + TimePlannerTitle( + date: "3/29/2021", + title: "friday", + ), + TimePlannerTitle( + date: "3/30/2021", + title: "saturday", + ), + ], + tasks: tasks, + style: TimePlannerStyle( + // cellHeight: 60, + // cellWidth: 60, + showScrollBar: true), + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () => _addObject(context), + tooltip: 'Add random task', + child: Icon(Icons.add), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/example_timeline_tile.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/example_timeline_tile.dart new file mode 100644 index 00000000..76c8017e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/example_timeline_tile.dart @@ -0,0 +1,3 @@ +library example_timeline_tile; + +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/axis.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/axis.dart new file mode 100644 index 00000000..867f7dc7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/axis.dart @@ -0,0 +1,163 @@ +import 'dart:core'; + +import 'package:flutter/foundation.dart'; + +/// Given an axis that has an object positioned somewhere between the start and +/// end point, this represents the different sizes and coordinates of this axis. +@immutable +class AxisPosition { + const AxisPosition({ + @required this.firstSpace, + @required this.objectSpace, + @required this.secondSpace, + }); + + final AxisCoordinates firstSpace; + final AxisCoordinates objectSpace; + final AxisCoordinates secondSpace; + + double get totalSize => firstSpace.size + objectSpace.size + secondSpace.size; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is AxisPosition && + runtimeType == other.runtimeType && + firstSpace == other.firstSpace && + objectSpace == other.objectSpace && + secondSpace == other.secondSpace; + + @override + int get hashCode => + firstSpace.hashCode ^ objectSpace.hashCode ^ secondSpace.hashCode; + + @override + String toString() { + return 'AxisPosition{' + 'firstSpace: $firstSpace, ' + 'objectSpace: $objectSpace, ' + 'secondSpace: $secondSpace}'; + } +} + +/// The coordinates to position an object into an axis. +@immutable +class AxisCoordinates { + const AxisCoordinates({ + @required this.start, + @required this.end, + }) : size = end - start, + assert( + end >= start, + 'The end coordinate must be bigger or equals than the start coordinate', + ); + + factory AxisCoordinates.zero() { + return const AxisCoordinates(start: 0, end: 0); + } + + /// The position it starts + final double start; + + /// The position it ends + final double end; + + /// The sum of space between [start] and [end] + final double size; + + double get center => start + (size / 2); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is AxisCoordinates && + runtimeType == other.runtimeType && + start == other.start && + end == other.end && + size == other.size; + + @override + int get hashCode => start.hashCode ^ end.hashCode ^ size.hashCode; + + @override + String toString() { + return 'AxisCoordinates{start: $start, end: $end, size: $size}'; + } +} + +/// Given an axis (x or y) of [totalSize], this will calculate how to position +/// an object in the axis based on its [objectSize] and the [axisPosition]. +/// If the object exceed the [totalSize] at the top or the bottom, it will +/// be aligned at the start or at the end with [_alignObject]. +AxisPosition calculateAxisPositioning({ + @required double totalSize, + @required double objectSize, + @required double axisPosition, +}) { + if (axisPosition < 0.0 || axisPosition > 1.0) { + throw AssertionError('The axisPosition must be provided and must be a value' + ' between 0.0 and 1.0 inclusive'); + } + + if (objectSize >= totalSize) + return _alignObject( + totalSize: totalSize, + objectSize: objectSize, + alignEnd: true, + alignStart: true, + ); + + final objectCenter = totalSize * axisPosition; + final objectHalfSize = objectSize / 2; + + final firstSize = objectCenter - objectHalfSize; + if (firstSize < 0) + return _alignObject( + totalSize: totalSize, + objectSize: objectSize, + alignStart: true, + ); + + final secondSize = totalSize - objectCenter - objectHalfSize; + if (secondSize < 0) + return _alignObject( + totalSize: totalSize, + objectSize: objectSize, + alignEnd: true, + ); + + return AxisPosition( + firstSpace: AxisCoordinates(start: 0, end: firstSize), + objectSpace: AxisCoordinates(start: firstSize, end: firstSize + objectSize), + secondSpace: AxisCoordinates(start: firstSize + objectSize, end: totalSize), + ); +} + +AxisPosition _alignObject({ + @required double totalSize, + @required double objectSize, + bool alignStart = false, + bool alignEnd = false, +}) { + if (alignStart == false && alignEnd == false) + throw AssertionError('Either alignTop or alignBottom must be true'); + + if (alignStart && alignEnd) + return AxisPosition( + firstSpace: AxisCoordinates.zero(), + objectSpace: AxisCoordinates(start: 0, end: totalSize), + secondSpace: AxisCoordinates.zero(), + ); + + return AxisPosition( + firstSpace: alignStart + ? AxisCoordinates.zero() + : AxisCoordinates(start: 0, end: totalSize - objectSize), + objectSpace: alignStart + ? AxisCoordinates(start: 0, end: objectSize) + : AxisCoordinates(start: totalSize - objectSize, end: totalSize), + secondSpace: alignEnd + ? AxisCoordinates(start: totalSize, end: totalSize) + : AxisCoordinates(start: objectSize, end: totalSize), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/style.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/style.dart new file mode 100644 index 00000000..d80cac76 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/style.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'tile.dart'; + +/// Used to customize the indicator from the line. +class IndicatorStyle { + const IndicatorStyle({ + this.width = 20, + this.height = 20, + this.indicator, + this.padding = const EdgeInsets.all(0), + this.color = Colors.grey, + this.iconStyle, + this.indicatorXY = 0.5, + this.drawGap = false, + }) : assert(width >= 0, + 'The width must be provided and bigger than 0.0'), + assert(height >= 0, + 'The height must be provided and bigger than 0.0'); + + /// The width from the indicator. + /// It defaults to 20. + /// Ignored in case the default indicator is rendered and the tile axis + /// is [TimelineAxis.horizontal]. + final double width; + + /// The height from the indicator. + /// It defaults to 20. + /// Ignored in case the default indicator is rendered and the tile axis + /// is [TimelineAxis.vertical]. + final double height; + + /// A custom widget to use as indicator. if not provided it will be rendered a + /// default circle as indicator. + final Widget indicator; + + /// The padding used with the indicator. It defaults to 0. + final EdgeInsets padding; + + /// The color used to paint the default indicator. It defaults to ([Colors.grey]). + final Color color; + + /// The style of the icon used inside the default indicator, if any. + /// It will only be used with the default indicator, and ignored in case there + /// is a custom indicator provided. + final IconStyle iconStyle; + + /// Value from 0.0 to 1.0 indicating the percentage in which the indicator + /// should be positioned on the line, either on Y if [TimelineAxis.vertical] + /// or X if [TimelineAxis.horizontal]. + /// For example, 0.2 means 20% from start to end. It defaults to 0.5. + final double indicatorXY; + + /// If the line must not be drawn behind the icon. If true, there will be a gap + /// even if the vertical/horizontal padding is 0. It defaults to false. + final bool drawGap; + + /// The total indicator height, including padding. + double get totalHeight => height + padding.top + padding.bottom; + + /// The total indicator width, including padding. + double get totalWidth => width + padding.left + padding.right; +} + +/// Used to customize the icon used with the default indicator. +class IconStyle { + IconStyle({ + @required this.iconData, + this.color = Colors.black, + this.fontSize, + }); + + /// The icon to render. + final IconData iconData; + + /// The color used to paint the icon. It defaults to ([Colors.black]). + final Color color; + + /// The fontSize from the line. If not provided, it will try to adjust the + /// icon size based on the default indicator size. According to ([IndicatorStyle.width]). + final double fontSize; +} + +/// Used to customize the line +class LineStyle { + const LineStyle({ + this.color = Colors.grey, + this.thickness = 4, + }); + + /// The color used to paint the line. It defaults to ([Colors.grey]). + final Color color; + + /// The thickness from the line. It can't be bigger than ([IndicatorStyle.width]) + /// and defaults to 4. + final double thickness; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/tile.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/tile.dart new file mode 100644 index 00000000..3638d151 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/tile.dart @@ -0,0 +1,601 @@ +import 'dart:math'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'axis.dart'; +import 'style.dart'; + +/// The axis used on the [TimelineTile]. +enum TimelineAxis { + /// Renders the tile in the [vertical] axis. + vertical, + + /// Renders the tile in the [horizontal] axis. + horizontal, +} + +/// The alignment used on the [TimelineTile]. +enum TimelineAlign { + /// Automatically align the line to the start according to [TimelineAxis], + /// only the ([TimelineTile.rightChild]) will be available. + start, + + /// Automatically align the line to the end according to [TimelineAxis], + /// only the ([TimelineTile.leftChild]) will be available. + end, + + /// Automatically align the line to the center, both ([TimelineTile.leftChild]) + /// and ([TimelineTile.rightChild]) will be available. + center, + + /// Indicates that the line will be aligned manually and must be used with ([TimelineTile.lineX]), + /// both ([TimelineTile.leftChild]) and ([TimelineTile.rightChild]) will be available + /// depending on the free space. + manual, +} + +/// A tile that renders a timeline format. +class TimelineTile extends StatelessWidget { + const TimelineTile({ + Key key, + this.axis = TimelineAxis.vertical, + this.alignment = TimelineAlign.start, + this.startChild, + this.endChild, + this.lineXY, + this.hasIndicator = true, + this.isFirst = false, + this.isLast = false, + this.indicatorStyle = const IndicatorStyle(width: 25), + this.beforeLineStyle = const LineStyle(), + LineStyle afterLineStyle, + }) : afterLineStyle = afterLineStyle ?? beforeLineStyle, + assert(alignment != TimelineAlign.start || startChild == null, + 'Cannot provide startChild with automatic alignment to the left'), + assert(alignment != TimelineAlign.end || endChild == null, + 'Cannot provide endChild with automatic alignment to the right'), + assert( + alignment != TimelineAlign.manual || + (lineXY != null && lineXY >= 0.0 && lineXY <= 1.0), + 'The lineX must be provided when aligning manually, ' + 'and must be a value between 0.0 and 1.0 inclusive'), + super(key: key); + + /// The axis used on the tile. See [TimelineAxis]. + /// It defaults to [TimelineAxis.vertical] + final TimelineAxis axis; + + /// The alignment used on the line. See [TimelineAlign]. + /// It defaults to [TimelineAlign.start] + final TimelineAlign alignment; + + /// The child widget positioned at the start + final Widget startChild; + + /// The child widget positioned at the end + final Widget endChild; + + /// The X (in case of [TimelineAxis.vertical]) or Y (in case of [TimelineAxis.horizontal]) + /// axis value used to position the line when [TimelineAlign.manual]. + /// Must be a value from 0.0 to 1.0 + final double lineXY; + + /// Whether it should have an indicator (default or custom). + /// It defaults to true. + final bool hasIndicator; + + /// Whether this is the first tile from the timeline. + /// In this case, it won't be rendered a line before the indicator. + final bool isFirst; + + /// Whether this is the last tile from the timeline. + /// In this case, it won't be rendered a line after the indicator. + final bool isLast; + + /// The style used to customize the indicator. + final IndicatorStyle indicatorStyle; + + /// The style used to customize the line rendered before the indicator. + final LineStyle beforeLineStyle; + + /// The style used to customize the line rendered after the indicator. + /// If null, it defaults to [beforeLineStyle]. + final LineStyle afterLineStyle; + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + double startCrossAxisSpace = 0; + double endCrossAxisSpace = 0; + if (axis == TimelineAxis.vertical) { + startCrossAxisSpace = indicatorStyle.padding.left; + endCrossAxisSpace = indicatorStyle.padding.right; + } else { + startCrossAxisSpace = indicatorStyle.padding.top; + endCrossAxisSpace = indicatorStyle.padding.bottom; + } + + final children = [ + if (startCrossAxisSpace > 0) + SizedBox( + height: + axis == TimelineAxis.vertical ? null : startCrossAxisSpace, + width: axis == TimelineAxis.vertical ? startCrossAxisSpace : null, + ), + _Indicator( + axis: axis, + beforeLineStyle: beforeLineStyle, + afterLineStyle: afterLineStyle, + indicatorStyle: indicatorStyle, + hasIndicator: hasIndicator, + isLast: isLast, + isFirst: isFirst, + ), + if (endCrossAxisSpace > 0) + SizedBox( + height: axis == TimelineAxis.vertical ? null : endCrossAxisSpace, + width: axis == TimelineAxis.vertical ? endCrossAxisSpace : null, + ), + ]; + + final defaultChild = axis == TimelineAxis.vertical + ? Container(height: 100) + : Container(width: 100); + if (alignment == TimelineAlign.start) { + children.add(Expanded(child: endChild ?? defaultChild)); + } else if (alignment == TimelineAlign.end) { + children.insert(0, Expanded(child: startChild ?? defaultChild)); + } else { + final indicatorAxisXY = + alignment == TimelineAlign.center ? 0.5 : lineXY; + final indicatorTotalSize = _indicatorTotalSize(); + + final positioning = calculateAxisPositioning( + totalSize: axis == TimelineAxis.vertical + ? constraints.maxWidth + : constraints.maxHeight, + objectSize: indicatorTotalSize, + axisPosition: indicatorAxisXY, + ); + + if (positioning.firstSpace.size > 0) { + children.insert( + 0, + SizedBox( + height: axis == TimelineAxis.horizontal + ? positioning.firstSpace.size + : null, + width: axis == TimelineAxis.vertical + ? positioning.firstSpace.size + : null, + child: startChild ?? defaultChild, + ), + ); + } + + if (positioning.secondSpace.size > 0) { + children.add( + SizedBox( + height: axis == TimelineAxis.horizontal + ? positioning.secondSpace.size + : null, + width: axis == TimelineAxis.vertical + ? positioning.secondSpace.size + : null, + child: endChild ?? defaultChild, + ), + ); + } + } + + return axis == TimelineAxis.vertical + ? IntrinsicHeight( + child: Row( + mainAxisSize: MainAxisSize.max, + children: children, + ), + ) + : IntrinsicWidth( + child: Column( + mainAxisSize: MainAxisSize.max, + children: children, + ), + ); + }, + ); + } + + double _indicatorTotalSize() { + if (axis == TimelineAxis.vertical) { + return indicatorStyle.padding.left + + indicatorStyle.padding.right + + (hasIndicator + ? indicatorStyle.width + : max(beforeLineStyle.thickness, afterLineStyle.thickness)); + } + + return indicatorStyle.padding.top + + indicatorStyle.padding.bottom + + (hasIndicator + ? indicatorStyle.height + : max(beforeLineStyle.thickness, afterLineStyle.thickness)); + } +} + +class _Indicator extends StatelessWidget { + const _Indicator({ + @required this.axis, + @required this.beforeLineStyle, + @required this.afterLineStyle, + @required this.indicatorStyle, + @required this.hasIndicator, + @required this.isFirst, + @required this.isLast, + }); + + /// See [TimelineTile.axis] + final TimelineAxis axis; + + /// See [TimelineTile.beforeLineStyle] + final LineStyle beforeLineStyle; + + /// See [TimelineTile.afterLineStyle] + final LineStyle afterLineStyle; + + /// See [TimelineTile.indicatorStyle] + final IndicatorStyle indicatorStyle; + + /// See [TimelineTile.hasIndicator] + final bool hasIndicator; + + /// See [TimelineTile.isFirst] + final bool isFirst; + + /// See [TimelineTile.isLast] + final bool isLast; + + @override + Widget build(BuildContext context) { + double size; + if (axis == TimelineAxis.vertical) { + size = hasIndicator + ? indicatorStyle.width + : max(beforeLineStyle.thickness, afterLineStyle.thickness); + } else { + size = hasIndicator + ? indicatorStyle.height + : max(beforeLineStyle.thickness, afterLineStyle.thickness); + } + + final childrenStack = [ + SizedBox( + height: axis == TimelineAxis.vertical ? double.infinity : size, + width: axis == TimelineAxis.vertical ? size : double.infinity, + ) + ]; + + final renderDefaultIndicator = + hasIndicator && indicatorStyle.indicator == null; + if (!renderDefaultIndicator) { + childrenStack.add( + _buildCustomIndicator(), + ); + } + + final painter = _TimelinePainter( + axis: axis, + beforeLineStyle: beforeLineStyle, + afterLineStyle: afterLineStyle, + indicatorStyle: indicatorStyle, + paintIndicator: renderDefaultIndicator, + isFirst: isFirst, + isLast: isLast, + ); + + return CustomPaint( + painter: painter, + child: Stack( + children: childrenStack, + ), + ); + } + + Widget _buildCustomIndicator() { + return Positioned.fill( + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + AxisPosition position; + EdgeInsets spaceChildren; + EdgeInsets spacePadding; + if (axis == TimelineAxis.vertical) { + position = calculateAxisPositioning( + totalSize: constraints.maxHeight, + objectSize: indicatorStyle.totalHeight, + axisPosition: indicatorStyle.indicatorXY, + ); + spaceChildren = EdgeInsets.only( + top: position.firstSpace.size, + bottom: position.secondSpace.size, + ); + spacePadding = EdgeInsets.only( + top: indicatorStyle.padding.top, + bottom: indicatorStyle.padding.bottom, + ); + } else { + position = calculateAxisPositioning( + totalSize: constraints.maxWidth, + objectSize: indicatorStyle.totalWidth, + axisPosition: indicatorStyle.indicatorXY, + ); + spaceChildren = EdgeInsets.only( + left: position.firstSpace.size, + right: position.secondSpace.size, + ); + spacePadding = EdgeInsets.only( + left: indicatorStyle.padding.left, + right: indicatorStyle.padding.right, + ); + } + + return Padding( + padding: spaceChildren, + child: Padding( + padding: spacePadding, + child: SizedBox( + height: indicatorStyle.height, + width: indicatorStyle.width, + child: indicatorStyle.indicator, + ), + ), + ); + }, + ), + ); + } +} + +/// A custom painter that renders a line and an indicator +class _TimelinePainter extends CustomPainter { + _TimelinePainter({ + @required this.axis, + this.paintIndicator = true, + this.isFirst = false, + this.isLast = false, + @required IndicatorStyle indicatorStyle, + @required LineStyle beforeLineStyle, + @required LineStyle afterLineStyle, + }) : beforeLinePaint = Paint() + ..color = beforeLineStyle.color + ..strokeWidth = beforeLineStyle.thickness, + afterLinePaint = Paint() + ..color = afterLineStyle.color + ..strokeWidth = afterLineStyle.thickness, + indicatorPaint = + !paintIndicator ? null : (Paint()..color = indicatorStyle.color), + indicatorXY = indicatorStyle.indicatorXY, + indicatorSize = axis == TimelineAxis.vertical + ? (paintIndicator + ? indicatorStyle.width + : (indicatorStyle.indicator != null + ? indicatorStyle.height + : 0)) + : (paintIndicator + ? indicatorStyle.height + : (indicatorStyle.indicator != null + ? indicatorStyle.width + : 0)), + indicatorStartGap = axis == TimelineAxis.vertical + ? indicatorStyle.padding.top + : indicatorStyle.padding.left, + indicatorEndGap = axis == TimelineAxis.vertical + ? indicatorStyle.padding.bottom + : indicatorStyle.padding.right, + drawGap = indicatorStyle.drawGap, + iconData = indicatorStyle.iconStyle != null + ? indicatorStyle.iconStyle?.iconData + : null, + iconColor = indicatorStyle.iconStyle != null + ? indicatorStyle.iconStyle?.color + : null, + iconSize = indicatorStyle.iconStyle != null + ? indicatorStyle.iconStyle?.fontSize + : null; + + /// The axis used to render the line at the [TimelineAxis.vertical] + /// or [TimelineAxis.horizontal]. + final TimelineAxis axis; + + /// Value from 0.0 to 1.0 indicating the percentage in which the indicator + /// should be positioned on the line, either on Y if [TimelineAxis.vertical] + /// or X if [TimelineAxis.horizontal]. + /// For example, 0.2 means 20% from start to end. It defaults to 0.5. + final double indicatorXY; + + /// A gap/space between the line and the indicator + final double indicatorStartGap; + + /// A gap/space between the line and the indicator + final double indicatorEndGap; + + /// The size from the indicator. If it is the default indicator, the height + /// will be equal to the width (when axis vertical), or the width will be + /// equal to the height (when axis horizontal), which is the equivalent of the + /// diameter of the circumference. + final double indicatorSize; + + /// Used to paint the top line + final Paint beforeLinePaint; + + /// Used to paint the bottom line + final Paint afterLinePaint; + + /// Used to paint the indicator + final Paint indicatorPaint; + + /// Whether it should paint a default indicator. It defaults to true. + final bool paintIndicator; + + /// Whether this paint should start the line somewhere in the middle, + /// according to [indicatorY]. It defaults to false. + final bool isFirst; + + /// Whether this paint should end the line somewhere in the middle, + /// according to [indicatorY]. It defaults to false. + final bool isLast; + + /// If there must be a gap between the lines. The gap size will always be the + /// [indicatorSize] + [indicatorStartGap] + [indicatorEndGap]. + final bool drawGap; + + /// The icon rendered with the default indicator. + final IconData iconData; + + /// The icon color. + final Color iconColor; + + /// The icon size. If not provided, the size will be adjusted according to [indicatorRadius]. + final double iconSize; + + @override + void paint(Canvas canvas, Size size) { + final hasGap = indicatorStartGap > 0 || indicatorEndGap > 0 || drawGap; + + final centerAxis = + axis == TimelineAxis.vertical ? size.width / 2 : size.height / 2; + final indicatorTotalSize = + indicatorSize + indicatorEndGap + indicatorStartGap; + final position = calculateAxisPositioning( + totalSize: axis == TimelineAxis.vertical ? size.height : size.width, + objectSize: indicatorTotalSize, + axisPosition: indicatorXY, + ); + + if (!hasGap) { + _drawSingleLine(canvas, centerAxis, position); + } else { + if (!isFirst) { + _drawBeforeLine(canvas, centerAxis, position); + } + if (!isLast) { + _drawAfterLine(canvas, centerAxis, position); + } + } + + if (paintIndicator) { + final indicatorRadius = + (position.objectSpace.size - indicatorStartGap - indicatorEndGap) / 2; + final indicatorCenterPoint = + position.objectSpace.start + indicatorStartGap + indicatorRadius; + + final indicatorCenter = axis == TimelineAxis.vertical + ? Offset(centerAxis, indicatorCenterPoint) + : Offset(indicatorCenterPoint, centerAxis); + canvas.drawCircle(indicatorCenter, indicatorRadius, indicatorPaint); + + if (iconData != null) { + var fontSize = iconSize; + fontSize ??= (indicatorRadius * 2) - 10; + + final builder = ui.ParagraphBuilder(ui.ParagraphStyle( + fontFamily: iconData.fontFamily, + )); + builder.pushStyle(ui.TextStyle( + fontSize: fontSize, + color: iconColor, + )); + builder.addText(String.fromCharCode(iconData.codePoint)); + + final paragraph = builder.build(); + paragraph.layout(const ui.ParagraphConstraints(width: 0.0)); + + final halfIconSize = fontSize / 2; + final offsetIcon = Offset(indicatorCenter.dx - halfIconSize, + indicatorCenter.dy - halfIconSize); + canvas.drawParagraph(paragraph, offsetIcon); + } + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return false; + } + + void _drawSingleLine( + Canvas canvas, double centerAxis, AxisPosition position) { + if (!isFirst) { + final beginTopLine = axis == TimelineAxis.vertical + ? Offset(centerAxis, 0) + : Offset(0, centerAxis); + final endTopLine = axis == TimelineAxis.vertical + ? Offset( + centerAxis, + paintIndicator || !drawGap + ? position.objectSpace.center + : position.firstSpace.end, + ) + : Offset( + paintIndicator || !drawGap + ? position.objectSpace.center + : position.firstSpace.end, + centerAxis, + ); + canvas.drawLine(beginTopLine, endTopLine, beforeLinePaint); + } + + if (!isLast) { + final beginBottomLine = axis == TimelineAxis.vertical + ? Offset( + centerAxis, + paintIndicator || !drawGap + ? position.objectSpace.center + : position.objectSpace.end, + ) + : Offset( + paintIndicator || !drawGap + ? position.objectSpace.center + : position.objectSpace.end, + centerAxis, + ); + final endBottomLine = axis == TimelineAxis.vertical + ? Offset(centerAxis, position.secondSpace.end) + : Offset(position.secondSpace.end, centerAxis); + canvas.drawLine(beginBottomLine, endBottomLine, afterLinePaint); + } + } + + void _drawBeforeLine( + Canvas canvas, double centerAxis, AxisPosition position) { + final beginTopLine = axis == TimelineAxis.vertical + ? Offset(centerAxis, 0) + : Offset(0, centerAxis); + final endTopLine = axis == TimelineAxis.vertical + ? Offset(centerAxis, position.firstSpace.end) + : Offset(position.firstSpace.end, centerAxis); + + final lineSize = + axis == TimelineAxis.vertical ? endTopLine.dy : endTopLine.dx; + // if the line size is less or equal than 0, the line shouldn't be rendered + if (lineSize > 0) { + canvas.drawLine(beginTopLine, endTopLine, beforeLinePaint); + } + } + + void _drawAfterLine(Canvas canvas, double centerAxis, AxisPosition position) { + final beginBottomLine = axis == TimelineAxis.vertical + ? Offset(centerAxis, position.secondSpace.start) + : Offset(position.secondSpace.start, centerAxis); + final endBottomLine = axis == TimelineAxis.vertical + ? Offset(centerAxis, position.secondSpace.end) + : Offset(position.secondSpace.end, centerAxis); + + final lineSize = axis == TimelineAxis.vertical + ? endBottomLine.dy - beginBottomLine.dy + : endBottomLine.dx - beginBottomLine.dx; + // if the line size is less or equal than 0, the line shouldn't be rendered + if (lineSize > 0) { + canvas.drawLine(beginBottomLine, endBottomLine, afterLinePaint); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/timeline_divider.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/timeline_divider.dart new file mode 100644 index 00000000..5dfc5ab1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/src/timeline_divider.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'tile.dart'; + +/// This is a port from the original [Divider]. +/// Except that this one allows to define the start and end +/// according to the width available, with percentage values +/// from 0.0 to 1.0 +class TimelineDivider extends StatelessWidget { + /// Creates a material design divider that can be used in conjunction to [TimelineTile]. + const TimelineDivider({ + Key key, + this.axis = TimelineAxis.horizontal, + this.thickness = 2, + this.begin = 0.0, + this.end = 1.0, + this.color = Colors.grey, + }) : assert(thickness >= 0.0, 'The thickness must be a positive value'), + assert(begin >= 0.0 && begin <= 1.0, + 'The begin value must be between 0.0 and 1.0'), + assert(end >= 0.0 && end <= 1.0, + 'The end value must be between 0.0 and 1.0'), + assert(end > begin, 'The end value must be bigger than the begin'), + super(key: key); + + /// The axis used to render the line at the [TimelineAxis.vertical] + /// or [TimelineAxis.horizontal]. Usually, the opposite axis from the tiles. + /// It defaults to [TimelineAxis.horizontal]. + final TimelineAxis axis; + + /// The thickness of the line drawn within the divider. + /// + /// It must be a positive value. It defaults to 2. + final double thickness; + + /// Where the line must start to be drawn. + /// This represents a percentage from the available width. + /// + /// It must be less than [end] and defaults to 0.0. + final double begin; + + /// Where the drawn from the line must end. + /// This represents a percentage from the available width. + /// + /// It must be bigger than [begin] and defaults to 1.0. + final double end; + + /// The color to use when painting the line. + /// + /// It defaults to [Colors.grey]. + final Color color; + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + final double halfThickness = thickness / 2; + + EdgeInsetsDirectional margin; + if (axis == TimelineAxis.horizontal) { + final double width = constraints.maxWidth; + final double beginX = width * begin; + final double endX = width * end; + + margin = EdgeInsetsDirectional.only( + start: beginX - halfThickness, + end: width - endX - halfThickness, + ); + } else { + final double height = constraints.maxHeight; + final double beginY = height * begin; + final double endY = height * end; + + margin = EdgeInsetsDirectional.only( + top: beginY - halfThickness, + bottom: height - endY - halfThickness, + ); + } + + return Container( + height: thickness, + margin: margin, + decoration: BoxDecoration( + border: Border( + left: axis == TimelineAxis.vertical + ? BorderSide( + color: color, + width: thickness, + ) + : BorderSide.none, + bottom: axis == TimelineAxis.horizontal + ? BorderSide( + color: color, + width: thickness, + ) + : BorderSide.none, + ), + ), + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/timeline_tile.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/timeline_tile.dart new file mode 100644 index 00000000..700731ce --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/lib/timeline_tile.dart @@ -0,0 +1,5 @@ +library timeline_tile; + +export 'src/tile.dart'; +export 'src/style.dart'; +export 'src/timeline_divider.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/main.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/main.dart new file mode 100644 index 00000000..8c549697 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/main.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import 'src/showcase_timeline_tile.dart'; + +void main() { + runApp(TimelineTileApp()); +} + +class TimelineTileApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'TimelineTile Showcase', + theme: ThemeData( + brightness: Brightness.dark, + textTheme: GoogleFonts.nanumPenScriptTextTheme( + Theme.of(context).textTheme, + ).apply(bodyColor: Colors.white), + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: ShowcaseTimelineTile(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_1.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_1.dart new file mode 100644 index 00000000..a73ce702 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_1.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example1 = Example( + name: 'The simplest tile', + description: 'If the axis is vertical, it aligns default to the start, with ' + 'a height of 100. The tile will always try to be as wide as it can get horizontally.\n\n' + 'If the axis is horizontal, It aligns default to the start, with a width' + 'of 100. The tile will always try to be as wide as it can get vertically.', + code: ''' +/// Vertical +return Container( + color: Colors.white, + child: TimelineTile(), +); +/// Horizontal +return Container( + color: Colors.white, + child: TimelineTile( + axis: TimelineAxis.horizontal, + ), +);''', + childVertical: Example1Vertical(), + childHorizontal: Example1Horizontal(), +); + +class Example1Vertical extends StatelessWidget { + const Example1Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: TimelineTile(), + ), + ], + ), + ); + } +} + +class Example1Horizontal extends StatelessWidget { + const Example1Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Row( + children: [ + Container( + constraints: const BoxConstraints(maxHeight: 100), + color: Colors.white, + child: TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_10.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_10.dart new file mode 100644 index 00000000..c2050268 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_10.dart @@ -0,0 +1,237 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example10 = Example( + name: 'Connect tiles with TimelineDivider.', + description: + 'The TimelineDivider widget allows you to connect tiles that are aligned ' + 'in different horizontal or vertical axis, when combined with TimelineAlign.manual.', + code: ''' +return Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.1, + isFirst: true, + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.purple, + ), + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + ), + const TimelineDivider( + begin: 0.1, + end: 0.9, + thickness: 6, + color: Colors.purple, + ), + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.9, + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + afterLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.cyan, + ), + ), + const TimelineDivider( + begin: 0.1, + end: 0.9, + thickness: 6, + color: Colors.deepOrange, + ), + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.1, + isLast: true, + beforeLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.red, + ), + ), + ], + ), +);''', + childVertical: Example10Vertical(), + childHorizontal: Example10Horizontal(), +); + +class Example10Vertical extends StatelessWidget { + const Example10Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.1, + isFirst: true, + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.purple, + ), + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + ), + const TimelineDivider( + begin: 0.1, + end: 0.9, + thickness: 6, + color: Colors.purple, + ), + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.9, + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + afterLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.cyan, + ), + ), + const TimelineDivider( + begin: 0.1, + end: 0.9, + thickness: 6, + color: Colors.deepOrange, + ), + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.1, + isLast: true, + beforeLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.red, + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class Example10Horizontal extends StatelessWidget { + const Example10Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Center( + child: Container( + constraints: const BoxConstraints(maxHeight: 120), + color: Colors.white, + child: ListView( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: [ + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.manual, + lineXY: 0.1, + isFirst: true, + indicatorStyle: const IndicatorStyle( + height: 20, + color: Colors.purple, + ), + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + ), + const TimelineDivider( + axis: TimelineAxis.vertical, + begin: 0.1, + end: 0.9, + thickness: 6, + color: Colors.purple, + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.manual, + lineXY: 0.9, + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + afterLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + height: 20, + color: Colors.cyan, + ), + ), + const TimelineDivider( + axis: TimelineAxis.vertical, + begin: 0.1, + end: 0.9, + thickness: 6, + color: Colors.deepOrange, + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.manual, + lineXY: 0.1, + isLast: true, + beforeLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + height: 20, + color: Colors.red, + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_2.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_2.dart new file mode 100644 index 00000000..1c653294 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_2.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example2 = Example( + name: 'A centered tile with children', + description: 'With TimelineAlign.center you can configure both start and end ' + 'children. But when providing children to the tile the height (axis vertical) ' + 'or the width (axis horizontal) will be as minimum as possible, so you can ' + 'control it with a height/width constraint (at least minHeight/minWidth). ' + 'This way the tile knows how to size it properly.', + code: ''' +return Container( + color: Colors.white, + child: TimelineTile( + alignment: TimelineAlign.center, + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.lightGreenAccent, + ), + endChild: Container( + color: Colors.amberAccent, + ), + ), + ), +);''', + childVertical: Example2Vertical(), + childHorizontal: Example2Horizontal(), +); + +class Example2Vertical extends StatelessWidget { + const Example2Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: TimelineTile( + alignment: TimelineAlign.center, + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.lightGreenAccent, + ), + endChild: Container( + color: Colors.amberAccent, + ), + ), + ), + ], + ), + ); + } +} + +class Example2Horizontal extends StatelessWidget { + const Example2Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Row( + children: [ + Container( + constraints: const BoxConstraints(maxHeight: 100), + color: Colors.white, + child: TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + startChild: Container( + constraints: const BoxConstraints( + minWidth: 120, + ), + color: Colors.lightGreenAccent, + ), + endChild: Container( + color: Colors.amberAccent, + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_3.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_3.dart new file mode 100644 index 00000000..ed191186 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_3.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example3 = Example( + name: 'Manual aligning the indicator', + description: + 'With TimelineAlign.manual you can provide the lineXY, which allows you to' + 'specify a value from 0.0 to 1.0, that represents a width/height percentage. ' + 'For example, aligning at 0.3(30%) of the width/height:', + code: ''' +return Container( + color: Colors.white, + child: TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.3, + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.lightGreenAccent, + ), + endChild: Container( + color: Colors.amberAccent, + ), + ), +);''', + childVertical: Example3Vertical(), + childHorizontal: Example3Horizontal(), +); + +class Example3Vertical extends StatelessWidget { + const Example3Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.3, + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.lightGreenAccent, + ), + endChild: Container( + color: Colors.amberAccent, + ), + ), + ), + ], + ), + ); + } +} + +class Example3Horizontal extends StatelessWidget { + const Example3Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Row( + children: [ + Container( + constraints: const BoxConstraints(maxHeight: 100), + color: Colors.white, + child: TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.manual, + lineXY: 0.3, + startChild: Container( + constraints: const BoxConstraints( + minWidth: 120, + ), + color: Colors.lightGreenAccent, + ), + endChild: Container( + color: Colors.amberAccent, + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_4.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_4.dart new file mode 100644 index 00000000..df209dd2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_4.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example4 = Example( + name: 'Is it the first or the last?', + description: + 'You can decide if a tile is the first or the last in a timeline. ' + 'This way you control whether a start or end line must be rendered.', + code: ''' +return Container( + color: Colors.white, + child: TimelineTile( + alignment: TimelineAlign.end, + isFirst: true, + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), +);''', + childVertical: Example4Vertical(), + childHorizontal: Example4Horizontal(), +); + +class Example4Vertical extends StatelessWidget { + const Example4Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: TimelineTile( + alignment: TimelineAlign.end, + isFirst: true, + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + ), + ], + ), + ); + } +} + +class Example4Horizontal extends StatelessWidget { + const Example4Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Row( + children: [ + Container( + constraints: const BoxConstraints(maxHeight: 100), + color: Colors.white, + child: TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.end, + isFirst: true, + startChild: Container( + constraints: const BoxConstraints( + minWidth: 120, + ), + color: Colors.amberAccent, + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_5.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_5.dart new file mode 100644 index 00000000..4c695212 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_5.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example5 = Example( + name: 'Start to make a timeline!!', + description: 'You can finally start to combine some tiles to make a Timeline.' + ' The flag hasIndicator can control whether an indicator should or' + " shouldn't be rendered.", + code: ''' +return Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.7, + isFirst: true, + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.7, + hasIndicator: false, + startChild: Container( + height: 50, + color: Colors.purple, + ), + endChild: Container( + color: Colors.cyan, + ), + ), + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.7, + isLast: true, + endChild: Container( + constraints: const BoxConstraints( + minHeight: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), +);''', + childVertical: Example5Vertical(), + childHorizontal: Example5Horizontal(), +); + +class Example5Vertical extends StatelessWidget { + const Example5Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.7, + isFirst: true, + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.7, + hasIndicator: false, + startChild: Container( + height: 50, + color: Colors.purple, + ), + endChild: Container( + color: Colors.cyan, + ), + ), + TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.7, + isLast: true, + endChild: Container( + constraints: const BoxConstraints( + minHeight: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class Example5Horizontal extends StatelessWidget { + const Example5Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Center( + child: Container( + constraints: const BoxConstraints(maxHeight: 100), + color: Colors.white, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.manual, + lineXY: 0.7, + isFirst: true, + startChild: Container( + constraints: const BoxConstraints( + minWidth: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.manual, + lineXY: 0.7, + hasIndicator: false, + startChild: Container( + width: 50, + color: Colors.purple, + ), + endChild: Container( + color: Colors.cyan, + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.manual, + lineXY: 0.7, + isLast: true, + endChild: Container( + constraints: const BoxConstraints( + minWidth: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_6.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_6.dart new file mode 100644 index 00000000..6ef8300f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_6.dart @@ -0,0 +1,224 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example6 = Example( + name: 'Customize the indicator as you wish. ', + description: 'The default indicator is a circle, and you can customize it ' + 'as you wish.\nWith IndicatorStyle you can change the color, the X/Y ' + 'position based on values from 0.0 to 1.0 or give it a padding.\n' + 'You must explicitly provide its height/width (depending on axis) though.', + code: ''' +return Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.purple, + indicatorXY: 0.2, + padding: EdgeInsets.all(8), + ), + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + indicatorStyle: const IndicatorStyle( + width: 10, + color: Colors.black, + padding: EdgeInsets.only( + top: 8, + left: 4, + right: 4, + ), + ), + startChild: Container( + height: 50, + color: Colors.purple, + ), + endChild: Container( + color: Colors.cyan, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + isLast: true, + indicatorStyle: const IndicatorStyle( + width: 30, + color: Colors.red, + indicatorXY: 0.3, + ), + endChild: Container( + constraints: const BoxConstraints( + minHeight: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), +);''', + childVertical: Example6Vertical(), + childHorizontal: Example6Horizontal(), +); + +class Example6Vertical extends StatelessWidget { + const Example6Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.purple, + indicatorXY: 0.2, + padding: EdgeInsets.all(8), + ), + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + indicatorStyle: const IndicatorStyle( + width: 10, + color: Colors.black, + padding: EdgeInsets.only( + top: 8, + left: 4, + right: 4, + ), + ), + startChild: Container( + height: 50, + color: Colors.purple, + ), + endChild: Container( + color: Colors.cyan, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + isLast: true, + indicatorStyle: const IndicatorStyle( + width: 30, + color: Colors.red, + indicatorXY: 0.3, + ), + endChild: Container( + constraints: const BoxConstraints( + minHeight: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class Example6Horizontal extends StatelessWidget { + const Example6Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Center( + child: Container( + constraints: const BoxConstraints(maxHeight: 100), + color: Colors.white, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: const IndicatorStyle( + height: 20, + color: Colors.purple, + indicatorXY: 0.2, + padding: EdgeInsets.all(8), + ), + startChild: Container( + constraints: const BoxConstraints( + minWidth: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + indicatorStyle: const IndicatorStyle( + height: 10, + color: Colors.black, + padding: EdgeInsets.only( + top: 8, + bottom: 8, + left: 4, + right: 4, + ), + ), + startChild: Container( + width: 50, + color: Colors.purple, + ), + endChild: Container( + color: Colors.cyan, + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + isLast: true, + indicatorStyle: const IndicatorStyle( + height: 30, + color: Colors.red, + indicatorXY: 0.3, + ), + endChild: Container( + constraints: const BoxConstraints( + minWidth: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_7.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_7.dart new file mode 100644 index 00000000..2fe13316 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_7.dart @@ -0,0 +1,184 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example7 = Example( + name: 'Give an Icon to the indicator.', + description: 'With IconStyle you can provide an Icon to be rendered inside ' + 'the default indicator.', + code: ''' +return Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: IndicatorStyle( + width: 40, + color: Colors.purple, + padding: const EdgeInsets.all(8), + iconStyle: IconStyle( + color: Colors.white, + iconData: Icons.insert_emoticon, + ), + ), + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + isLast: true, + indicatorStyle: IndicatorStyle( + width: 30, + color: Colors.red, + indicatorXY: 0.7, + iconStyle: IconStyle( + color: Colors.white, + iconData: Icons.thumb_up, + ), + ), + endChild: Container( + constraints: const BoxConstraints( + minHeight: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), +);''', + childVertical: Example7Vertical(), + childHorizontal: Example7Horizontal(), +); + +class Example7Vertical extends StatelessWidget { + const Example7Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: IndicatorStyle( + width: 40, + color: Colors.purple, + padding: const EdgeInsets.all(8), + iconStyle: IconStyle( + color: Colors.white, + iconData: Icons.insert_emoticon, + ), + ), + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + isLast: true, + indicatorStyle: IndicatorStyle( + width: 30, + color: Colors.red, + indicatorXY: 0.7, + iconStyle: IconStyle( + color: Colors.white, + iconData: Icons.thumb_up, + ), + ), + endChild: Container( + constraints: const BoxConstraints( + minHeight: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class Example7Horizontal extends StatelessWidget { + const Example7Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Center( + child: Container( + constraints: const BoxConstraints(maxHeight: 100), + color: Colors.white, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: IndicatorStyle( + height: 40, + color: Colors.purple, + padding: const EdgeInsets.all(8), + iconStyle: IconStyle( + color: Colors.white, + iconData: Icons.insert_emoticon, + ), + ), + startChild: Container( + constraints: const BoxConstraints( + minWidth: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + isLast: true, + indicatorStyle: IndicatorStyle( + height: 30, + color: Colors.red, + indicatorXY: 0.7, + iconStyle: IconStyle( + color: Colors.white, + iconData: Icons.thumb_up, + ), + ), + endChild: Container( + constraints: const BoxConstraints( + minWidth: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_8.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_8.dart new file mode 100644 index 00000000..7bb76d77 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_8.dart @@ -0,0 +1,319 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example8 = Example( + name: 'Or provide your own custom indicator.', + description: + 'With the indicator parameter you can customize the tile with your own ' + 'indicator.\nHowever, you must control its size through both width and ' + 'height parameters.', + code: ''' +class Example8 extends StatelessWidget { + const Example8({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.end, + isFirst: true, + indicatorStyle: IndicatorStyle( + width: 40, + height: 60, + padding: const EdgeInsets.all(8), + indicator: Image.asset('assets/hitchhiker_2.png'), + ), + startChild: const _Child( + text: "Don't Panic!", + font: 'Bungee', + ), + ), + TimelineTile( + alignment: TimelineAlign.end, + indicatorStyle: IndicatorStyle( + width: 40, + height: 40, + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), + drawGap: true, + indicator: Container( + decoration: const BoxDecoration( + border: Border.fromBorderSide( + BorderSide( + color: Colors.grey, + ), + ), + shape: BoxShape.circle, + ), + child: const Center( + child: Text( + '42', + style: TextStyle( + color: Colors.deepOrange, + fontSize: 30, + ), + ), + ), + ), + ), + startChild: const _Child( + text: 'So long, and thanks', + ), + ), + TimelineTile( + alignment: TimelineAlign.end, + isLast: true, + indicatorStyle: IndicatorStyle( + width: 40, + height: 40, + padding: const EdgeInsets.all(8), + indicator: Image.asset('assets/hitchhiker.png'), + ), + startChild: const _Child( + text: 'for all the fish !', + ), + ), + ], + ), + ); + } +} + +class _Child extends StatelessWidget { + const _Child({ + Key key, + this.text, + this.font = 'Shrikhand', + }) : super(key: key); + + final String text; + final String font; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(8), + color: Colors.amberAccent, + constraints: const BoxConstraints(minHeight: 120), + child: Center( + child: Text( + text, + textAlign: TextAlign.center, + style: GoogleFonts.getFont( + font, + color: Colors.deepOrange, + fontSize: 26, + ), + ), + ), + ); + } +};''', + childVertical: Example8Vertical(), + childHorizontal: Example8Horizontal(), +); + +class Example8Vertical extends StatelessWidget { + const Example8Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.end, + isFirst: true, + indicatorStyle: IndicatorStyle( + width: 40, + height: 60, + padding: const EdgeInsets.all(8), + indicator: Image.asset('assets/hitchhiker_2.png'), + ), + startChild: const _Child( + text: "Don't Panic!", + font: 'Bungee', + ), + ), + TimelineTile( + alignment: TimelineAlign.end, + indicatorStyle: IndicatorStyle( + width: 40, + height: 40, + padding: const EdgeInsets.symmetric( + horizontal: 8, + ), + drawGap: true, + indicator: Container( + decoration: const BoxDecoration( + border: Border.fromBorderSide( + BorderSide( + color: Colors.grey, + ), + ), + shape: BoxShape.circle, + ), + child: const Center( + child: Text( + '42', + style: TextStyle( + color: Colors.deepOrange, + fontSize: 30, + ), + ), + ), + ), + ), + startChild: const _Child( + text: 'So long, and thanks', + ), + ), + TimelineTile( + alignment: TimelineAlign.end, + isLast: true, + indicatorStyle: IndicatorStyle( + width: 40, + height: 40, + padding: const EdgeInsets.all(8), + indicator: Image.asset('assets/hitchhiker.png'), + ), + startChild: const _Child( + text: 'for all the fish !', + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class Example8Horizontal extends StatelessWidget { + const Example8Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + constraints: const BoxConstraints(maxHeight: 160), + color: Colors.white, + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.end, + isFirst: true, + indicatorStyle: IndicatorStyle( + width: 40, + height: 60, + padding: const EdgeInsets.all(8), + indicator: Image.asset('assets/hitchhiker_2.png'), + ), + startChild: const _Child( + text: "Don't Panic!", + font: 'Bungee', + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.end, + indicatorStyle: IndicatorStyle( + width: 40, + height: 60, + padding: const EdgeInsets.symmetric(vertical: 8), + drawGap: true, + indicator: Container( + decoration: const BoxDecoration( + border: Border.fromBorderSide( + BorderSide( + color: Colors.grey, + ), + ), + shape: BoxShape.circle, + ), + child: const Center( + child: Text( + '42', + style: TextStyle( + color: Colors.deepOrange, + fontSize: 30, + ), + ), + ), + ), + ), + startChild: const _Child( + text: 'So long, and thanks', + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.end, + isLast: true, + indicatorStyle: IndicatorStyle( + width: 40, + height: 60, + padding: const EdgeInsets.all(8), + indicator: Image.asset('assets/hitchhiker.png'), + ), + startChild: const _Child( + text: 'for all the fish !', + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class _Child extends StatelessWidget { + const _Child({ + Key key, + @required this.text, + this.font = 'Shrikhand', + }) : super(key: key); + + final String text; + final String font; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(8), + color: Colors.amberAccent, + constraints: const BoxConstraints(minHeight: 120), + child: Center( + child: Text( + text, + textAlign: TextAlign.center, + style: GoogleFonts.getFont( + font, + color: Colors.deepOrange, + fontSize: 26, + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_9.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_9.dart new file mode 100644 index 00000000..80f80459 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/example/example_9.dart @@ -0,0 +1,225 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import '../showcase_timeline.dart'; + +const example9 = Example( + name: "Customize the tile's line.", + description: + 'With LineStyle you can customize both beforeLine and afterLine.', + code: ''' +return Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.purple, + ), + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + afterLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.cyan, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + isLast: true, + beforeLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.red, + ), + endChild: Container( + constraints: const BoxConstraints( + minHeight: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), +);''', + childVertical: Example9Vertical(), + childHorizontal: Example9Horizontal(), +); + +class Example9Vertical extends StatelessWidget { + const Example9Vertical({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Container( + color: Colors.white, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.purple, + ), + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + startChild: Container( + constraints: const BoxConstraints( + minHeight: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + afterLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.cyan, + ), + ), + TimelineTile( + alignment: TimelineAlign.center, + isLast: true, + beforeLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + width: 20, + color: Colors.red, + ), + endChild: Container( + constraints: const BoxConstraints( + minHeight: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class Example9Horizontal extends StatelessWidget { + const Example9Horizontal({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildListDelegate( + [ + Center( + child: Container( + constraints: const BoxConstraints(maxHeight: 160), + color: Colors.white, + child: ListView( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: [ + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + isFirst: true, + indicatorStyle: const IndicatorStyle( + height: 20, + color: Colors.purple, + ), + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + startChild: Container( + constraints: const BoxConstraints( + minWidth: 120, + ), + color: Colors.amberAccent, + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + beforeLineStyle: const LineStyle( + color: Colors.purple, + thickness: 6, + ), + afterLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + height: 20, + color: Colors.cyan, + ), + ), + TimelineTile( + axis: TimelineAxis.horizontal, + alignment: TimelineAlign.center, + isLast: true, + beforeLineStyle: const LineStyle( + color: Colors.deepOrange, + thickness: 6, + ), + indicatorStyle: const IndicatorStyle( + height: 20, + color: Colors.red, + ), + endChild: Container( + constraints: const BoxConstraints( + minWidth: 80, + ), + color: Colors.lightGreenAccent, + ), + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/showcase_timeline.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/showcase_timeline.dart new file mode 100644 index 00000000..da461013 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/showcase_timeline.dart @@ -0,0 +1,228 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_highlight/flutter_highlight.dart'; +import 'package:flutter_highlight/themes/atelier-sulphurpool-dark.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import 'example/example_1.dart'; +import 'example/example_10.dart'; +import 'example/example_2.dart'; +import 'example/example_3.dart'; +import 'example/example_4.dart'; +import 'example/example_5.dart'; +import 'example/example_6.dart'; +import 'example/example_7.dart'; +import 'example/example_8.dart'; +import 'example/example_9.dart'; + +class ShowcaseTimeline extends StatelessWidget { + const ShowcaseTimeline({Key key, @required this.example}) : super(key: key); + + final Example example; + + @override + Widget build(BuildContext context) { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF004E92), + Color(0xFF000428), + ], + ), + ), + child: SafeArea( + child: Scaffold( + backgroundColor: Colors.transparent, + body: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Text( + example.name, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 32, + color: Colors.white, + ), + ), + const SizedBox(height: 16), + Expanded( + child: CustomScrollView( + slivers: [ + SliverList( + delegate: SliverChildListDelegate( + [ + _Description( + description: example.description, + code: example.code, + ), + const SizedBox(height: 16), + const Text( + 'Vertical Axis:', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 24), + ), + ], + ), + ), + const SliverPadding(padding: EdgeInsets.only(top: 20)), + example.childVertical, + const SliverPadding(padding: EdgeInsets.only(top: 20)), + SliverList( + delegate: SliverChildListDelegate( + [ + const Text( + 'Horizontal Axis:', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 24), + ), + ], + ), + ), + const SliverPadding(padding: EdgeInsets.only(top: 20)), + example.childHorizontal, + const SliverPadding(padding: EdgeInsets.only(top: 40)), + ], + ), + ) + ], + ), + ), + ), + ), + ), + ); + } +} + +class _Code extends StatelessWidget { + const _Code({Key key, @required this.code}) : super(key: key); + + final String code; + + @override + Widget build(BuildContext context) { + return HighlightView( + code, + language: 'dart', + theme: atelierSulphurpoolDarkTheme, + ); + } +} + +class _Description extends StatelessWidget { + const _Description({ + Key key, + @required this.description, + @required this.code, + }) : super(key: key); + + final String description; + final String code; + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(6)), + color: Colors.white.withOpacity(0.2), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.all(16), + child: Text( + description, + style: GoogleFonts.jura(fontSize: 18), + ), + ), + Theme( + data: Theme.of(context).copyWith( + accentColor: Colors.white, + dividerColor: Colors.transparent, + unselectedWidgetColor: Colors.white, + ), + child: ExpansionTile( + title: Text( + ' SOURCE CODE', + style: GoogleFonts.lato( + color: Colors.white.withOpacity(0.7), + fontSize: 16, + ), + ), + children: [ + _Code(code: code), + OutlinedButton( + onPressed: () { + showCodeDialog(context); + }, + child: Text( + 'FULL SCREEN', + style: GoogleFonts.lato( + color: Colors.white.withOpacity(0.7), + fontSize: 16, + ), + ), + style: ButtonStyle( + side: MaterialStateProperty.all( + BorderSide( + color: Colors.white.withOpacity(0.7), + width: 2, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + void showCodeDialog(BuildContext context) { + showDialog( + context: context, + builder: (BuildContext context) { + return Center( + child: SingleChildScrollView( + child: _Code(code: code), + ), + ); + }, + ); + } +} + +class Example { + const Example({ + @required this.name, + @required this.description, + @required this.code, + @required this.childHorizontal, + @required this.childVertical, + }); + + final String name; + final String description; + final String code; + final Widget childVertical; + final Widget childHorizontal; +} + +const examples = [ + example1, + example2, + example3, + example4, + example5, + example6, + example7, + example8, + example9, + example10, +]; diff --git a/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/showcase_timeline_tile.dart b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/showcase_timeline_tile.dart new file mode 100644 index 00000000..f6e15844 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timeline_tile/src/showcase_timeline_tile.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:flutter_helper/samples/timeline_tile/lib/timeline_tile.dart'; + +import 'showcase_timeline.dart'; + +class ShowcaseTimelineTile extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF004E92), + Color(0xFF000428), + ], + ), + ), + child: SafeArea( + child: Scaffold( + backgroundColor: Colors.transparent, + body: Center( + child: Column( + children: [ + const SizedBox(height: 16), + const Text( + 'TimelineTile Showcase', + style: TextStyle( + fontSize: 32, + color: Colors.white, + ), + ), + const SizedBox(height: 16), + Expanded( + child: ListView.builder( + itemCount: examples.length, + itemBuilder: (BuildContext context, int index) { + final example = examples[index]; + + return TimelineTile( + alignment: TimelineAlign.manual, + lineXY: 0.1, + isFirst: index == 0, + isLast: index == examples.length - 1, + indicatorStyle: IndicatorStyle( + width: 40, + height: 40, + indicator: _IndicatorExample(number: '${index + 1}'), + drawGap: true, + ), + beforeLineStyle: LineStyle( + color: Colors.white.withOpacity(0.2), + ), + endChild: GestureDetector( + child: _RowExample(example: example), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => + ShowcaseTimeline(example: example), + ), + ); + }, + ), + ); + }, + ), + ) + ], + ), + ), + ), + ), + ); + } +} + +class _IndicatorExample extends StatelessWidget { + const _IndicatorExample({Key key, @required this.number}) : super(key: key); + + final String number; + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.fromBorderSide( + BorderSide( + color: Colors.white.withOpacity(0.2), + width: 4, + ), + ), + ), + child: Center( + child: Text( + number, + style: const TextStyle(fontSize: 30), + ), + ), + ); + } +} + +class _RowExample extends StatelessWidget { + const _RowExample({Key key, @required this.example}) : super(key: key); + + final Example example; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(20), + child: Row( + children: [ + Expanded( + child: Text( + example.name, + style: GoogleFonts.jura( + color: Colors.white, + fontSize: 18, + ), + ), + ), + const Icon( + Icons.navigate_next, + color: Colors.white, + size: 26, + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/component_page.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/component_page.dart new file mode 100644 index 00000000..87c11a80 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/component_page.dart @@ -0,0 +1,405 @@ +import 'package:flutter/material.dart'; +import 'lib/timelines.dart'; + +import 'widget.dart'; + +class ComponentPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final children = [ + _ComponentRow( + name: 'Dot\nIndicator', + item: DotIndicator(), + ), + _ComponentRow( + name: 'Outlined dot\nIndicator', + item: OutlinedDotIndicator(), + ), + _ComponentRow( + name: 'Container\nIndicator', + item: ContainerIndicator( + child: Container( + width: 15.0, + height: 15.0, + color: Colors.blue, + ), + ), + ), + _ComponentRow( + name: 'Solid line\nConnector', + item: SizedBox( + height: 20.0, + child: SolidLineConnector(), + ), + ), + _ComponentRow( + name: 'Dashed line\nConnector', + item: SizedBox( + height: 20.0, + child: DashedLineConnector(), + ), + ), + _ComponentRow( + name: 'Decorated line\nConnector', + item: SizedBox( + height: 20.0, + child: DecoratedLineConnector( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Colors.blue, Colors.lightBlueAccent.shade100], + ), + ), + ), + ), + ), + _ComponentRow( + name: 'Simple TimelineNode', + item: SizedBox( + height: 50.0, + child: TimelineNode.simple(), + ), + ), + _ComponentRow( + name: 'Complex TimelineNode', + item: SizedBox( + height: 80.0, + child: TimelineNode( + indicator: Card( + margin: EdgeInsets.zero, + child: Padding( + padding: EdgeInsets.all(8.0), + child: Text('Complex'), + ), + ), + startConnector: DashedLineConnector(), + endConnector: SolidLineConnector(), + ), + ), + ), + _ComponentRow( + name: 'TimelineTile', + item: TimelineTile( + oppositeContents: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + contents: Card( + child: Container( + padding: EdgeInsets.all(8.0), + child: Text('contents'), + ), + ), + node: TimelineNode( + indicator: DotIndicator(), + startConnector: SolidLineConnector(), + endConnector: SolidLineConnector(), + ), + ), + ), + _ComponentRow( + name: 'ConnectionDirection.before', + item: Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: FixedTimeline.tileBuilder( + builder: TimelineTileBuilder.connectedFromStyle( + connectionDirection: ConnectionDirection.before, + connectorStyleBuilder: (context, index) { + return (index == 1) + ? ConnectorStyle.dashedLine + : ConnectorStyle.solidLine; + }, + indicatorStyleBuilder: (context, index) => IndicatorStyle.dot, + itemExtent: 40.0, + itemCount: 3, + ), + ), + ), + ), + _ComponentRow( + name: 'ConnectionDirection.after', + item: Padding( + padding: const EdgeInsets.all(8.0), + child: FixedTimeline.tileBuilder( + builder: TimelineTileBuilder.connectedFromStyle( + connectionDirection: ConnectionDirection.after, + connectorStyleBuilder: (context, index) { + return (index == 1) + ? ConnectorStyle.dashedLine + : ConnectorStyle.solidLine; + }, + indicatorStyleBuilder: (context, index) => IndicatorStyle.dot, + itemExtent: 40.0, + itemCount: 3, + ), + ), + ), + ), + _ComponentRow( + name: 'ContentsAlign.basic', + item: Padding( + padding: const EdgeInsets.all(8.0), + child: FixedTimeline.tileBuilder( + builder: TimelineTileBuilder.connectedFromStyle( + contentsAlign: ContentsAlign.basic, + oppositeContentsBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + contentsBuilder: (context, index) => Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Contents'), + ), + ), + connectorStyleBuilder: (context, index) => + ConnectorStyle.solidLine, + indicatorStyleBuilder: (context, index) => IndicatorStyle.dot, + itemCount: 3, + ), + ), + ), + ), + _ComponentRow( + name: 'ContentsAlign.reverse', + item: Padding( + padding: const EdgeInsets.all(8.0), + child: FixedTimeline.tileBuilder( + builder: TimelineTileBuilder.connectedFromStyle( + contentsAlign: ContentsAlign.reverse, + oppositeContentsBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + contentsBuilder: (context, index) => Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Contents'), + ), + ), + connectorStyleBuilder: (context, index) => + ConnectorStyle.solidLine, + indicatorStyleBuilder: (context, index) => IndicatorStyle.dot, + itemCount: 3, + ), + ), + ), + ), + _ComponentRow( + name: 'ContentsAlign.alternating', + item: FixedTimeline.tileBuilder( + builder: TimelineTileBuilder.connectedFromStyle( + contentsAlign: ContentsAlign.alternating, + oppositeContentsBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + contentsBuilder: (context, index) => Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Contents'), + ), + ), + connectorStyleBuilder: (context, index) => ConnectorStyle.solidLine, + indicatorStyleBuilder: (context, index) => IndicatorStyle.dot, + itemCount: 3, + ), + ), + ), + _ComponentRow( + name: 'Horizontal\nTimeline', + item: SizedBox( + height: 150, + child: Timeline.tileBuilder( + // shrinkWrap: true, + scrollDirection: Axis.horizontal, + builder: TimelineTileBuilder.fromStyle( + contentsBuilder: (context, index) => Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Contents'), + ), + ), + oppositeContentsBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + itemCount: 20, + ), + ), + ), + ), + _ComponentRow( + name: 'Styled node\nHorizontal\nTimeline', + item: SizedBox( + height: 150, + child: Timeline.tileBuilder( + // shrinkWrap: true, + scrollDirection: Axis.horizontal, + builder: TimelineTileBuilder.fromStyle( + contentsBuilder: (context, index) => Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Contents'), + ), + ), + oppositeContentsBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + indicatorStyle: IndicatorStyle.outlined, + connectorStyle: ConnectorStyle.dashedLine, + itemCount: 20, + ), + ), + ), + ), + _ComponentRow( + name: 'Reverse\nHorizontal\nTimeline', + item: SizedBox( + height: 150, + child: Timeline.tileBuilder( + // shrinkWrap: true, + scrollDirection: Axis.horizontal, + builder: TimelineTileBuilder.fromStyle( + contentsBuilder: (context, index) => Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Contents'), + ), + ), + oppositeContentsBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + contentsAlign: ContentsAlign.reverse, + itemCount: 20, + ), + ), + ), + ), + _ComponentRow( + name: 'Alternating\nHorizontal\nTimeline', + item: SizedBox( + height: 150, + child: Timeline.tileBuilder( + // shrinkWrap: true, + scrollDirection: Axis.horizontal, + builder: TimelineTileBuilder.fromStyle( + contentsBuilder: (context, index) => Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Contents'), + ), + ), + oppositeContentsBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + contentsAlign: ContentsAlign.alternating, + itemCount: 20, + ), + ), + ), + ), + _ComponentRow( + name: 'Vertical\nTimeline', + item: SizedBox( + height: 500, + child: Timeline.tileBuilder( + builder: TimelineTileBuilder.fromStyle( + contentsBuilder: (context, index) => Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Contents'), + ), + ), + oppositeContentsBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('opposite\ncontents'), + ), + contentsAlign: ContentsAlign.alternating, + indicatorStyle: IndicatorStyle.outlined, + connectorStyle: ConnectorStyle.dashedLine, + itemCount: 10, + ), + ), + ), + ), + ]; + + return Scaffold( + appBar: TitleAppBar('Components'), + body: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Table( + children: children, + columnWidths: { + 0: FlexColumnWidth(1), + 1: FlexColumnWidth(2), + 2: FlexColumnWidth(0.3), + }, + ), + ), + ); + } +} + +class _ComponentRow extends TableRow { + _ComponentRow({ + @required String name, + @required Widget item, + }) : super( + children: [ + _ComponentName(name), + _ComponentItem(child: item), + ], + ); +} + +class _ComponentItem extends StatelessWidget { + const _ComponentItem({ + Key key, + @required this.child, + }) : super(key: key); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Container( + constraints: BoxConstraints( + minHeight: 65.0, + ), + child: Center( + child: child, + ), + ); + } +} + +class _ComponentName extends StatelessWidget { + const _ComponentName( + this.name, { + Key key, + }) : assert(name.length > 0), + super(key: key); + + final String name; + + @override + Widget build(BuildContext context) { + return _ComponentItem( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Align( + alignment: Alignment.centerLeft, + child: FittedBox( + child: Text(name), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/connector_theme.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/connector_theme.dart new file mode 100644 index 00000000..c8f84749 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/connector_theme.dart @@ -0,0 +1,211 @@ +import 'dart:ui' show lerpDouble; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'connectors.dart'; +import 'timeline_node.dart'; +import 'timeline_theme.dart'; + +/// Defines the visual properties of [SolidLineConnector], connectors inside +/// [TimelineNode]. +/// +/// Descendant widgets obtain the current [ConnectorThemeData] object using +/// `ConnectorTheme.of(context)`. Instances of [ConnectorThemeData] can be +/// customized with [ConnectorThemeData.copyWith]. +/// +/// Typically a [ConnectorThemeData] is specified as part of the overall +/// [TimelineTheme] with [TimelineThemeData.connectorTheme]. +/// +/// All [ConnectorThemeData] properties are `null` by default. When null, the +/// widgets will provide their own defaults. +/// +/// See also: +/// +/// * [TimelineThemeData], which describes the overall theme information for +/// the timeline. +@immutable +class ConnectorThemeData with Diagnosticable { + /// Creates a theme that can be used for [ConnectorTheme] or + /// [TimelineThemeData.connectorTheme]. + const ConnectorThemeData({ + this.color, + this.space, + this.thickness, + this.indent, + }); + + /// The color of [SolidLineConnector]s and connectors inside [TimelineNode]s, + /// and so forth. + final Color color; + + /// This represents the amount of horizontal or vertical space the connector + /// takes up. + final double space; + + /// The thickness of the line drawn within the connector. + final double thickness; + + /// The amount of empty space at the edge of [SolidLineConnector]. + final double indent; + + /// Creates a copy of this object with the given fields replaced with the new + /// values. + ConnectorThemeData copyWith({ + Color color, + double space, + double thickness, + double indent, + }) { + return ConnectorThemeData( + color: color ?? this.color, + space: space ?? this.space, + thickness: thickness ?? this.thickness, + indent: indent ?? this.indent, + ); + } + + /// Linearly interpolate between two Connector themes. + /// + /// The argument `t` must not be null. + /// + /// {@macro dart.ui.shadow.lerp} + static ConnectorThemeData lerp( + ConnectorThemeData a, ConnectorThemeData b, double t) { + return ConnectorThemeData( + color: Color.lerp(a?.color, b?.color, t), + space: lerpDouble(a?.space, b?.space, t), + thickness: lerpDouble(a?.thickness, b?.thickness, t), + indent: lerpDouble(a?.indent, b?.indent, t), + ); + } + + @override + int get hashCode { + return hashValues( + color, + space, + thickness, + indent, + ); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other.runtimeType != runtimeType) return false; + return other is ConnectorThemeData && + other.color == color && + other.space == space && + other.thickness == thickness && + other.indent == indent; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(ColorProperty('color', color, defaultValue: null)) + ..add(DoubleProperty('space', space, defaultValue: null)) + ..add(DoubleProperty('thickness', thickness, defaultValue: null)) + ..add(DoubleProperty('indent', indent, defaultValue: null)); + } +} + +/// An inherited widget that defines the configuration for +/// [SolidLineConnector]s, connectors inside [TimelineNode]s. +class ConnectorTheme extends InheritedTheme { + /// Creates a connector theme that controls the configurations for + /// [SolidLineConnector]s, connectors inside [TimelineNode]s. + const ConnectorTheme({ + Key key, + @required this.data, + @required Widget child, + }) : super(key: key, child: child); + + /// The properties for descendant [SolidLineConnector]s, connectors inside + /// [TimelineNode]s. + final ConnectorThemeData data; + + /// The closest instance of this class's [data] value that encloses the given + /// context. + /// + /// If there is no ancestor, it returns [TimelineThemeData.connectorTheme]. + /// Applications can assume that the returned value will not be null. + /// + /// Typical usage is as follows: + /// + /// ```dart + /// ConnectorThemeData theme = ConnectorTheme.of(context); + /// ``` + static ConnectorThemeData of(BuildContext context) { + final connectorTheme = + context.dependOnInheritedWidgetOfExactType(); + return connectorTheme?.data ?? TimelineTheme.of(context).connectorTheme; + } + + @override + Widget wrap(BuildContext context, Widget child) { + final ancestorTheme = + context.findAncestorWidgetOfExactType(); + return identical(this, ancestorTheme) + ? child + : ConnectorTheme(data: data, child: child); + } + + @override + bool updateShouldNotify(ConnectorTheme oldWidget) => data != oldWidget.data; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + data.debugFillProperties(properties); + } +} + +/// Connector component configured through [ConnectorTheme] +mixin ThemedConnectorComponent on Widget { + /// {@template timelines.connector.direction} + /// If this is null, then the [TimelineThemeData.direction] is used. + /// {@endtemplate} + Axis get direction; + Axis getEffectiveDirection(BuildContext context) { + return direction ?? TimelineTheme.of(context).direction; + } + + /// {@template timelines.connector.thickness} + /// If this is null, then the [ConnectorThemeData.thickness] is used which + /// defaults to 2.0. + /// {@endtemplate} + double get thickness; + double getEffectiveThickness(BuildContext context) { + return thickness ?? ConnectorTheme.of(context).thickness ?? 2.0; + } + + /// {@template timelines.connector.space} + /// If this is null, then the [ConnectorThemeData.space] is used. If that is + /// also null, then this defaults to double.infinity. + /// {@endtemplate} + double get space; + double getEffectiveSpace(BuildContext context) { + return space ?? ConnectorTheme.of(context).space; + } + + double get indent; + double getEffectiveIndent(BuildContext context) { + return indent ?? ConnectorTheme.of(context).indent ?? 0.0; + } + + double get endIndent; + double getEffectiveEndIndent(BuildContext context) { + return endIndent ?? ConnectorTheme.of(context).indent ?? 0.0; + } + + Color get color; + Color getEffectiveColor(BuildContext context) { + return color ?? + ConnectorTheme.of(context).color ?? + TimelineTheme.of(context).color; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/connectors.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/connectors.dart new file mode 100644 index 00000000..aa2ecd35 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/connectors.dart @@ -0,0 +1,452 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'connector_theme.dart'; +import 'line_painter.dart'; +import 'timelines.dart'; +import 'timeline_node.dart'; +import 'timeline_theme.dart'; + +/// Abstract class for predefined connector widgets. +/// +/// See also: +/// +/// * [SolidLineConnector], which is a [Connector] that draws solid line. +/// * [DashedLineConnector], which is a [Connector] that draws outlined dot. +/// * [TransparentConnector], which is a [Connector] that only takes up space. +abstract class Connector extends StatelessWidget with ThemedConnectorComponent { + /// Creates an connector. + const Connector({ + Key key, + this.direction, + this.space, + this.thickness, + this.indent, + this.endIndent, + this.color, + }) : assert(thickness == null || thickness >= 0.0), + assert(space == null || space >= 0.0), + assert(indent == null || indent >= 0.0), + assert(endIndent == null || endIndent >= 0.0), + super(key: key); + + /// Creates a solid line connector. + /// + /// See also: + /// + /// * [SolidLineConnector], exactly the same. + factory Connector.solidLine({ + Key key, + Axis direction, + double thickness, + double space, + double indent, + double endIndent, + Color color, + }) { + return SolidLineConnector( + key: key, + direction: direction, + thickness: thickness, + space: space, + indent: indent, + endIndent: endIndent, + color: color, + ); + } + + /// Creates a dashed line connector. + /// + /// See also: + /// + /// * [DashedLineConnector], exactly the same. + factory Connector.dashedLine({ + Key key, + Axis direction, + double thickness, + double dash, + double gap, + double space, + double indent, + double endIndent, + Color color, + Color gapColor, + }) { + return DashedLineConnector( + key: key, + direction: direction, + thickness: thickness, + dash: dash, + gap: gap, + space: space, + indent: indent, + endIndent: endIndent, + color: color, + gapColor: gapColor, + ); + } + + /// Creates a dashed transparent connector. + /// + /// See also: + /// + /// * [TransparentConnector], exactly the same. + factory Connector.transparent({ + Key key, + Axis direction, + double indent, + double endIndent, + double space, + }) { + return TransparentConnector( + key: key, + direction: direction, + indent: indent, + endIndent: endIndent, + space: space, + ); + } + + /// {@macro timelines.direction} + /// + /// {@macro timelines.connector.direction} + @override + final Axis direction; + + /// The connector's cross axis size extent. + /// + /// The connector itself is always drawn as a line that is centered within the + /// size specified by this value. + /// {@macro timelines.connector.space} + @override + final double space; + + /// The thickness of the line drawn within the connector. + /// + /// {@macro timelines.connector.thickness} + @override + final double thickness; + + /// The amount of empty space to the leading edge of the connector. + /// + /// If this is null, then the [ConnectorThemeData.indent] is used. If that is + /// also null, then this defaults to 0.0. + @override + final double indent; + + /// The amount of empty space to the trailing edge of the connector. + /// + /// If this is null, then the [ConnectorThemeData.indent] is used. If that is + /// also null, then this defaults to 0.0. + @override + final double endIndent; + + /// The color to use when painting the line. + /// + /// If this is null, then the [ConnectorThemeData.color] is used. If that is + /// also null, then [TimelineThemeData.color] is used. + @override + final Color color; +} + +/// A thin line, with padding on either side. +/// +/// The box's total cross axis size(width or height, depend on [direction]) is +/// controlled by [space]. +/// +/// The appropriate padding is automatically computed from the cross axis size. +class SolidLineConnector extends Connector { + /// Creates a solid line connector. + /// + /// The [thickness], [space], [indent], and [endIndent] must be null or + /// non-negative. + const SolidLineConnector({ + Key key, + Axis direction, + double thickness, + double space, + double indent, + double endIndent, + Color color, + }) : super( + key: key, + thickness: thickness, + space: space, + indent: indent, + endIndent: endIndent, + color: color, + ); + + @override + Widget build(BuildContext context) { + final direction = getEffectiveDirection(context); + final thickness = getEffectiveThickness(context); + final color = getEffectiveColor(context); + final space = getEffectiveSpace(context); + final indent = getEffectiveIndent(context); + final endIndent = getEffectiveEndIndent(context); + + switch (direction) { + case Axis.vertical: + return _ConnectorIndent( + direction: direction, + indent: indent, + endIndent: endIndent, + space: space, + child: Container( + width: thickness, + color: color, + ), + ); + case Axis.horizontal: + return _ConnectorIndent( + direction: direction, + indent: indent, + endIndent: endIndent, + space: space, + child: Container( + height: thickness, + color: color, + ), + ); + } + } +} + +/// A decorated thin line, with padding on either side. +/// +/// The box's total cross axis size(width or height, depend on [direction]) is +/// controlled by [space]. +/// +/// The appropriate padding is automatically computed from the cross axis size. +class DecoratedLineConnector extends Connector { + /// Creates a decorated line connector. + /// + /// The [thickness], [space], [indent], and [endIndent] must be null or + /// non-negative. + const DecoratedLineConnector({ + Key key, + Axis direction, + double thickness, + double space, + double indent, + double endIndent, + this.decoration, + }) : super( + key: key, + thickness: thickness, + space: space, + indent: indent, + endIndent: endIndent, + ); + + /// The decoration to paint line. + /// + /// Use the [SolidLineConnector] class to specify a simple solid color line. + final Decoration decoration; + + @override + Widget build(BuildContext context) { + final direction = getEffectiveDirection(context); + final thickness = getEffectiveThickness(context); + final space = getEffectiveSpace(context); + final indent = getEffectiveIndent(context); + final endIndent = getEffectiveEndIndent(context); + final color = decoration == null ? getEffectiveColor(context) : null; + + switch (direction) { + case Axis.vertical: + return _ConnectorIndent( + direction: direction, + indent: indent, + endIndent: endIndent, + space: space, + child: Container( + width: thickness, + color: color, + decoration: decoration, + ), + ); + case Axis.horizontal: + return _ConnectorIndent( + direction: direction, + indent: indent, + endIndent: endIndent, + space: space, + child: Container( + height: thickness, + color: color, + decoration: decoration, + ), + ); + } + } +} + +/// A thin dashed line, with padding on either side. +/// +/// The box's total cross axis size(width or height, depend on [direction]) is +/// controlled by [space]. +/// +/// The appropriate padding is automatically computed from the cross axis size. +/// +/// See also: +/// +/// * [DashedLinePainter], which is painter that draws this connector. +class DashedLineConnector extends Connector { + /// Creates a dashed line connector. + /// + /// The [thickness], [space], [indent], and [endIndent] must be null or + /// non-negative. + const DashedLineConnector({ + Key key, + Axis direction, + double thickness, + this.dash, + this.gap, + double space, + double indent, + double endIndent, + Color color, + this.gapColor, + }) : super( + key: key, + direction: direction, + thickness: thickness, + space: space, + indent: indent, + endIndent: endIndent, + color: color, + ); + + /// The dash size of the line drawn within the connector. + /// + /// If this is null, then this defaults to 1.0. + final double dash; + + /// The gap of the line drawn within the connector. + /// + /// If this is null, then this defaults to 1.0. + final double gap; + + /// The color to use when painting the gap in the line. + /// + /// If this is null, then the [Colors.transparent] is used. + final Color gapColor; + + @override + Widget build(BuildContext context) { + final direction = getEffectiveDirection(context); + return _ConnectorIndent( + direction: direction, + indent: getEffectiveIndent(context), + endIndent: getEffectiveEndIndent(context), + space: getEffectiveSpace(context), + child: CustomPaint( + painter: DashedLinePainter( + direction: direction, + color: getEffectiveColor(context), + strokeWidth: getEffectiveThickness(context), + dashSize: dash ?? 1.0, + gapSize: gap ?? 1.0, + gapColor: gapColor ?? Colors.transparent, + ), + child: Container(), + ), + ); + } +} + +/// A transparent connector for start, end [TimelineNode] of the [Timeline]. +/// +/// This connector will be not displayed, it only occupies an area. +class TransparentConnector extends Connector { + /// Creates a transparent connector. + /// + /// The [space], [indent], and [endIndent] must be null or non-negative. + const TransparentConnector({ + Key key, + Axis direction, + double indent, + double endIndent, + double space, + }) : super( + key: key, + direction: direction, + indent: indent, + endIndent: endIndent, + space: space, + ); + + @override + Widget build(BuildContext context) { + return _ConnectorIndent( + direction: getEffectiveDirection(context), + indent: getEffectiveIndent(context), + endIndent: getEffectiveEndIndent(context), + space: getEffectiveSpace(context), + child: Container(), + ); + } +} + +/// Apply indent to [child]. +class _ConnectorIndent extends StatelessWidget { + /// Creates a indent. + /// + /// The [direction]and [child] must be null. And [space], [indent] and + /// [endIndent] must be null or non-negative. + const _ConnectorIndent({ + Key key, + @required this.direction, + @required this.space, + this.indent, + this.endIndent, + @required this.child, + }) : assert(space == null || space >= 0), + assert(indent == null || indent >= 0), + assert(endIndent == null || endIndent >= 0), + super(key: key); + + /// {@macro timelines.direction} + final Axis direction; + + /// The connector's cross axis size extent. + /// + /// The connector itself is always drawn as a line that is centered within the + /// size specified by this value. + final double space; + + /// The amount of empty space to the leading edge of the connector. + final double indent; + + /// The amount of empty space to the trailing edge of the connector. + final double endIndent; + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.child} + final Widget child; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: direction == Axis.vertical ? space : null, + height: direction == Axis.vertical ? null : space, + child: Center( + child: Padding( + padding: direction == Axis.vertical + ? EdgeInsetsDirectional.only( + top: indent ?? 0, + bottom: endIndent ?? 0, + ) + : EdgeInsetsDirectional.only( + start: indent ?? 0, + end: endIndent ?? 0, + ), + child: child, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/indicator_theme.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/indicator_theme.dart new file mode 100644 index 00000000..30802a78 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/indicator_theme.dart @@ -0,0 +1,180 @@ +import 'dart:ui' show lerpDouble; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'indicators.dart'; +import 'timeline_node.dart'; +import 'timeline_theme.dart'; + +/// Defines the visual properties of [DotIndicator], indicators inside +/// [TimelineNode]s. +/// +/// Descendant widgets obtain the current [IndicatorThemeData] object using +/// `IndicatorTheme.of(context)`. Instances of [IndicatorThemeData] can be +/// customized with [IndicatorThemeData.copyWith]. +/// +/// Typically a [IndicatorThemeData] is specified as part of the overall +/// [TimelineTheme] with [TimelineThemeData.indicatorTheme]. +/// +/// All [IndicatorThemeData] properties are `null` by default. When null, the +/// widgets will provide their own defaults. +/// +/// See also: +/// +/// * [TimelineThemeData], which describes the overall theme information for +/// the timeline. +@immutable +class IndicatorThemeData with Diagnosticable { + /// Creates a theme that can be used for [IndicatorTheme] or + /// [TimelineThemeData.indicatorTheme]. + const IndicatorThemeData({ + this.color, + this.size, + this.position, + }); + + /// The color of [DotIndicator]s and indicators inside [TimelineNode]s, and so + /// forth. + final Color color; + + /// The size of [DotIndicator]s and indicators inside [TimelineNode]s, and so + /// forth in logical pixels. + /// + /// Indicators occupy a square with width and height equal to size. + final double size; + + /// A position of indicator inside both two connectors. + final double position; + + /// Creates a copy of this object with the given fields replaced with the new + /// values. + IndicatorThemeData copyWith({ + Color color, + double size, + double position, + }) { + return IndicatorThemeData( + color: color ?? this.color, + size: size ?? this.size, + position: position ?? this.position, + ); + } + + /// Linearly interpolate between two Indicator themes. + /// + /// The argument `t` must not be null. + /// + /// {@macro dart.ui.shadow.lerp} + static IndicatorThemeData lerp( + IndicatorThemeData a, IndicatorThemeData b, double t) { + return IndicatorThemeData( + color: Color.lerp(a?.color, b?.color, t), + size: lerpDouble(a?.size, b?.size, t), + position: lerpDouble(a?.position, b?.position, t), + ); + } + + @override + int get hashCode => hashValues(color, size, position); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other.runtimeType != runtimeType) return false; + return other is IndicatorThemeData && + other.color == color && + other.size == size && + other.position == position; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(ColorProperty('color', color, defaultValue: null)) + ..add(DoubleProperty('size', size, defaultValue: null)) + ..add(DoubleProperty('position', size, defaultValue: null)); + } +} + +/// Controls the default color and size of indicators in a widget subtree. +/// +/// The indicator theme is honored by [TimelineNode], [DotIndicator] and +/// [OutlinedDotIndicator] widgets. +class IndicatorTheme extends InheritedTheme { + /// Creates an indicator theme that controls the color and size for + /// [DotIndicator]s, indicators inside [TimelineNode]s. + const IndicatorTheme({ + Key key, + @required this.data, + @required Widget child, + }) : super(key: key, child: child); + + /// The properties for descendant [DotIndicator]s, indicators inside + /// [TimelineNode]s. + final IndicatorThemeData data; + + /// The data from the closest instance of this class that encloses the given + /// context. + /// + /// Defaults to the current [TimelineThemeData.indicatorTheme]. + /// + /// Typical usage is as follows: + /// + /// ```dart + /// IndicatorThemeData theme = IndicatorTheme.of(context); + /// ``` + static IndicatorThemeData of(BuildContext context) { + final indicatorTheme = + context.dependOnInheritedWidgetOfExactType(); + return indicatorTheme?.data ?? TimelineTheme.of(context).indicatorTheme; + } + + @override + Widget wrap(BuildContext context, Widget child) { + final ancestorTheme = + context.findAncestorWidgetOfExactType(); + return identical(this, ancestorTheme) + ? child + : IndicatorTheme(data: data, child: child); + } + + @override + bool updateShouldNotify(IndicatorTheme oldWidget) => data != oldWidget.data; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + data.debugFillProperties(properties); + } +} + +/// Indicator component configured through [IndicatorTheme] +mixin ThemedIndicatorComponent on PositionedIndicator { + /// {@template timelines.indicator.color} + /// Defaults to the current [IndicatorTheme] color, if any. + /// + /// If no [IndicatorTheme] and no [TimelineTheme] is specified, indicators + /// will default to blue. + /// {@endtemplate} + Color get color; + Color getEffectiveColor(BuildContext context) { + return color ?? + IndicatorTheme.of(context).color ?? + TimelineTheme.of(context).color; + } + + /// {@template timelines.indicator.size} + /// Indicators occupy a square with width and height equal to size. + /// + /// Defaults to the current [IndicatorTheme] size, if any. If there is no + /// [IndicatorTheme], or it does not specify an explicit size, then it + /// defaults to own child size(0.0). + /// {@endtemplate} + double get size; + double getEffectiveSize(BuildContext context) { + return size ?? IndicatorTheme.of(context).size; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/indicators.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/indicators.dart new file mode 100644 index 00000000..ba98ebeb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/indicators.dart @@ -0,0 +1,270 @@ +import 'package:flutter/material.dart'; + +import 'indicator_theme.dart'; +import 'timeline_theme.dart'; + +/// [TimelineNode]'s indicator. +mixin PositionedIndicator on Widget { + /// {@template timelines.indicator.position} + /// If this is null, then the [IndicatorThemeData.position] is used. If that + /// is also null, then this defaults to [TimelineThemeData.indicatorPosition]. + /// {@endtemplate} + double get position; + double getEffectivePosition(BuildContext context) { + return position ?? + IndicatorTheme.of(context).position ?? + TimelineTheme.of(context).indicatorPosition; + } +} + +/// Abstract class for predefined indicator widgets. +/// +/// See also: +/// +/// * [DotIndicator], which is a [Indicator] that draws dot. +/// * [OutlinedDotIndicator], which is a [Indicator] that draws outlined dot. +/// * [ContainerIndicator], which is a [Indicator] that draws it's child. +abstract class Indicator extends StatelessWidget + with PositionedIndicator, ThemedIndicatorComponent { + /// Creates an indicator. + const Indicator({ + Key key, + this.size, + this.color, + this.border, + this.position, + this.child, + }) : assert(size == null || size >= 0), + assert(position == null || 0 <= position && position <= 1), + super(key: key); + + /// Creates a dot indicator. + /// + /// See also: + /// + /// * [DotIndicator], exactly the same. + factory Indicator.dot({ + Key key, + double size, + Color color, + double position, + Border border, + Widget child, + }) => + DotIndicator( + size: size, + color: color, + position: position, + border: border, + child: child, + ); + + /// Creates a outlined dot indicator. + /// + /// See also: + /// + /// * [OutlinedDotIndicator], exactly the same. + factory Indicator.outlined({ + Key key, + double size, + Color color, + Color backgroundColor, + double position, + double borderWidth = 2.0, + Widget child, + }) => + OutlinedDotIndicator( + size: size, + color: color, + position: position, + backgroundColor: backgroundColor, + borderWidth: borderWidth, + child: child, + ); + + /// Creates a transparent indicator. + /// + /// See also: + /// + /// * [ContainerIndicator], this is created without child. + factory Indicator.transparent({ + Key key, + double size, + double position, + }) => + ContainerIndicator( + size: size, + position: position, + ); + + /// Creates a widget indicator. + /// + /// See also: + /// + /// * [OutlinedDotIndicator], exactly the same. + factory Indicator.widget({ + Key key, + double size, + double position, + Widget child, + }) => + ContainerIndicator( + size: size, + position: position, + child: child, + ); + + /// The size of the dot in logical pixels. + /// + /// {@macro timelines.indicator.size} + @override + final double size; + + /// The color to use when drawing the dot. + /// + /// {@macro timelines.indicator.color} + @override + final Color color; + + /// The position of a indicator between the two connectors. + /// + /// {@macro timelines.indicator.position} + @override + final double position; + + /// The border to use when drawing the dot's outline. + final BoxBorder border; + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.child} + final Widget child; +} + +/// A widget that displays an [child]. The [child] if null, the indicator is not +/// visible. +class ContainerIndicator extends Indicator { + /// Creates a container indicator. + const ContainerIndicator({ + Key key, + double size, + double position, + this.child, + }) : super( + key: key, + size: size, + position: position, + color: Colors.transparent, + ); + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.child} + final Widget child; + + @override + Widget build(BuildContext context) { + final size = getEffectiveSize(context); + return Container( + width: size, + height: size, + child: child, + ); + } +} + +/// A widget that displays an dot. +class DotIndicator extends Indicator { + /// Creates a dot indicator. + /// + /// The [size] must be null or non-negative. + const DotIndicator({ + Key key, + double size, + Color color, + double position, + this.border, + this.child, + }) : super( + key: key, + size: size, + color: color, + position: position, + ); + + /// The border to use when drawing the dot's outline. + final BoxBorder border; + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.child} + final Widget child; + + @override + Widget build(BuildContext context) { + final effectiveSize = getEffectiveSize(context); + final effectiveColor = getEffectiveColor(context); + return Center( + child: Container( + width: effectiveSize ?? ((child == null) ? 15.0 : null), + height: effectiveSize ?? ((child == null) ? 15.0 : null), + child: child, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: effectiveColor, + border: border, + ), + ), + ); + } +} + +/// A widget that displays an outlined dot. +class OutlinedDotIndicator extends Indicator { + /// Creates a outlined dot indicator. + /// + /// The [size] must be null or non-negative. + const OutlinedDotIndicator({ + Key key, + double size, + Color color, + double position, + this.backgroundColor, + this.borderWidth = 2.0, + this.child, + }) : assert(size == null || size >= 0), + assert(position == null || 0 <= position && position <= 1), + super( + key: key, + size: size, + color: color, + position: position, + ); + + /// The color to use when drawing the dot in outline. + /// + /// {@macro timelines.indicator.color} + final Color backgroundColor; + + /// The width of this outline, in logical pixels. + final double borderWidth; + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.child} + final Widget child; + + @override + Widget build(BuildContext context) { + return DotIndicator( + size: size, + color: backgroundColor ?? Colors.transparent, + position: position, + border: Border.all( + color: color ?? getEffectiveColor(context), + width: borderWidth, + ), + child: child, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/line_painter.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/line_painter.dart new file mode 100644 index 00000000..96f2c743 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/line_painter.dart @@ -0,0 +1,215 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import 'connectors.dart'; + +/// Paints a [DashedLineConnector]. +/// +/// Draw the line like this: +/// ``` +/// 0 > [dash][gap][dash][gap] < constraints size +/// ``` +/// +/// [dashSize] specifies the size of [dash]. and [gapSize] specifies the size of +/// [gap]. +/// +/// When using the default colors, this painter draws a dotted line or dashed +/// line that familiar. +/// If set other [gapColor], this painter draws a line that alternates between +/// two colors. +class DashedLinePainter extends CustomPainter { + /// Creates a dashed line painter. + /// + /// The [dashSize] argument must be 1 or more, and the [gapSize] and + /// [strokeWidth] arguments must be positive numbers. + /// + /// The [direction], [color], [gapColor] and [strokeCap] arguments must not be + /// null. + const DashedLinePainter({ + @required this.direction, + @required this.color, + this.gapColor = Colors.transparent, + this.dashSize = 1.0, + this.gapSize = 1.0, + this.strokeWidth = 1.0, + this.strokeCap = StrokeCap.square, + }) : assert(dashSize >= 1), + assert(gapSize >= 0), + assert(strokeWidth >= 0); + + /// {@macro timelines.direction} + final Axis direction; + + /// The color to paint dash of line. + final Color color; + + /// The color to paint gap(another dash) of line. + final Color gapColor; + + /// The size of dash + final double dashSize; + + /// The size of gap, it also draws [gapColor] + final double gapSize; + + /// The stroke width of dash and gap. + final double strokeWidth; + + /// Styles to use for line endings. + final StrokeCap strokeCap; + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..strokeWidth = strokeWidth + ..strokeCap = strokeCap + ..style = PaintingStyle.stroke; + + var offset = _DashOffset( + containerSize: size, + strokeWidth: strokeWidth, + dashSize: dashSize, + gapSize: gapSize, + axis: direction, + ); + + while (offset.hasNext) { + // draw dash + paint.color = color; + canvas.drawLine( + offset, + offset.translateDashSize(), + paint, + ); + offset = offset.translateDashSize(); + + // draw gap + if (gapColor != Colors.transparent) { + paint.color = gapColor; + canvas.drawLine( + offset, + offset.translateGapSize(), + paint, + ); + } + offset = offset.translateGapSize(); + } + } + + @override + bool shouldRepaint(DashedLinePainter oldDelegate) { + return direction != oldDelegate.direction || + color != oldDelegate.color || + gapColor != oldDelegate.gapColor || + dashSize != oldDelegate.dashSize || + gapSize != oldDelegate.gapSize || + strokeWidth != oldDelegate.strokeWidth || + strokeCap != oldDelegate.strokeCap; + } +} + +class _DashOffset extends Offset { + factory _DashOffset({ + @required Size containerSize, + @required double strokeWidth, + @required double dashSize, + @required double gapSize, + @required Axis axis, + }) { + return _DashOffset._( + dx: axis == Axis.vertical ? containerSize.width / 2 : 0, + dy: axis == Axis.vertical ? 0 : containerSize.height / 2, + strokeWidth: strokeWidth, + containerSize: containerSize, + dashSize: dashSize, + gapSize: gapSize, + axis: axis, + ); + } + + const _DashOffset._({ + @required double dx, + @required double dy, + @required this.strokeWidth, + @required this.containerSize, + @required this.dashSize, + @required this.gapSize, + @required this.axis, + }) : super(dx, dy); + + final Size containerSize; + final double strokeWidth; + final double dashSize; + final double gapSize; + final Axis axis; + + double get offset { + if (axis == Axis.vertical) { + return dy; + } else { + return dx; + } + } + + bool get hasNext { + if (axis == Axis.vertical) { + return offset < containerSize.height; + } else { + return offset < containerSize.width; + } + } + + _DashOffset translateDashSize() { + return _translateDirectionally(dashSize); + } + + _DashOffset translateGapSize() { + return _translateDirectionally(gapSize + strokeWidth); + } + + _DashOffset _translateDirectionally(double offset) { + if (axis == Axis.vertical) { + return translate(0, offset) as _DashOffset; + } else { + return translate(offset, 0) as _DashOffset; + } + } + + @override + Offset translate(double translateX, double translateY) { + double dx, dy; + if (axis == Axis.vertical) { + dx = this.dx; + dy = this.dy + translateY; + } else { + dx = this.dx + translateX; + dy = this.dy; + } + return copyWith( + dx: min(dx, containerSize.width), + dy: min(dy, containerSize.height), + ); + } + + _DashOffset copyWith({ + double dx, + double dy, + Size containerSize, + double strokeWidth, + double dashSize, + double gapSize, + Axis axis, + }) { + return _DashOffset._( + dx: dx ?? this.dx, + dy: dy ?? this.dy, + containerSize: containerSize ?? this.containerSize, + strokeWidth: strokeWidth ?? this.strokeWidth, + dashSize: dashSize ?? this.dashSize, + gapSize: gapSize ?? this.gapSize, + axis: axis ?? this.axis, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_node.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_node.dart new file mode 100644 index 00000000..2441a3b8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_node.dart @@ -0,0 +1,218 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +import 'connectors.dart'; +import 'indicators.dart'; +import 'timeline_theme.dart'; +import 'util.dart'; + +/// [TimelineTile]'s timeline node +mixin TimelineTileNode on Widget { + /// {@template timelines.node.position} + /// If this is null, then the [TimelineThemeData.nodePosition] is used. + /// {@endtemplate} + double get position; + double getEffectivePosition(BuildContext context) { + return position ?? TimelineTheme.of(context).nodePosition; + } +} + +/// A widget that displays indicator and two connectors. +/// +/// The [indicator] displayed between the [startConnector] and [endConnector] +class TimelineNode extends StatelessWidget with TimelineTileNode { + /// Creates a timeline node. + /// + /// The [indicatorPosition] must be null or a value between 0 and 1. + const TimelineNode({ + Key key, + this.direction, + this.startConnector, + this.endConnector, + this.indicator = const ContainerIndicator(), + this.indicatorPosition, + this.position, + this.overlap, + }) : assert(indicatorPosition == null || + 0 <= indicatorPosition && indicatorPosition <= 1), + super(key: key); + + /// Creates a timeline node that connects the dot indicator in a solid line. + TimelineNode.simple({ + Key key, + Axis direction, + Color color, + double lineThickness, + double nodePosition, + double indicatorPosition, + double indicatorSize, + Widget indicatorChild, + double indent, + double endIndent, + bool drawStartConnector = true, + bool drawEndConnector = true, + bool overlap, + }) : this( + key: key, + direction: direction, + startConnector: drawStartConnector + ? SolidLineConnector( + direction: direction, + color: color, + thickness: lineThickness, + indent: indent, + endIndent: endIndent, + ) + : null, + endConnector: drawEndConnector + ? SolidLineConnector( + direction: direction, + color: color, + thickness: lineThickness, + indent: indent, + endIndent: endIndent, + ) + : null, + indicator: DotIndicator( + child: indicatorChild, + position: indicatorPosition, + size: indicatorSize, + color: color, + ), + indicatorPosition: indicatorPosition, + position: nodePosition, + overlap: overlap, + ); + + /// {@macro timelines.direction} + final Axis direction; + + /// The connector of the start edge of this node + final Widget startConnector; + + /// The connector of the end edge of this node + final Widget endConnector; + + /// The indicator of the node + final Widget indicator; + + /// The position of a indicator between the two connectors. + /// + /// {@macro timelines.indicator.position} + final double indicatorPosition; + + /// A position of timeline node between both two contents. + /// + /// {@macro timelines.node.position} + @override + final double position; + + /// Determine whether each connectors and indicator will overlap. + /// + /// When each connectors overlap, they are drawn from the center offset of the + /// indicator. + final bool overlap; + + double _getEffectiveIndicatorPosition(BuildContext context) { + var indicatorPosition = this.indicatorPosition; + indicatorPosition ??= (indicator is PositionedIndicator) + ? (indicator as PositionedIndicator).getEffectivePosition(context) + : TimelineTheme.of(context).indicatorPosition; + return indicatorPosition; + } + + bool _getEffectiveOverlap(BuildContext context) { + var overlap = this.overlap ?? TimelineTheme.of(context).nodeItemOverlap; + return overlap; + } + + @override + Widget build(BuildContext context) { + final direction = this.direction ?? TimelineTheme.of(context).direction; + final overlap = _getEffectiveOverlap(context); + // double: support both flex and logical pixel + final indicatorFlex = _getEffectiveIndicatorPosition(context); + Widget line = indicator; + final lineItems = [ + if (indicatorFlex > 0) + Flexible( + flex: (indicatorFlex * kFlexMultiplier).toInt(), + child: startConnector ?? TransparentConnector(), + ), + if (!overlap) indicator, + if (indicatorFlex < 1) + Flexible( + flex: ((1 - indicatorFlex) * kFlexMultiplier).toInt(), + child: endConnector ?? TransparentConnector(), + ), + ]; + + switch (direction) { + case Axis.vertical: + line = Column( + mainAxisSize: MainAxisSize.min, + children: lineItems, + ); + break; + case Axis.horizontal: + line = Row( + mainAxisSize: MainAxisSize.min, + children: lineItems, + ); + break; + } + + Widget result; + if (overlap) { + Widget positionedIndicator = indicator; + final positionedIndicatorItems = [ + if (indicatorFlex > 0) + Flexible( + flex: (indicatorFlex * kFlexMultiplier).toInt(), + child: TransparentConnector(), + ), + indicator, + Flexible( + flex: ((1 - indicatorFlex) * kFlexMultiplier).toInt(), + child: TransparentConnector(), + ), + ]; + + switch (direction) { + case Axis.vertical: + positionedIndicator = Column( + mainAxisSize: MainAxisSize.min, + children: positionedIndicatorItems, + ); + break; + case Axis.horizontal: + positionedIndicator = Row( + mainAxisSize: MainAxisSize.min, + children: positionedIndicatorItems, + ); + break; + } + + result = Stack( + alignment: Alignment.center, + children: [ + line, + positionedIndicator, + ], + ); + } else { + result = line; + } + + if (TimelineTheme.of(context).direction != direction) { + result = TimelineTheme( + data: TimelineTheme.of(context).copyWith( + direction: direction, + ), + child: result, + ); + } + + return result; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_theme.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_theme.dart new file mode 100644 index 00000000..d0b16ab9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_theme.dart @@ -0,0 +1,378 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'connector_theme.dart'; +import 'indicator_theme.dart'; +import 'timelines.dart'; + +/// Applies a theme to descendant timeline widgets. +/// +/// A theme describes the colors and typographic choices of an application. +/// +/// Descendant widgets obtain the current theme's [TimelineThemeData] object +/// using [TimelineTheme.of]. When a widget uses [TimelineTheme.of], it is +/// automatically rebuilt if the theme later changes, so that the changes can be +/// applied. +/// +/// See also: +/// +/// * [TimelineThemeData], which describes the actual configuration of a theme. +class TimelineTheme extends StatelessWidget { + /// Applies the given theme [data] to [child]. + /// + /// The [data] and [child] arguments must not be null. + const TimelineTheme({ + Key key, + @required this.data, + @required this.child, + }) : super(key: key); + + /// Specifies the direction for descendant widgets. + final TimelineThemeData data; + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.child} + final Widget child; + + static final TimelineThemeData _kFallbackTheme = TimelineThemeData.fallback(); + + /// The data from the closest [TimelineTheme] instance that encloses the given + /// context. + /// + /// Defaults to [new ThemeData.fallback] if there is no [Theme] in the given + /// build context. + /// + /// When the [TimelineTheme] is actually created in the same `build` function + /// (possibly indirectly, e.g. as part of a [Timeline]), the `context` + /// argument to the `build` function can't be used to find the [TimelineTheme] + /// (since it's "above" the widget being returned). In such cases, the + /// following technique with a [Builder] can be used to provide a new scope + /// with a [BuildContext] that is "under" the [TimelineTheme]: + /// + /// ```dart + /// @override + /// Widget build(BuildContext context) { + /// // double: replace to Timeline + /// return TimelineTheme( + /// data: TimelineThemeData.vertical(), + /// child: Builder( + /// // Create an inner BuildContext so that we can refer to the Theme with TimelineTheme.of(). + /// builder: (BuildContext context) { + /// return Center( + /// child: TimelineNode( + /// direction: TimelineTheme.of(context).direction, + /// child: Text('Example'), + /// ), + /// ); + /// }, + /// ), + /// ); + /// } + /// ``` + static TimelineThemeData of(BuildContext context) { + final inheritedTheme = + context.dependOnInheritedWidgetOfExactType<_InheritedTheme>(); + return inheritedTheme?.theme?.data ?? _kFallbackTheme; + } + + @override + Widget build(BuildContext context) { + return _InheritedTheme( + theme: this, + child: IndicatorTheme( + data: data.indicatorTheme, + child: child, + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add( + DiagnosticsProperty('data', data, showName: false)); + } +} + +class _InheritedTheme extends InheritedTheme { + const _InheritedTheme({ + Key key, + @required this.theme, + @required Widget child, + }) : super(key: key, child: child); + + final TimelineTheme theme; + + @override + Widget wrap(BuildContext context, Widget child) { + final ancestorTheme = + context.findAncestorWidgetOfExactType<_InheritedTheme>(); + return identical(this, ancestorTheme) + ? child + : TimelineTheme(data: theme.data, child: child); + } + + @override + bool updateShouldNotify(_InheritedTheme old) => theme.data != old.theme.data; +} + +/// Defines the configuration of the overall visual [TimelineTheme] for a +/// [Timeline] or a widget subtree within the app. +/// +/// The [Timeline] theme property can be used to configure the appearance of the +/// entire timeline. Widget subtree's within an timeline can override the +/// timeline's theme by including a [TimelineTheme] widget at the top of the +/// subtree. +/// +/// Widgets whose appearance should align with the overall theme can obtain the +/// current theme's configuration with [TimelineTheme.of]. +/// +/// The static [TimelineTheme.of] method finds the [TimelineThemeData] value +/// specified for the nearest [BuildContext] ancestor. This lookup is +/// inexpensive, essentially just a single HashMap access. It can sometimes be a +/// little confusing because [TimelineTheme.of] can not see a [TimelineTheme] +/// widget that is defined in the current build method's context. To overcome +/// that, create a new custom widget for the subtree that appears below the new +/// [TimelineTheme], or insert a widget that creates a new BuildContext, like +/// [Builder]. +/// +/// {@tool snippet} +/// In this example, the [Container] widget uses [Theme.of] to retrieve the +/// color from the theme's [color] to draw an amber square. +/// The [Builder] widget separates the parent theme's [BuildContext] from the +/// child's [BuildContext]. +/// +/// ![](https://flutter.github.io/assets-for-api-docs/assets/material/theme_data.png) +/// +/// ```dart +/// TimelineTheme( +/// data: TimelineThemeData( +/// color: Colors.red, +/// ), +/// child: Builder( +/// builder: (BuildContext context) { +/// return Container( +/// width: 100, +/// height: 100, +/// color: TimelineTheme.of(context).color, +/// ); +/// }, +/// ), +/// ) +/// ``` +/// {@end-tool} +/// +/// {@tool snippet} +@immutable +class TimelineThemeData with Diagnosticable { + /// Create a [TimelineThemeData] that's used to configure a [TimelineTheme]. + /// + /// See also: + /// + /// * [TimelineThemeData.vertical], which creates a vertical direction + /// TimelineThemeData. + /// * [TimelineThemeData.horizontal], which creates a horizontal direction + /// TimelineThemeData. + factory TimelineThemeData({ + Axis direction, + Color color, + double nodePosition, + bool nodeItemOverlap, + double indicatorPosition, + IndicatorThemeData indicatorTheme, + ConnectorThemeData connectorTheme, + }) { + direction ??= Axis.vertical; + color ??= Colors + .blue; // double: Need to change the default color to the theme color? + nodePosition ??= 0.5; + nodeItemOverlap ??= false; + indicatorPosition ??= 0.5; + indicatorTheme ??= IndicatorThemeData(); + connectorTheme ??= ConnectorThemeData(); + return TimelineThemeData.raw( + direction: direction, + color: color, + nodePosition: nodePosition, + nodeItemOverlap: nodeItemOverlap, + indicatorPosition: indicatorPosition, + indicatorTheme: indicatorTheme, + connectorTheme: connectorTheme, + ); + } + + /// The default direction theme. Same as [new TimelineThemeData.vertical]. + /// + /// This is used by [TimelineTheme.of] when no theme has been specified. + factory TimelineThemeData.fallback() => TimelineThemeData.vertical(); + + /// Create a [TimelineThemeData] given a set of exact values. All the values + /// must be specified. They all must also be non-null. + /// + /// This will rarely be used directly. It is used by [lerp] to create + /// intermediate themes based on two themes created with the + /// [new TimelineThemeData] constructor. + const TimelineThemeData.raw({ + @required this.direction, + @required this.color, + @required this.nodePosition, + @required this.nodeItemOverlap, + @required this.indicatorPosition, + @required this.indicatorTheme, + @required this.connectorTheme, + }); + + /// A default vertical theme. + factory TimelineThemeData.vertical() => TimelineThemeData( + direction: Axis.vertical, + ); + + /// A default horizontal theme. + factory TimelineThemeData.horizontal() => TimelineThemeData( + direction: Axis.horizontal, + ); + + /// {@macro timelines.direction} + final Axis direction; + + /// The color for major parts of the timeline (indicator, connector, etc) + final Color color; + + /// The position for [TimelineNode] in [TimelineTile]. + /// + /// Defaults to 0.5. + final double nodePosition; + + /// Determine whether each connectors and indicator will overlap in + /// [TimelineNode]. + /// + /// When each connectors overlap, they are drawn from the center offset of the + /// indicator. + final bool nodeItemOverlap; + + /// The position for indicator in [TimelineNode]. + /// + /// Defaults to 0.5. + final double indicatorPosition; + + /// A theme for customizing the appearance and layout of + /// [ThemedIndicatorComponent] widgets. + final IndicatorThemeData indicatorTheme; + + /// A theme for customizing the appearance and layout of + /// [ThemedConnectorComponent] widgets. + final ConnectorThemeData connectorTheme; + + /// Creates a copy of this theme but with the given fields replaced with the + /// new values. + TimelineThemeData copyWith({ + Axis direction, + Color color, + double nodePosition, + bool nodeItemOverlap, + double indicatorPosition, + IndicatorThemeData indicatorTheme, + ConnectorThemeData connectorTheme, + }) { + return TimelineThemeData.raw( + direction: direction ?? this.direction, + color: color ?? this.color, + nodePosition: nodePosition ?? this.nodePosition, + nodeItemOverlap: nodeItemOverlap ?? this.nodeItemOverlap, + indicatorPosition: indicatorPosition ?? this.indicatorPosition, + indicatorTheme: indicatorTheme ?? this.indicatorTheme, + connectorTheme: connectorTheme ?? this.connectorTheme, + ); + } + + /// Linearly interpolate between two themes. + /// + /// The arguments must not be null. + /// + /// {@macro dart.ui.shadow.lerp} + static TimelineThemeData lerp( + TimelineThemeData a, TimelineThemeData b, double t) { + // Warning: make sure these properties are in the exact same order as in + // hashValues() and in the raw constructor and in the order of fields in + // the class and in the lerp() method. + return TimelineThemeData.raw( + direction: t < 0.5 ? a.direction : b.direction, + color: Color.lerp(a.color, b.color, t), + nodePosition: lerpDouble(a.nodePosition, b.nodePosition, t), + nodeItemOverlap: t < 0.5 ? a.nodeItemOverlap : b.nodeItemOverlap, + indicatorPosition: + lerpDouble(a.indicatorPosition, b.indicatorPosition, t), + indicatorTheme: + IndicatorThemeData.lerp(a.indicatorTheme, b.indicatorTheme, t), + connectorTheme: + ConnectorThemeData.lerp(a.connectorTheme, b.connectorTheme, t), + ); + } + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) return false; + // Warning: make sure these properties are in the exact same order as in + // hashValues() and in the raw constructor and in the order of fields in + // the class and in the lerp() method. + return other is TimelineThemeData && + other.direction == direction && + other.color == color && + other.nodePosition == nodePosition && + other.nodeItemOverlap == nodeItemOverlap && + other.indicatorPosition == indicatorPosition && + other.indicatorTheme == indicatorTheme && + other.connectorTheme == connectorTheme; + } + + @override + int get hashCode { + // Warning: For the sanity of the reader, please make sure these properties + // are in the exact same order as in operator == and in the raw constructor + // and in the order of fields in the class and in the lerp() method. + final values = [ + direction, + color, + nodePosition, + nodeItemOverlap, + indicatorPosition, + indicatorTheme, + connectorTheme, + ]; + return hashList(values); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + final defaultData = TimelineThemeData.fallback(); + properties + ..add(DiagnosticsProperty('direction', direction, + defaultValue: defaultData.direction, level: DiagnosticLevel.debug)) + ..add(ColorProperty('color', color, + defaultValue: defaultData.color, level: DiagnosticLevel.debug)) + ..add(DoubleProperty('nodePosition', nodePosition, + defaultValue: defaultData.nodePosition, level: DiagnosticLevel.debug)) + ..add(FlagProperty('nodeItemOverlap', + value: nodeItemOverlap, ifTrue: 'overlap connector and indicator')) + ..add(DoubleProperty('indicatorPosition', indicatorPosition, + defaultValue: defaultData.indicatorPosition, + level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty( + 'indicatorTheme', + indicatorTheme, + defaultValue: defaultData.indicatorTheme, + level: DiagnosticLevel.debug, + )) + ..add(DiagnosticsProperty( + 'connectorTheme', + connectorTheme, + defaultValue: defaultData.connectorTheme, + level: DiagnosticLevel.debug, + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_tile.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_tile.dart new file mode 100644 index 00000000..69bf8054 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_tile.dart @@ -0,0 +1,211 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'indicator_theme.dart'; +import 'timeline_node.dart'; +import 'timeline_theme.dart'; +import 'util.dart'; + +/// Align the timeline node within the timeline tile. +enum TimelineNodeAlign { + /// Align [TimelineTile.node] to start side. + start, + + /// Align [TimelineTile.node] to end side. + end, + + /// Align according to the [TimelineTile.nodePosition]. + basic, +} + +/// A widget that displays timeline node and two contents. +/// +/// The [contents] are displayed on the end side, and the [oppositeContents] are +/// displayed on the start side. +/// The [node] is displayed between the two. +class TimelineTile extends StatelessWidget { + const TimelineTile({ + Key key, + this.direction, + @required this.node, + this.nodeAlign = TimelineNodeAlign.basic, + this.nodePosition, + this.contents, + this.oppositeContents, + this.mainAxisExtent, + this.crossAxisExtent, + }) : assert( + nodeAlign == TimelineNodeAlign.basic || + (nodeAlign != TimelineNodeAlign.basic && nodePosition == null), + 'Cannot provide both a nodeAlign and a nodePosition', + ), + assert(nodePosition == null || nodePosition >= 0), + super(key: key); + + /// {@template timelines.direction} + /// The axis along which the timeline scrolls. + /// {@endtemplate} + final Axis direction; + + /// A widget that displays indicator and two connectors. + final Widget node; + + /// Align the [node] within the timeline tile. + /// + /// If try to use indicators with different sizes in each timeline tile, the + /// timeline node may be broken. + /// This can be prevented by set [IndicatorThemeData.size] to an appropriate + /// size. + /// + /// If [nodeAlign] is not [TimelineNodeAlign.basic], then [nodePosition] is + /// ignored. + final TimelineNodeAlign nodeAlign; + + /// A position of [node] inside both two contents. + /// + /// {@macro timelines.node.position} + final double nodePosition; + + /// The contents to display inside the timeline tile. + final Widget contents; + + /// The contents to display on the opposite side of the [contents]. + final Widget oppositeContents; + + /// The extent of the child in the scrolling axis. + /// If the scroll axis is vertical, this extent is the child's height. If the + /// scroll axis is horizontal, this extent is the child's width. + /// + /// If non-null, forces the tile to have the given extent in the scroll + /// direction. + /// + /// Specifying an [mainAxisExtent] is more efficient than letting the tile + /// determine their own extent because the because it don't use the Intrinsic + /// widget([IntrinsicHeight]/[IntrinsicWidth]) when building. + final double mainAxisExtent; + + /// The extent of the child in the non-scrolling axis. + /// + /// If the scroll axis is vertical, this extent is the child's width. If the + /// scroll axis is horizontal, this extent is the child's height. + final double crossAxisExtent; + + double _getEffectiveNodePosition(BuildContext context) { + if (nodeAlign == TimelineNodeAlign.start) return 0.0; + if (nodeAlign == TimelineNodeAlign.end) return 1.0; + var nodePosition = this.nodePosition; + nodePosition ??= (node is TimelineTileNode) + ? (node as TimelineTileNode).getEffectivePosition(context) + : TimelineTheme.of(context).nodePosition; + return nodePosition; + } + + @override + Widget build(BuildContext context) { + // double: reduce direction check + final direction = this.direction ?? TimelineTheme.of(context).direction; + final nodeFlex = _getEffectiveNodePosition(context) * kFlexMultiplier; + + var minNodeExtent = TimelineTheme.of(context).indicatorTheme.size ?? 0.0; + var items = [ + if (nodeFlex > 0) + Expanded( + flex: nodeFlex.toInt(), + child: Align( + alignment: direction == Axis.vertical + ? AlignmentDirectional.centerEnd + : Alignment.bottomCenter, + child: oppositeContents ?? SizedBox.shrink(), + ), + ), + ConstrainedBox( + constraints: BoxConstraints( + minWidth: direction == Axis.vertical ? minNodeExtent : 0.0, + minHeight: direction == Axis.vertical ? 0.0 : minNodeExtent, + ), + child: node, + ), + if (nodeFlex < kFlexMultiplier) + Expanded( + flex: (kFlexMultiplier - nodeFlex).toInt(), + child: Align( + alignment: direction == Axis.vertical + ? AlignmentDirectional.centerStart + : Alignment.topCenter, + child: contents ?? SizedBox.shrink(), + ), + ), + ]; + + var result; + switch (direction) { + case Axis.vertical: + result = Row( + mainAxisAlignment: MainAxisAlignment.center, + children: items, + ); + + if (mainAxisExtent != null) { + result = SizedBox( + width: crossAxisExtent, + height: mainAxisExtent, + child: result, + ); + } else { + result = IntrinsicHeight( + child: result, + ); + + if (crossAxisExtent != null) { + result = SizedBox( + width: crossAxisExtent, + child: result, + ); + } + } + break; + case Axis.horizontal: + result = Column( + mainAxisAlignment: MainAxisAlignment.center, + children: items, + ); + if (mainAxisExtent != null) { + result = SizedBox( + width: mainAxisExtent, + height: crossAxisExtent, + child: result, + ); + } else { + result = IntrinsicWidth( + child: result, + ); + + if (crossAxisExtent != null) { + result = SizedBox( + height: crossAxisExtent, + child: result, + ); + } + } + break; + default: + throw ArgumentError.value(direction, '$direction is invalid.'); + } + + result = Align( + child: result, + ); + + if (TimelineTheme.of(context).direction != direction) { + result = TimelineTheme( + data: TimelineTheme.of(context).copyWith( + direction: direction, + ), + child: result, + ); + } + + return result; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_tile_builder.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_tile_builder.dart new file mode 100644 index 00000000..7bcd5c63 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timeline_tile_builder.dart @@ -0,0 +1,549 @@ +import 'package:flutter/material.dart'; + +import 'connectors.dart'; +import 'indicators.dart'; +import 'timeline_node.dart'; +import 'timeline_theme.dart'; +import 'timeline_tile.dart'; + +/// How a contents displayed be into timeline. +/// +/// See also: +/// * [TimelineTileBuilder.fromStyle] +enum ContentsAlign { + /// The contents aligned end of timeline. And the opposite contents aligned + /// start of timeline. + /// + /// Example: + /// ``` + /// opposite contents | contents + /// opposite contents | contents + /// opposite contents | contents + /// ``` + basic, + + /// The contents aligned start of timeline. And the opposite contents aligned + /// end of timeline. + /// + /// Example: + /// + /// ``` + /// contents | opposite contents + /// contents | opposite contents + /// contents | opposite contents + /// ``` + reverse, + + /// The contents and opposite contents displayed alternating. + /// + /// Example: + /// ``` + /// contents | opposite contents + /// opposite contents | contents + /// contents | opposite contents + /// opposite contents | contents + /// contents | opposite contents + /// ``` + alternating, +} + +/// An enum that representing the direction the connector is connected through +/// the builder. +/// +/// See also: +/// +/// * [TimelineTileBuilder.connected], which is how the builder uses this enum +/// to connect each connector. +/// * [TimelineTileBuilder.connectedFromStyle], which is how the builder uses +/// this enum to connect each connector. +enum ConnectionDirection { before, after } + +/// An enum that representing the connector type in [TimelineNode]. +/// +/// For example, if the timeline direction is Axis.horizontal and the text +/// direction is LTR: +/// ``` +/// start end +/// ---- O ---- +/// ``` +/// See also: +/// +/// * [ConnectedConnectorBuilder], which is use this. +enum ConnectorType { start, end } + +/// An enum that determines the style of indicator in timeline tile builder. +/// +/// double: replace with class to support parameters +/// +/// See also: +/// +/// * [TimelineTileBuilder.fromStyle], which is use this. +/// * [TimelineTileBuilder.connectedFromStyle], which is use this. +enum IndicatorStyle { + /// Draw dot indicator. + dot, + + /// Draw outlined dot indicator. + outlined, + + /// Draw container indicator. double: need child to builds... + container, + + /// Draw transparent indicator. (invisible indicator) + transparent, +} + +/// Types of connectors displayed into timeline +/// +/// See also: +/// * [TimelineTileBuilder.fromStyle]. +enum ConnectorStyle { + /// Draw solid line connector. + solidLine, + + /// Draw dashed line connector. + dashedLine, + + /// Draw transparent connector. (invisible connector) + transparent, +} + +/// Signature for a function that creates a connected connector widget for a +/// given index and type, e.g., in a timeline tile builder. +typedef ConnectedConnectorBuilder = Widget Function( + BuildContext context, int index, ConnectorType type); + +/// Signature for a function that creates a typed value for a given index, e.g., +/// in a timeline tile builder. +/// +/// Used by [TimelineTileBuilder] that use lazily-generated typed value. +typedef IndexedValueBuilder = T Function(BuildContext context, int index); + +/// WARNING: The interface of this class is not yet clear. It may change +/// frequently. +/// +/// A delegate that supplies [TimelineTile] for timeline using a builder +/// callback. +class TimelineTileBuilder { + /// Create a connected tile builder, which builds tiles using each component + /// builder. + /// + /// Check below for how to build: + /// + /// Original build system: + /// + /// ``` + /// | <-- builder(0) + /// O contents1 <-- builder(0) + /// | <-- builder(0) + /// | <-- builder(1) + /// O contents2 <-- builder(1) + /// | <-- builder(1) + /// ``` + /// + /// Connected build system(before): + /// + /// ``` + /// | <-- draw if provided [firstConnectorBuilder] + /// O contents1 <-- builder(0) + /// | <-- builder(1) + /// | <-- builder(1) + /// O contents2 <-- builder(1) + /// | <-- builder(2) + /// | <-- builder(2) + /// O <-- builder(2) + /// | <-- builder(3) + /// .. + /// | <-- draw if provided [lastConnectorBuilder] + /// ``` + /// + /// + /// Connected build system(after): + /// + /// ``` + /// | <-- draw if provided [firstConnectorBuilder] + /// O contents1 <-- builder(0) + /// | <-- builder(0) + /// | <-- builder(0) + /// O contents2 <-- builder(1) + /// | <-- builder(1) + /// | <-- builder(1) + /// O <-- builder(2) + /// | <-- builder(2) + /// .. + /// | <-- draw if provided [lastConnectorBuilder] + /// ``` + /// + /// The above example can be made similar by just set the + /// [TimelineNode.indicatorPosition] as 0 or 1, but the contents position may + /// be limited. + /// + /// {@macro timelines.itemExtentBuilder} + /// + /// See also: + /// + /// * [TimelineTileBuilder.connectedFromStyle], which builds connected tiles + /// from style. + factory TimelineTileBuilder.connected({ + @required int itemCount, + ContentsAlign contentsAlign = ContentsAlign.basic, + ConnectionDirection connectionDirection = ConnectionDirection.after, + NullableIndexedWidgetBuilder contentsBuilder, + NullableIndexedWidgetBuilder oppositeContentsBuilder, + NullableIndexedWidgetBuilder indicatorBuilder, + ConnectedConnectorBuilder connectorBuilder, + WidgetBuilder firstConnectorBuilder, + WidgetBuilder lastConnectorBuilder, + double itemExtent, + IndexedValueBuilder itemExtentBuilder, + IndexedValueBuilder nodePositionBuilder, + IndexedValueBuilder indicatorPositionBuilder, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + bool addSemanticIndexes = true, + }) { + return TimelineTileBuilder( + itemCount: itemCount, + contentsAlign: contentsAlign, + contentsBuilder: contentsBuilder, + oppositeContentsBuilder: oppositeContentsBuilder, + indicatorBuilder: indicatorBuilder, + startConnectorBuilder: _createConnectedStartConnectorBuilder( + connectionDirection: connectionDirection, + firstConnectorBuilder: firstConnectorBuilder, + connectorBuilder: connectorBuilder, + ), + endConnectorBuilder: _createConnectedEndConnectorBuilder( + connectionDirection: connectionDirection, + lastConnectorBuilder: lastConnectorBuilder, + connectorBuilder: connectorBuilder, + itemCount: itemCount, + ), + itemExtent: itemExtent, + itemExtentBuilder: itemExtentBuilder, + nodePositionBuilder: nodePositionBuilder, + indicatorPositionBuilder: indicatorPositionBuilder, + ); + } + + /// Create a connected tile builder, which builds tiles using each style. + /// + /// {@macro timelines.itemExtentBuilder} + /// + /// See also: + /// + /// * [TimelineTileBuilder.connected], which builds connected tiles. + /// * [TimelineTileBuilder.fromStyle], which builds tiles from style. + factory TimelineTileBuilder.connectedFromStyle({ + @required int itemCount, + ConnectionDirection connectionDirection = ConnectionDirection.after, + NullableIndexedWidgetBuilder contentsBuilder, + NullableIndexedWidgetBuilder oppositeContentsBuilder, + ContentsAlign contentsAlign = ContentsAlign.basic, + IndexedValueBuilder indicatorStyleBuilder, + IndexedValueBuilder connectorStyleBuilder, + ConnectorStyle firstConnectorStyle = ConnectorStyle.solidLine, + ConnectorStyle lastConnectorStyle = ConnectorStyle.solidLine, + double itemExtent, + IndexedValueBuilder itemExtentBuilder, + IndexedValueBuilder nodePositionBuilder, + IndexedValueBuilder indicatorPositionBuilder, + }) { + return TimelineTileBuilder( + itemCount: itemCount, + contentsAlign: contentsAlign, + contentsBuilder: contentsBuilder, + oppositeContentsBuilder: oppositeContentsBuilder, + indicatorBuilder: (context, index) => _createStyledIndicatorBuilder( + indicatorStyleBuilder?.call(context, index))(context), + startConnectorBuilder: _createConnectedStartConnectorBuilder( + connectionDirection: connectionDirection, + firstConnectorBuilder: (context) => + _createStyledConnectorBuilder(firstConnectorStyle)(context), + connectorBuilder: (context, index, __) => _createStyledConnectorBuilder( + connectorStyleBuilder?.call(context, index))(context), + ), + endConnectorBuilder: _createConnectedEndConnectorBuilder( + connectionDirection: connectionDirection, + lastConnectorBuilder: (context) => + _createStyledConnectorBuilder(lastConnectorStyle)(context), + connectorBuilder: (context, index, __) => _createStyledConnectorBuilder( + connectorStyleBuilder?.call(context, index))(context), + itemCount: itemCount, + ), + itemExtent: itemExtent, + itemExtentBuilder: itemExtentBuilder, + nodePositionBuilder: nodePositionBuilder, + indicatorPositionBuilder: indicatorPositionBuilder, + ); + } + + /// Create a tile builder, which builds tiles using each style. + /// + /// {@macro timelines.itemExtentBuilder} + /// double: style each index like fromStyleBuilder + /// + /// See also: + /// + /// * [IndicatorStyle] + /// * [ConnectorStyle] + /// * [ContentsAlign] + factory TimelineTileBuilder.fromStyle({ + @required int itemCount, + NullableIndexedWidgetBuilder contentsBuilder, + NullableIndexedWidgetBuilder oppositeContentsBuilder, + ContentsAlign contentsAlign = ContentsAlign.basic, + IndicatorStyle indicatorStyle = IndicatorStyle.dot, + ConnectorStyle connectorStyle = ConnectorStyle.solidLine, + ConnectorStyle endConnectorStyle = ConnectorStyle.solidLine, + double itemExtent, + IndexedValueBuilder itemExtentBuilder, + IndexedValueBuilder nodePositionBuilder, + IndexedValueBuilder indicatorPositionBuilder, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + bool addSemanticIndexes = true, + }) { + return TimelineTileBuilder( + itemCount: itemCount, + contentsAlign: contentsAlign, + contentsBuilder: contentsBuilder, + oppositeContentsBuilder: oppositeContentsBuilder, + indicatorBuilder: (context, index) => + _createStyledIndicatorBuilder(indicatorStyle)(context), + startConnectorBuilder: (context, _) => + _createStyledConnectorBuilder(connectorStyle)(context), + endConnectorBuilder: (context, _) => + _createStyledConnectorBuilder(connectorStyle)(context), + itemExtent: itemExtent, + itemExtentBuilder: itemExtentBuilder, + nodePositionBuilder: nodePositionBuilder, + indicatorPositionBuilder: indicatorPositionBuilder, + ); + } + + /// Create a tile builder, which builds tiles using each component builder. + /// + /// {@template timelines.itemExtentBuilder} + /// If each item has a fixed extent, use [itemExtent], and if each item has a + /// different extent, use [itemExtentBuilder]. + /// {@endtemplate} + /// + /// double: need refactoring, is it has many builders...? + factory TimelineTileBuilder({ + @required int itemCount, + ContentsAlign contentsAlign = ContentsAlign.basic, + NullableIndexedWidgetBuilder contentsBuilder, + NullableIndexedWidgetBuilder oppositeContentsBuilder, + NullableIndexedWidgetBuilder indicatorBuilder, + NullableIndexedWidgetBuilder startConnectorBuilder, + NullableIndexedWidgetBuilder endConnectorBuilder, + double itemExtent, + IndexedValueBuilder itemExtentBuilder, + IndexedValueBuilder nodePositionBuilder, + IndexedValueBuilder nodeItemOverlapBuilder, + IndexedValueBuilder indicatorPositionBuilder, + IndexedValueBuilder themeBuilder, + }) { + assert( + itemExtent == null || itemExtentBuilder == null, + 'Cannot provide both a itemExtent and a itemExtentBuilder.', + ); + + final effectiveContentsBuilder = _createAlignedContentsBuilder( + align: contentsAlign, + contentsBuilder: contentsBuilder, + oppositeContentsBuilder: oppositeContentsBuilder, + ); + final effectiveOppositeContentsBuilder = _createAlignedContentsBuilder( + align: contentsAlign, + contentsBuilder: oppositeContentsBuilder, + oppositeContentsBuilder: contentsBuilder, + ); + + return TimelineTileBuilder._( + (context, index) { + final tile = TimelineTile( + mainAxisExtent: itemExtent ?? itemExtentBuilder?.call(context, index), + node: TimelineNode( + indicator: indicatorBuilder?.call(context, index) ?? + Indicator.transparent(), + startConnector: startConnectorBuilder?.call(context, index), + endConnector: endConnectorBuilder?.call(context, index), + overlap: nodeItemOverlapBuilder?.call(context, index), + position: nodePositionBuilder?.call(context, index), + indicatorPosition: indicatorPositionBuilder?.call(context, index), + ), + contents: effectiveContentsBuilder(context, index), + oppositeContents: effectiveOppositeContentsBuilder(context, index), + ); + + final theme = themeBuilder?.call(context, index); + if (theme != null) { + return TimelineTheme( + data: theme, + child: tile, + ); + } else { + return tile; + } + }, + itemCount: itemCount, + ); + } + + const TimelineTileBuilder._( + this._builder, { + @required this.itemCount, + }) : assert(itemCount >= 0); + + final IndexedWidgetBuilder _builder; + final int itemCount; + + Widget build(BuildContext context, int index) { + return _builder(context, index); + } + + static NullableIndexedWidgetBuilder _createConnectedStartConnectorBuilder({ + ConnectionDirection connectionDirection, + WidgetBuilder firstConnectorBuilder, + ConnectedConnectorBuilder connectorBuilder, + }) => + (context, index) { + if (index == 0) { + if (firstConnectorBuilder != null) { + return firstConnectorBuilder.call(context); + } else { + return null; + } + } + + if (connectionDirection == ConnectionDirection.before) { + return connectorBuilder?.call(context, index, ConnectorType.start); + } else { + return connectorBuilder?.call( + context, index - 1, ConnectorType.start); + } + }; + + static NullableIndexedWidgetBuilder _createConnectedEndConnectorBuilder({ + ConnectionDirection connectionDirection, + WidgetBuilder lastConnectorBuilder, + ConnectedConnectorBuilder connectorBuilder, + @required int itemCount, + }) => + (context, index) { + if (index == itemCount - 1) { + if (lastConnectorBuilder != null) { + return lastConnectorBuilder.call(context); + } else { + return null; + } + } + + if (connectionDirection == ConnectionDirection.before) { + return connectorBuilder?.call(context, index + 1, ConnectorType.end); + } else { + return connectorBuilder?.call(context, index, ConnectorType.end); + } + }; + + static NullableIndexedWidgetBuilder _createAlignedContentsBuilder({ + @required ContentsAlign align, + NullableIndexedWidgetBuilder contentsBuilder, + NullableIndexedWidgetBuilder oppositeContentsBuilder, + }) { + return (context, index) { + switch (align) { + case ContentsAlign.alternating: + if (index.isOdd) { + return oppositeContentsBuilder?.call(context, index); + } + + return contentsBuilder?.call(context, index); + case ContentsAlign.reverse: + return oppositeContentsBuilder?.call(context, index); + case ContentsAlign.basic: + default: + return contentsBuilder?.call(context, index); + } + }; + } + + static WidgetBuilder _createStyledIndicatorBuilder(IndicatorStyle style) { + return (_) { + switch (style) { + case IndicatorStyle.dot: + return Indicator.dot(); + case IndicatorStyle.outlined: + return Indicator.outlined(); + case IndicatorStyle.container: + return Indicator.widget(); + case IndicatorStyle.transparent: + default: + return Indicator.transparent(); + } + }; + } + + static WidgetBuilder _createStyledConnectorBuilder(ConnectorStyle style) { + return (_) { + switch (style) { + case ConnectorStyle.solidLine: + return Connector.solidLine(); + case ConnectorStyle.dashedLine: + return Connector.dashedLine(); + case ConnectorStyle.transparent: + default: + return Connector.transparent(); + } + }; + } +} + +int _kDefaultSemanticIndexCallback(Widget _, int localIndex) => localIndex; + +/// The widgets returned from the builder callback are automatically wrapped in +/// [AutomaticKeepAlive] widgets if [addAutomaticKeepAlives] is true +/// (the default) and in [RepaintBoundary] widgets if [addRepaintBoundaries] is +/// true (also the default). +/// +/// ## Accessibility +/// +/// The [CustomScrollView] requires that its semantic children are annotated +/// using [IndexedSemantics]. This is done by default in the delegate with the +/// `addSemanticIndexes` parameter set to true. +/// +/// If multiple delegates are used in a single scroll view, then the indexes +/// will not be correct by default. The `semanticIndexOffset` can be used to +/// offset the semantic indexes of each delegate so that the indexes are +/// monotonically increasing. For example, if a scroll view contains two +/// delegates where the first has 10 children contributing semantics, then the +/// second delegate should offset its children by 10. +/// +/// See also: +/// +/// * [IndexedSemantics], for an example of manually annotating child nodes +/// with semantic indexes. +class TimelineTileBuilderDelegate extends SliverChildBuilderDelegate { + TimelineTileBuilderDelegate( + NullableIndexedWidgetBuilder builder, { + ChildIndexGetter findChildIndexCallback, + int childCount, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + bool addSemanticIndexes = true, + SemanticIndexCallback semanticIndexCallback = + _kDefaultSemanticIndexCallback, + int semanticIndexOffset = 0, + }) : super( + builder, + findChildIndexCallback: findChildIndexCallback, + childCount: childCount, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + addSemanticIndexes: addSemanticIndexes, + semanticIndexCallback: semanticIndexCallback, + semanticIndexOffset: semanticIndexOffset, + ); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timelines.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timelines.dart new file mode 100644 index 00000000..a12ac9b6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/timelines.dart @@ -0,0 +1,491 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'timeline_theme.dart'; +import 'timeline_tile_builder.dart'; + +/// A scrollable timeline of widgets arranged linearly. +class Timeline extends BoxScrollView { + /// Creates a scrollable, linear array of widgets that are created on demand. + /// + /// This constructor is appropriate for list views with a large (or infinite) + /// number of children because the builder is called only for those children + /// that are actually visible. + /// + /// Providing a non-null `itemCount` improves the ability of the [Timeline] to + /// estimate the maximum scroll extent. + /// + /// The `itemBuilder` callback will be called only with indices greater than + /// or equal to zero and less than `itemCount`. + /// + /// The `itemBuilder` should always return a non-null widget, and actually + /// create the widget instances when called. + /// Avoid using a builder that returns a previously-constructed widget; if the + /// timeline view's children are created in advance, or all at once when the + /// [Timeline] itself is created, it is more efficient to use the [Timeline] + /// constructor. Even more efficient, however, is to create the instances on + /// demand using this constructor's `itemBuilder` callback. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The + /// `addSemanticIndexes` argument corresponds to the + /// [SliverChildBuilderDelegate.addSemanticIndexes] property. None + /// may be null. + /// + /// [Timeline.builder] by default does not support child reordering. If you + /// are planning to change child order at a + /// later time, consider using [Timeline] or [Timeline.custom]. + factory Timeline.tileBuilder({ + Key key, + @required TimelineTileBuilder builder, + Axis scrollDirection, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + // double itemExtent, double: fixedExtentTileBuilder + double cacheExtent, + int semanticChildCount, + DragStartBehavior dragStartBehavior = DragStartBehavior.start, + ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = + ScrollViewKeyboardDismissBehavior.manual, + String restorationId, + Clip clipBehavior = Clip.hardEdge, + TimelineThemeData theme, + }) { + assert(builder.itemCount >= 0); + assert( + semanticChildCount == null || semanticChildCount <= builder.itemCount); + return Timeline.custom( + key: key, + childrenDelegate: SliverChildBuilderDelegate( + builder.build, + childCount: builder.itemCount, + // double: apply some fields if needed. + ), + scrollDirection: scrollDirection, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + // itemExtent: itemExtent, + cacheExtent: cacheExtent, + semanticChildCount: semanticChildCount ?? builder.itemCount, + dragStartBehavior: dragStartBehavior, + keyboardDismissBehavior: keyboardDismissBehavior, + restorationId: restorationId, + clipBehavior: clipBehavior, + theme: theme, + ); + } + + /// Creates a scrollable, linear array of widgets from an explicit [List]. + /// + /// This constructor is appropriate for timeline views with a small number of + /// children because constructing the [List] requires doing work for every + /// child that could possibly be displayed in the timeline view instead of + /// just those children that are actually visible. + /// + /// It is usually more efficient to create children on demand using + /// [Timeline.builder] because it will create the widget children lazily as + /// necessary. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverChildListDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverChildListDelegate.addRepaintBoundaries] property. The + /// `addSemanticIndexes` argument corresponds to the + /// [SliverChildListDelegate.addSemanticIndexes] property. None may be null. + Timeline({ + Key key, + Axis scrollDirection, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + this.itemExtent, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + bool addSemanticIndexes = true, + double cacheExtent, + List children = const [], + int semanticChildCount, + DragStartBehavior dragStartBehavior = DragStartBehavior.start, + ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = + ScrollViewKeyboardDismissBehavior.manual, + String restorationId, + Clip clipBehavior = Clip.hardEdge, + TimelineThemeData theme, + }) : childrenDelegate = SliverChildListDelegate( + children, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + addSemanticIndexes: addSemanticIndexes, + ), + assert(scrollDirection == null || theme == null, + 'Cannot provide both a scrollDirection and a theme.'), + this.theme = theme, + super( + key: key, + scrollDirection: scrollDirection ?? theme?.direction ?? Axis.vertical, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + cacheExtent: cacheExtent, + semanticChildCount: semanticChildCount ?? children.length, + dragStartBehavior: dragStartBehavior, + keyboardDismissBehavior: keyboardDismissBehavior, + restorationId: restorationId, + clipBehavior: clipBehavior, + ); + + /// Creates a scrollable, linear array of widgets that are created on demand. + /// + /// This constructor is appropriate for list views with a large (or infinite) + /// number of children because the builder is called only for those children + /// that are actually visible. + /// + /// Providing a non-null `itemCount` improves the ability of the [Timeline] to + /// estimate the maximum scroll extent. + /// + /// The `itemBuilder` callback will be called only with indices greater than + /// or equal to zero and less than `itemCount`. + /// + /// The `itemBuilder` should always return a non-null widget, and actually + /// create the widget instances when called. + /// Avoid using a builder that returns a previously-constructed widget; if the + /// timeline view's children are created in advance, or all at once when the + /// [Timeline] itself is created, it is more efficient to use the [Timeline] + /// constructor. Even more efficient, however, is to create the instances on + /// demand using this constructor's `itemBuilder` callback. + /// + /// The `addAutomaticKeepAlives` argument corresponds to the + /// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The + /// `addRepaintBoundaries` argument corresponds to the + /// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The + /// `addSemanticIndexes` argument corresponds to the + /// [SliverChildBuilderDelegate.addSemanticIndexes] property. None + /// may be null. + /// + /// [Timeline.builder] by default does not support child reordering. If you + /// are planning to change child order at a + /// later time, consider using [Timeline] or [Timeline.custom]. + Timeline.builder({ + Key key, + Axis scrollDirection, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + this.itemExtent, + @required IndexedWidgetBuilder itemBuilder, + @required int itemCount, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + bool addSemanticIndexes = true, + double cacheExtent, + int semanticChildCount, + DragStartBehavior dragStartBehavior = DragStartBehavior.start, + ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = + ScrollViewKeyboardDismissBehavior.manual, + String restorationId, + Clip clipBehavior = Clip.hardEdge, + TimelineThemeData theme, + }) : assert(itemCount >= 0), + assert(semanticChildCount == null || semanticChildCount <= itemCount), + assert(scrollDirection == null || theme == null, + 'Cannot provide both a scrollDirection and a theme.'), + childrenDelegate = SliverChildBuilderDelegate( + itemBuilder, + childCount: itemCount, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + addSemanticIndexes: addSemanticIndexes, + ), + this.theme = theme, + super( + key: key, + scrollDirection: scrollDirection ?? theme?.direction ?? Axis.vertical, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + cacheExtent: cacheExtent, + semanticChildCount: semanticChildCount ?? itemCount, + dragStartBehavior: dragStartBehavior, + keyboardDismissBehavior: keyboardDismissBehavior, + restorationId: restorationId, + clipBehavior: clipBehavior, + ); + + /// Creates a scrollable, linear array of widgets with a custom child model. + /// + /// For example, a custom child model can control the algorithm used to + /// estimate the size of children that are not actually visible. + /// + /// See also: + /// + /// * This works similarly to [ListView.custom]. + Timeline.custom({ + Key key, + Axis scrollDirection, + bool reverse = false, + ScrollController controller, + bool primary, + ScrollPhysics physics, + bool shrinkWrap = false, + EdgeInsetsGeometry padding, + this.itemExtent, + @required this.childrenDelegate, + double cacheExtent, + int semanticChildCount, + DragStartBehavior dragStartBehavior = DragStartBehavior.start, + ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = + ScrollViewKeyboardDismissBehavior.manual, + String restorationId, + Clip clipBehavior = Clip.hardEdge, + TimelineThemeData theme, + }) : assert(scrollDirection == null || theme == null, + 'Cannot provide both a scrollDirection and a theme.'), + this.theme = theme, + super( + key: key, + scrollDirection: scrollDirection ?? theme?.direction ?? Axis.vertical, + reverse: reverse, + controller: controller, + primary: primary, + physics: physics, + shrinkWrap: shrinkWrap, + padding: padding, + cacheExtent: cacheExtent, + semanticChildCount: semanticChildCount, + dragStartBehavior: dragStartBehavior, + keyboardDismissBehavior: keyboardDismissBehavior, + restorationId: restorationId, + clipBehavior: clipBehavior, + ); + + /// If non-null, forces the children to have the given extent in the scroll + /// direction. + /// + /// Specifying an [itemExtent] is more efficient than letting the children + /// determine their own extent because the scrolling machinery can make use + /// of the foreknowledge of the children's extent to save work, for example + /// when the scroll position changes drastically. + final double itemExtent; + + /// A delegate that provides the children for the [Timeline]. + /// + /// The [Timeline.custom] constructor lets you specify this delegate + /// explicitly. The [Timeline] and [Timeline.builder] constructors create a + /// [childrenDelegate] that wraps the given [List] and [IndexedWidgetBuilder], + /// respectively. + final SliverChildDelegate childrenDelegate; + + /// Default visual properties, like colors, size and spaces, for this + /// timeline's component widgets. + /// + /// The default value of this property is the value of + /// [TimelineThemeData.vertical()]. + final TimelineThemeData theme; + + @override + Widget buildChildLayout(BuildContext context) { + Widget result; + if (itemExtent != null) { + result = SliverFixedExtentList( + delegate: childrenDelegate, + itemExtent: itemExtent, + ); + } else { + result = SliverList(delegate: childrenDelegate); + } + + var theme; + if (this.theme != null) { + theme = this.theme; + } else if (scrollDirection != TimelineTheme.of(context).direction) { + theme = TimelineTheme.of(context).copyWith(direction: scrollDirection); + } + + if (theme != null) { + return TimelineTheme( + data: theme, + child: result, + ); + } else { + return result; + } + } +} + +/// A widget that displays its children in a one-dimensional array with +/// timeline theme. +class FixedTimeline extends StatelessWidget { + /// Creates a timeline flex layout. + factory FixedTimeline.tileBuilder({ + Key key, + @required TimelineTileBuilder builder, + TimelineThemeData theme, + Axis direction, + MainAxisSize mainAxisSize = MainAxisSize.max, + TextDirection textDirection, + VerticalDirection verticalDirection = VerticalDirection.down, + Clip clipBehavior = Clip.none, + }) { + // double: how remove Builders + return FixedTimeline( + children: [ + for (int i = 0; i < builder.itemCount; i++) + Builder( + builder: (context) => builder.build(context, i), + ), + ], + theme: theme, + direction: direction, + mainAxisSize: mainAxisSize, + textDirection: textDirection, + verticalDirection: verticalDirection, + clipBehavior: clipBehavior, + ); + } + + /// Creates a timeline flex layout. + /// + /// The [direction], [verticalDirection] arguments must not be null. + /// + /// The [textDirection] argument defaults to the ambient [Directionality], + /// if any. If there is no ambient directionality, and a text direction is + /// going to be necessary to decide which direction to lay the children in or + /// to disambiguate `start` or `end` values for the main or cross axis + /// directions, the [textDirection] must not be null. + const FixedTimeline({ + Key key, + this.theme, + this.direction, + this.mainAxisSize = MainAxisSize.max, + this.textDirection, + this.verticalDirection = VerticalDirection.down, + this.clipBehavior = Clip.none, + this.children = const [], + }) : assert(direction == null || theme == null, + 'Cannot provide both a direction and a theme.'), + super(key: key); + + /// Default visual properties, like colors, size and spaces, for this + /// timeline's component widgets. + /// + /// The default value of this property is the value of + /// [TimelineThemeData.vertical()]. + final TimelineThemeData theme; + + /// The direction to use as the main axis. + final Axis direction; + + /// The widgets below this widget in the tree. + /// + /// If this list is going to be mutated, it is usually wise to put a [Key] on + /// each of the child widgets, so that the framework can match old + /// configurations to new configurations and maintain the underlying + /// render objects. + /// + /// See also: + /// + /// * [MultiChildRenderObjectWidget.children] + final List children; + + /// How much space should be occupied in the main axis. + /// + /// After allocating space to children, there might be some remaining free + /// space. This value controls whether to maximize or minimize the amount of + /// free space, subject to the incoming layout constraints. + /// + /// If some children have a non-zero flex factors (and none have a fit of + /// [FlexFit.loose]), they will expand to consume all the available space and + /// there will be no remaining free space to maximize or minimize, making this + /// value irrelevant to the final layout. + final MainAxisSize mainAxisSize; + + /// Determines the order to lay children out horizontally and how to interpret + /// `start` and `end` in the horizontal direction. + /// + /// Defaults to the ambient [Directionality]. + /// + /// If [textDirection] is [TextDirection.rtl], then the direction in which + /// text flows starts from right to left. Otherwise, if [textDirection] is + /// [TextDirection.ltr], then the direction in which text flows starts from + /// left to right. + /// + /// If the [direction] is [Axis.horizontal], this controls the order in which + /// the children are positioned (left-to-right or right-to-left). + /// + /// If the [direction] is [Axis.horizontal], and there's more than one child, + /// then the [textDirection] (or the ambient [Directionality]) must not + /// be null. + final TextDirection textDirection; + + /// Determines the order to lay children out vertically and how to interpret + /// `start` and `end` in the vertical direction. + /// + /// Defaults to [VerticalDirection.down]. + /// + /// If the [direction] is [Axis.vertical], there's more than one child, then + /// the [verticalDirection] must not be null. + final VerticalDirection verticalDirection; + + /// The content will be clipped (or not) according to this option. + /// + /// See the enum Clip for details of all possible options and their common + /// use cases. + /// + /// Defaults to [Clip.none]. + final Clip clipBehavior; + + @override + Widget build(BuildContext context) { + final direction = this.direction ?? this.theme?.direction ?? Axis.vertical; + + Widget result = Flex( + direction: direction, + children: children, + mainAxisSize: mainAxisSize, + textDirection: textDirection, + verticalDirection: verticalDirection, + clipBehavior: clipBehavior, + ); + + var theme; + if (this.direction != null) { + if (direction != TimelineTheme.of(context).direction) { + theme = TimelineTheme.of(context).copyWith(direction: this.direction); + } + } else if (this.theme != null) { + theme = this.theme; + } + + if (theme != null) { + return TimelineTheme( + data: theme, + child: result, + ); + } else { + return result; + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/util.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/util.dart new file mode 100644 index 00000000..8cd6a756 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/src/util.dart @@ -0,0 +1 @@ +const kFlexMultiplier = 1000.0; diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/lib/timelines.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/timelines.dart new file mode 100644 index 00000000..1b65013c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/lib/timelines.dart @@ -0,0 +1,12 @@ +/// Widgets that make it easy to implement the timeline UI component. +library timelines; + +export 'src/connector_theme.dart'; +export 'src/connectors.dart'; +export 'src/indicator_theme.dart'; +export 'src/indicators.dart'; +export 'src/timelines.dart'; +export 'src/timeline_node.dart'; +export 'src/timeline_theme.dart'; +export 'src/timeline_tile.dart'; +export 'src/timeline_tile_builder.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/main.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/main.dart new file mode 100644 index 00000000..8fd97d40 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/main.dart @@ -0,0 +1,187 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'lib/timelines.dart'; + +import 'component_page.dart'; +import 'showcase/package_delivery_tracking.dart'; +import 'showcase/process_timeline.dart'; +import 'showcase/timeline_status.dart'; +import 'showcase_page.dart'; +import 'theme_page.dart'; +import 'widget.dart'; + +void main() { + runApp(TimeLinesApp()); +} + +class TimeLinesApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Timelines Demo', + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + onGenerateRoute: (settings) { + String path = Uri.tryParse(settings.name)?.path; + Widget child; + switch (path) { + case '/theme': + child = ThemePage(); + break; + case '/timeline_status': + child = TimelineStatusPage(); + break; + case '/package_delivery_tracking': + child = PackageDeliveryTrackingPage(); + break; + case '/process_timeline': + child = ProcessTimelinePage(); + break; + default: + child = ExamplePage(); + } + + return MaterialPageRoute(builder: (context) => HomePage(child: child)); + }, + initialRoute: '/', + ); + } +} + +class HomePage extends StatefulWidget { + HomePage({ + Key key, + @required this.child, + }) : super(key: key); + + final Widget child; + + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends State { + final _navigatorKey = GlobalKey(); + + @override + void didUpdateWidget(covariant HomePage oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.child != widget.child) { + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + if (_navigatorKey.currentState?.canPop() ?? false) { + _navigatorKey.currentState?.maybePop(); + return false; + } else { + return true; + } + }, + child: Column( + children: [ + Expanded( + child: Navigator( + key: _navigatorKey, + onGenerateRoute: (settings) => MaterialPageRoute( + builder: (context) => widget.child, + ), + ), + ), + if (kIsWeb) WebAlert() + ], + ), + ); + } +} + +class WebAlert extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SizedBox( + height: 80.0, + child: Material( + child: Center( + child: Text( + 'You are using the web version now.\nSome UI can be broken.', + textAlign: TextAlign.center, + ), + ), + ), + ); + } +} + +class ExamplePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return TimelineTheme( + data: TimelineThemeData( + indicatorTheme: IndicatorThemeData(size: 15.0), + ), + child: Scaffold( + appBar: AppBar( + title: Text('Timelines Example'), + ), + body: ListView( + padding: EdgeInsets.all(20.0), + children: [ + _NavigationCard( + name: 'Components', + navigationBuilder: () => ComponentPage(), + ), + _NavigationCard( + name: 'Theme', + navigationBuilder: () => ThemePage(), + ), + _NavigationCard( + name: 'Showcase', + navigationBuilder: () => ShowcasePage(), + ), + ], + ), + ), + ); + } +} + +class _NavigationCard extends StatelessWidget { + const _NavigationCard({ + Key key, + @required this.name, + this.navigationBuilder, + }) : super(key: key); + + final String name; + final NavigateWidgetBuilder navigationBuilder; + + @override + Widget build(BuildContext context) { + return Center( + child: NavigationCard( + margin: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: 10.0, + ), + borderRadius: BorderRadius.circular(8), + navigationBuilder: navigationBuilder, + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Row( + children: [ + Expanded( + child: Text(name), + ), + Icon(Icons.chevron_right), + ], + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/package_delivery_tracking.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/package_delivery_tracking.dart new file mode 100644 index 00000000..7bae1ba0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/package_delivery_tracking.dart @@ -0,0 +1,328 @@ +import 'package:flutter/material.dart'; +import '../lib/timelines.dart'; + +import '../widget.dart'; + +const kTileHeight = 50.0; + +class PackageDeliveryTrackingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: TitleAppBar('Package Delivery Tracking'), + body: ListView.builder( + itemBuilder: (context, index) { + final data = _data(index + 1); + return Center( + child: Container( + width: 360.0, + child: Card( + margin: EdgeInsets.all(20.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(20.0), + child: _OrderTitle( + orderInfo: data, + ), + ), + Divider(height: 1.0), + _DeliveryProcesses(processes: data.deliveryProcesses), + Divider(height: 1.0), + Padding( + padding: const EdgeInsets.all(20.0), + child: _OnTimeBar(driver: data.driverInfo), + ), + ], + ), + ), + ), + ); + }, + ), + ); + } +} + +class _OrderTitle extends StatelessWidget { + const _OrderTitle({ + Key key, + @required this.orderInfo, + }) : super(key: key); + + final _OrderInfo orderInfo; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Text( + 'Delivery #${orderInfo.id}', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + Spacer(), + Text( + '${orderInfo.date.day}/${orderInfo.date.month}/${orderInfo.date.year}', + style: TextStyle( + color: Color(0xffb6b2b2), + ), + ), + ], + ); + } +} + +class _InnerTimeline extends StatelessWidget { + const _InnerTimeline({ + @required this.messages, + }); + + final List<_DeliveryMessage> messages; + + @override + Widget build(BuildContext context) { + bool isEdgeIndex(int index) { + return index == 0 || index == messages.length + 1; + } + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: FixedTimeline.tileBuilder( + theme: TimelineTheme.of(context).copyWith( + nodePosition: 0, + connectorTheme: TimelineTheme.of(context).connectorTheme.copyWith( + thickness: 1.0, + ), + indicatorTheme: TimelineTheme.of(context).indicatorTheme.copyWith( + size: 10.0, + position: 0.5, + ), + ), + builder: TimelineTileBuilder( + indicatorBuilder: (_, index) => + !isEdgeIndex(index) ? Indicator.outlined(borderWidth: 1.0) : null, + startConnectorBuilder: (_, index) => Connector.solidLine(), + endConnectorBuilder: (_, index) => Connector.solidLine(), + contentsBuilder: (_, index) { + if (isEdgeIndex(index)) { + return null; + } + + return Padding( + padding: EdgeInsets.only(left: 8.0), + child: Text(messages[index - 1].toString()), + ); + }, + itemExtentBuilder: (_, index) => isEdgeIndex(index) ? 10.0 : 30.0, + nodeItemOverlapBuilder: (_, index) => + isEdgeIndex(index) ? true : null, + itemCount: messages.length + 2, + ), + ), + ); + } +} + +class _DeliveryProcesses extends StatelessWidget { + const _DeliveryProcesses({Key key, @required this.processes}) + : super(key: key); + + final List<_DeliveryProcess> processes; + @override + Widget build(BuildContext context) { + return DefaultTextStyle( + style: TextStyle( + color: Color(0xff9b9b9b), + fontSize: 12.5, + ), + child: Padding( + padding: const EdgeInsets.all(20.0), + child: FixedTimeline.tileBuilder( + theme: TimelineThemeData( + nodePosition: 0, + color: Color(0xff989898), + indicatorTheme: IndicatorThemeData( + position: 0, + size: 20.0, + ), + connectorTheme: ConnectorThemeData( + thickness: 2.5, + ), + ), + builder: TimelineTileBuilder.connected( + connectionDirection: ConnectionDirection.before, + itemCount: processes.length, + contentsBuilder: (_, index) { + if (processes[index].isCompleted) return null; + + return Padding( + padding: EdgeInsets.only(left: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + processes[index].name, + style: DefaultTextStyle.of(context).style.copyWith( + fontSize: 18.0, + ), + ), + _InnerTimeline(messages: processes[index].messages), + ], + ), + ); + }, + indicatorBuilder: (_, index) { + if (processes[index].isCompleted) { + return DotIndicator( + color: Color(0xff66c97f), + child: Icon( + Icons.check, + color: Colors.white, + size: 12.0, + ), + ); + } else { + return OutlinedDotIndicator( + borderWidth: 2.5, + ); + } + }, + connectorBuilder: (_, index, ___) => SolidLineConnector( + color: processes[index].isCompleted ? Color(0xff66c97f) : null, + ), + ), + ), + ), + ); + } +} + +class _OnTimeBar extends StatelessWidget { + const _OnTimeBar({Key key, @required this.driver}) : super(key: key); + + final _DriverInfo driver; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + MaterialButton( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('On-time!'), + ), + ); + }, + elevation: 0, + shape: StadiumBorder(), + color: Color(0xff66c97f), + textColor: Colors.white, + child: Text('On-time'), + ), + Spacer(), + Text( + 'Driver\n${driver.name}', + textAlign: TextAlign.center, + ), + SizedBox(width: 12.0), + Container( + width: 40.0, + height: 40.0, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + fit: BoxFit.fitWidth, + image: NetworkImage( + driver.thumbnailUrl, + ), + ), + ), + ), + ], + ); + } +} + +_OrderInfo _data(int id) => _OrderInfo( + id: id, + date: DateTime.now(), + driverInfo: _DriverInfo( + name: 'Philipe', + thumbnailUrl: + 'https://i.pinimg.com/originals/08/45/81/084581e3155d339376bf1d0e17979dc6.jpg', + ), + deliveryProcesses: [ + _DeliveryProcess( + 'Package Process', + messages: [ + _DeliveryMessage('8:30am', 'Package received by driver'), + _DeliveryMessage('11:30am', 'Reached halfway mark'), + ], + ), + _DeliveryProcess( + 'In Transit', + messages: [ + _DeliveryMessage('13:00pm', 'Driver arrived at destination'), + _DeliveryMessage('11:35am', 'Package delivered by m.vassiliades'), + ], + ), + _DeliveryProcess.complete(), + ], + ); + +class _OrderInfo { + const _OrderInfo({ + @required this.id, + @required this.date, + @required this.driverInfo, + @required this.deliveryProcesses, + }); + + final int id; + final DateTime date; + final _DriverInfo driverInfo; + final List<_DeliveryProcess> deliveryProcesses; +} + +class _DriverInfo { + const _DriverInfo({ + @required this.name, + @required this.thumbnailUrl, + }); + + final String name; + final String thumbnailUrl; +} + +class _DeliveryProcess { + const _DeliveryProcess( + this.name, { + this.messages = const [], + }); + + const _DeliveryProcess.complete() + : this.name = 'Done', + this.messages = const []; + + final String name; + final List<_DeliveryMessage> messages; + + bool get isCompleted => name == 'Done'; +} + +class _DeliveryMessage { + const _DeliveryMessage(this.createdAt, this.message); + + final String createdAt; // final DateTime createdAt; + final String message; + + @override + String toString() { + return '$createdAt $message'; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/process_timeline.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/process_timeline.dart new file mode 100644 index 00000000..e26326c0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/process_timeline.dart @@ -0,0 +1,255 @@ +import 'dart:developer'; +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import '../lib/timelines.dart'; + +import '../widget.dart'; + +const kTileHeight = 50.0; + +const completeColor = Color(0xff5e6172); +const inProgressColor = Color(0xff5ec792); +const todoColor = Color(0xffd1d2d7); + +class ProcessTimelinePage extends StatefulWidget { + @override + _ProcessTimelinePageState createState() => _ProcessTimelinePageState(); +} + +class _ProcessTimelinePageState extends State { + int _processIndex = 2; + + Color getColor(int index) { + if (index == _processIndex) { + return inProgressColor; + } else if (index < _processIndex) { + return completeColor; + } else { + return todoColor; + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: TitleAppBar('Process Timeline'), + body: Timeline.tileBuilder( + theme: TimelineThemeData( + direction: Axis.horizontal, + connectorTheme: ConnectorThemeData( + space: 30.0, + thickness: 5.0, + ), + ), + builder: TimelineTileBuilder.connected( + connectionDirection: ConnectionDirection.before, + itemExtentBuilder: (_, __) => + MediaQuery.of(context).size.width / _processes.length, + oppositeContentsBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: Image.asset( + 'assets/images/process_timeline/status${index + 1}.png', + width: 50.0, + color: getColor(index), + ), + ); + }, + contentsBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.only(top: 15.0), + child: Text( + _processes[index], + style: TextStyle( + fontWeight: FontWeight.bold, + color: getColor(index), + ), + ), + ); + }, + indicatorBuilder: (_, index) { + var color; + var child; + if (index == _processIndex) { + color = inProgressColor; + child = Padding( + padding: const EdgeInsets.all(8.0), + child: CircularProgressIndicator( + strokeWidth: 3.0, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ); + } else if (index < _processIndex) { + color = completeColor; + child = Icon( + Icons.check, + color: Colors.white, + size: 15.0, + ); + } else { + color = todoColor; + } + + if (index <= _processIndex) { + return Stack( + children: [ + CustomPaint( + size: Size(30.0, 30.0), + painter: _BezierPainter( + color: color, + drawStart: index > 0, + drawEnd: index < _processIndex, + ), + ), + DotIndicator( + size: 30.0, + color: color, + child: child, + ), + ], + ); + } else { + return Stack( + children: [ + CustomPaint( + size: Size(15.0, 15.0), + painter: _BezierPainter( + color: color, + drawEnd: index < _processes.length - 1, + ), + ), + OutlinedDotIndicator( + borderWidth: 4.0, + color: color, + ), + ], + ); + } + }, + connectorBuilder: (_, index, type) { + if (index > 0) { + if (index == _processIndex) { + final prevColor = getColor(index - 1); + final color = getColor(index); + List gradientColors; + if (type == ConnectorType.start) { + gradientColors = [Color.lerp(prevColor, color, 0.5), color]; + } else { + gradientColors = [ + prevColor, + Color.lerp(prevColor, color, 0.5) + ]; + } + return DecoratedLineConnector( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: gradientColors, + ), + ), + ); + } else { + return SolidLineConnector( + color: getColor(index), + ); + } + } else { + return null; + } + }, + itemCount: _processes.length, + ), + ), + floatingActionButton: FloatingActionButton( + child: Icon(FontAwesomeIcons.chevronRight), + onPressed: () { + setState(() { + _processIndex = (_processIndex + 1) % _processes.length; + }); + }, + backgroundColor: inProgressColor, + ), + ); + } +} + +/// hardcoded bezier painter +/// double: Bezier curve into package component +class _BezierPainter extends CustomPainter { + const _BezierPainter({ + @required this.color, + this.drawStart = true, + this.drawEnd = true, + }); + + final Color color; + final bool drawStart; + final bool drawEnd; + + Offset _offset(double radius, double angle) { + return Offset( + radius * cos(angle) + radius, + radius * sin(angle) + radius, + ); + } + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..style = PaintingStyle.fill + ..color = color; + + final radius = size.width / 2; + + var angle; + var offset1; + var offset2; + + var path; + + if (drawStart) { + angle = 3 * pi / 4; + offset1 = _offset(radius, angle); + offset2 = _offset(radius, -angle); + path = Path() + ..moveTo(offset1.dx, offset1.dy) + ..quadraticBezierTo(0.0, size.height / 2, -radius, + radius) // double connector start & gradient + ..quadraticBezierTo(0.0, size.height / 2, offset2.dx, offset2.dy) + ..close(); + + canvas.drawPath(path, paint); + } + if (drawEnd) { + angle = -pi / 4; + offset1 = _offset(radius, angle); + offset2 = _offset(radius, -angle); + + path = Path() + ..moveTo(offset1.dx, offset1.dy) + ..quadraticBezierTo(size.width, size.height / 2, size.width + radius, + radius) // double connector end & gradient + ..quadraticBezierTo(size.width, size.height / 2, offset2.dx, offset2.dy) + ..close(); + + canvas.drawPath(path, paint); + } + } + + @override + bool shouldRepaint(_BezierPainter oldDelegate) { + return oldDelegate.color != color || + oldDelegate.drawStart != drawStart || + oldDelegate.drawEnd != drawEnd; + } +} + +final _processes = [ + 'Prospect', + 'Tour', + 'Offer', + 'Contract', + 'Settled', +]; diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/timeline_status.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/timeline_status.dart new file mode 100644 index 00000000..cde6c40c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/showcase/timeline_status.dart @@ -0,0 +1,239 @@ +import 'package:flutter/material.dart'; +import '../lib/timelines.dart'; + +import '../widget.dart'; + +const kTileHeight = 50.0; + +class TimelineStatusPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: TitleAppBar('Timeline Status'), + body: Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Row( + children: [ + _Timeline1(), + SizedBox(width: 12.0), + _Timeline2(), + SizedBox(width: 12.0), + _Timeline3(), + ], + ), + ), + ), + ); + } +} + +class _Timeline1 extends StatelessWidget { + @override + Widget build(BuildContext context) { + final data = _TimelineStatus.values; + return Flexible( + child: Timeline.tileBuilder( + theme: TimelineThemeData( + nodePosition: 0, + connectorTheme: ConnectorThemeData( + thickness: 3.0, + color: Color(0xffd3d3d3), + ), + indicatorTheme: IndicatorThemeData( + size: 15.0, + ), + ), + padding: EdgeInsets.symmetric(vertical: 20.0), + builder: TimelineTileBuilder.connected( + contentsBuilder: (_, __) => _EmptyContents(), + connectorBuilder: (_, index, __) { + if (index == 0) { + return SolidLineConnector(color: Color(0xff6ad192)); + } else { + return SolidLineConnector(); + } + }, + indicatorBuilder: (_, index) { + switch (data[index]) { + case _TimelineStatus.done: + return DotIndicator( + color: Color(0xff6ad192), + child: Icon( + Icons.check, + color: Colors.white, + size: 10.0, + ), + ); + case _TimelineStatus.sync: + return DotIndicator( + color: Color(0xff193fcc), + child: Icon( + Icons.sync, + size: 10.0, + color: Colors.white, + ), + ); + case _TimelineStatus.inProgress: + return OutlinedDotIndicator( + color: Color(0xffa7842a), + borderWidth: 2.0, + backgroundColor: Color(0xffebcb62), + ); + case _TimelineStatus.todo: + default: + return OutlinedDotIndicator( + color: Color(0xffbabdc0), + backgroundColor: Color(0xffe6e7e9), + ); + } + }, + itemExtentBuilder: (_, __) => kTileHeight, + itemCount: data.length, + ), + ), + ); + } +} + +class _Timeline2 extends StatelessWidget { + @override + Widget build(BuildContext context) { + List<_TimelineStatus> data = [ + _TimelineStatus.done, + _TimelineStatus.inProgress, + _TimelineStatus.inProgress, + _TimelineStatus.todo + ]; + + return Flexible( + child: Timeline.tileBuilder( + theme: TimelineThemeData( + nodePosition: 0, + color: Color(0xffc2c5c9), + connectorTheme: ConnectorThemeData( + thickness: 3.0, + ), + ), + padding: EdgeInsets.only(top: 20.0), + builder: TimelineTileBuilder.connected( + indicatorBuilder: (context, index) { + return DotIndicator( + color: data[index].isInProgress ? Color(0xff193fcc) : null, + ); + }, + connectorBuilder: (_, index, connectorType) { + var color; + if (index + 1 < data.length - 1) { + color = data[index].isInProgress && data[index + 1].isInProgress + ? Color(0xff193fcc) + : null; + } + return SolidLineConnector( + indent: connectorType == ConnectorType.start ? 0 : 2.0, + endIndent: connectorType == ConnectorType.end ? 0 : 2.0, + color: color, + ); + }, + contentsBuilder: (_, __) => _EmptyContents(), + itemExtentBuilder: (_, __) { + return kTileHeight; + }, + itemCount: data.length, + ), + ), + ); + } +} + +class _Timeline3 extends StatelessWidget { + @override + Widget build(BuildContext context) { + List<_TimelineStatus> data = [ + _TimelineStatus.done, + _TimelineStatus.inProgress, + _TimelineStatus.inProgress, + _TimelineStatus.todo + ]; + + return Flexible( + child: Timeline.tileBuilder( + theme: TimelineThemeData( + nodePosition: 0, + nodeItemOverlap: true, + connectorTheme: ConnectorThemeData( + color: Color(0xffe6e7e9), + thickness: 15.0, + ), + ), + padding: EdgeInsets.only(top: 20.0), + builder: TimelineTileBuilder.connected( + indicatorBuilder: (context, index) { + final status = data[index]; + return OutlinedDotIndicator( + color: + status.isInProgress ? Color(0xff6ad192) : Color(0xffe6e7e9), + backgroundColor: + status.isInProgress ? Color(0xffd4f5d6) : Color(0xffc2c5c9), + borderWidth: status.isInProgress ? 3.0 : 2.5, + ); + }, + connectorBuilder: (context, index, connectorType) { + var color; + if (index + 1 < data.length - 1 && + data[index].isInProgress && + data[index + 1].isInProgress) { + color = data[index].isInProgress ? Color(0xff6ad192) : null; + } + return SolidLineConnector( + color: color, + ); + }, + contentsBuilder: (context, index) { + var height; + if (index + 1 < data.length - 1 && + data[index].isInProgress && + data[index + 1].isInProgress) { + height = kTileHeight - 10; + } else { + height = kTileHeight + 5; + } + return SizedBox( + height: height, + child: Align( + alignment: Alignment.centerLeft, + child: _EmptyContents(), + ), + ); + }, + itemCount: data.length, + ), + ), + ); + } +} + +class _EmptyContents extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.only(left: 10.0), + height: 10.0, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(2.0), + color: Color(0xffe6e7e9), + ), + ); + } +} + +enum _TimelineStatus { + done, + sync, + inProgress, + todo, +} + +extension on _TimelineStatus { + bool get isInProgress => this == _TimelineStatus.inProgress; +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/showcase_page.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/showcase_page.dart new file mode 100644 index 00000000..c94275fc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/showcase_page.dart @@ -0,0 +1,154 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import 'showcase/package_delivery_tracking.dart'; +import 'showcase/process_timeline.dart'; +import 'showcase/timeline_status.dart'; +import 'widget.dart'; + +class ShowcasePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: TitleAppBar('Showcase'), + body: LayoutBuilder( + builder: (context, constraints) { + final cards = [ + _ShowcaseCard( + image: 'assets/images/timeline_status.png', + title: 'Timeline Status', + designer: 'Tridip Thrizu', + url: + 'https://dribbble.com/shots/5659998-Daily-UI-Component-4-Timeline-Status', + navigationBuilder: () => TimelineStatusPage(), + ), + _ShowcaseCard( + image: 'assets/images/package_delivery_tracking.png', + title: 'Package Delivery Tracking', + designer: 'Series Eight', + url: + 'https://dribbble.com/shots/1899993-Package-Delivery-Tracking/attachments/1899993-Package-Delivery-Tracking?mode=media', + navigationBuilder: () => PackageDeliveryTrackingPage(), + ), + _ShowcaseCard( + image: 'assets/images/process_timeline.png', + title: 'Process Timeline', + designer: 'Eddie Lobanovskiy', + url: 'https://dribbble.com/shots/5260798-Process', + navigationBuilder: () => ProcessTimelinePage(), + ), + ]; + + if (constraints.maxWidth >= 760) { + return SingleChildScrollView( + padding: EdgeInsets.all(40.0), + child: Center( + child: Wrap( + children: cards + .map( + (card) => SizedBox(width: 320.0, child: card), + ) + .toList(), + ), + ), + ); + } else { + return ListView( + padding: EdgeInsets.symmetric(vertical: 20.0), + children: cards, + ); + } + }, + ), + ); + } +} + +class _ShowcaseCard extends StatelessWidget { + const _ShowcaseCard({ + Key key, + @required this.navigationBuilder, + @required this.image, + @required this.title, + @required this.designer, + @required this.url, + }) : super(key: key); + + final String image; + final String title; + final String designer; + final String url; + + final NavigateWidgetBuilder navigationBuilder; + + Widget _forceLightTheme(BuildContext context, Widget child) { + return Theme( + data: ThemeData.light(), + child: child, + ); + } + + @override + Widget build(BuildContext context) { + return NavigationCard( + navigationBuilder: () => _forceLightTheme(context, navigationBuilder()), + child: Container( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Image.asset( + image, + width: MediaQuery.of(context).size.width, + fit: BoxFit.fitWidth, + ), + Container( + child: Column( + children: [ + SizedBox(height: 20.0), + Text(title), + Container( + padding: EdgeInsets.all(12.0), + alignment: Alignment.centerRight, + child: InkWell( + child: Container( + padding: EdgeInsets.all(8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + FontAwesomeIcons.dribbble, + semanticLabel: 'Original', + size: 10.0, + color: Colors.grey[600], + ), + SizedBox(width: 6.0), + Flexible( + child: Text( + 'Designed by $designer', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 10.0, + color: Colors.grey[600], + ), + ), + ), + ], + ), + ), + onTap: () async { + if (await canLaunch(url)) await launch(url); + }, + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/theme_page.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/theme_page.dart new file mode 100644 index 00000000..2481b706 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/theme_page.dart @@ -0,0 +1,362 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'lib/timelines.dart'; + +import 'widget.dart'; + +class ThemePage extends StatefulWidget { + @override + _ThemePageState createState() => _ThemePageState(); +} + +class _ThemePageState extends State { + final _themeColors = { + 'RED': Colors.red, + 'GREEN': Colors.green, + 'BLUE': Colors.blue, + 'AMBER': Colors.amber, + 'TEAL': Colors.teal, + 'ORANGE': Colors.orange, + }; + + TimelineThemeData _theme; + + @override + void initState() { + super.initState(); + _theme = TimelineThemeData(); + } + + void _updateTheme(TimelineThemeData theme) { + if (_theme != theme) { + setState(() { + _theme = theme; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: TitleAppBar('Theme'), + body: Stack( + children: [ + ListView( + padding: EdgeInsets.fromLTRB(20.0, 160.0, 20.0, 40.0), + children: [ + Card( + child: Container( + padding: EdgeInsets.all(20.0), + child: Row( + children: [ + Text('contents: '), + Container( + width: 10.0, + height: 10.0, + color: Colors.teal, + ), + SizedBox(width: 10.0), + Text('opposite contents: '), + Container( + width: 10.0, + height: 10.0, + color: Colors.amber, + ), + ], + ), + ), + ), + SizedBox(height: 10.0), + Card( + child: Container( + padding: EdgeInsets.all(20.0), + child: Column( + children: [ + Text( + 'TimelineTheme', + style: Theme.of(context).textTheme.headline6, + ), + _ThemeDropdown( + title: 'Direction', + items: { + 'Vertical': Axis.vertical, + 'Horizontal': Axis.horizontal, + }, + value: _theme.direction, + onChanged: (Axis axis) { + if (_theme.direction != axis) { + setState(() { + _updateTheme(_theme.copyWith(direction: axis)); + }); + } + }, + ), + _ThemeDropdown( + title: 'Color', + items: _themeColors, + value: _theme.color, + onChanged: (Color color) { + _updateTheme(_theme.copyWith(color: color)); + }, + ), + SizedBox(height: 10.0), + Row( + children: [ + Text('Node item overlap'), + SizedBox(width: 12.0), + Checkbox( + value: _theme.nodeItemOverlap, + onChanged: (overlap) { + _updateTheme( + _theme.copyWith(nodeItemOverlap: overlap)); + }, + ), + ], + ), + _ThemeSlider( + title: 'Node Position', + value: _theme.nodePosition, + onChanged: (nodePosition) { + _updateTheme( + _theme.copyWith(nodePosition: nodePosition)); + }, + ), + _ThemeSlider( + title: 'Indicator Position', + value: _theme.indicatorPosition, + onChanged: (indicatorPosition) { + _updateTheme(_theme.copyWith( + indicatorPosition: indicatorPosition)); + }, + ), + ], + ), + ), + ), + Card( + child: Container( + padding: EdgeInsets.all(20.0), + child: Column( + children: [ + Text( + 'IndicatorTheme', + style: Theme.of(context).textTheme.headline6, + ), + _ThemeDropdown( + title: 'Color', + items: _themeColors, + value: _theme.indicatorTheme.color, + onChanged: (color) { + _updateTheme( + _theme.copyWith( + indicatorTheme: + _theme.indicatorTheme.copyWith(color: color), + ), + ); + }, + ), + SizedBox(height: 10.0), + _ThemeSlider( + title: 'Position', + value: _theme.indicatorTheme.position ?? 0, + onChanged: (position) { + _updateTheme( + _theme.copyWith( + indicatorTheme: _theme.indicatorTheme + .copyWith(position: position), + ), + ); + }, + ), + _ThemeSlider( + title: 'Size', + value: _theme.indicatorTheme.size ?? 0, + max: 100.0, + onChanged: (size) { + _updateTheme( + _theme.copyWith( + indicatorTheme: + _theme.indicatorTheme.copyWith(size: size), + ), + ); + }, + ), + ], + ), + ), + ), + Card( + child: Container( + padding: EdgeInsets.all(20.0), + child: Column( + children: [ + Text( + 'ConnectorTheme', + style: Theme.of(context).textTheme.headline6, + ), + _ThemeDropdown( + title: 'Color', + items: _themeColors, + value: _theme.connectorTheme.color, + onChanged: (color) { + _updateTheme( + _theme.copyWith( + connectorTheme: + _theme.connectorTheme.copyWith(color: color), + ), + ); + }, + ), + SizedBox(height: 10.0), + _ThemeSlider( + title: 'Space', + value: _theme.connectorTheme.space ?? 0, + max: 100, + onChanged: (space) { + _updateTheme( + _theme.copyWith( + connectorTheme: + _theme.connectorTheme.copyWith(space: space), + ), + ); + }, + ), + _ThemeSlider( + title: 'Indent', + value: _theme.connectorTheme.indent ?? 0, + max: 22, + onChanged: (indent) { + _updateTheme( + _theme.copyWith( + connectorTheme: _theme.connectorTheme + .copyWith(indent: indent), + ), + ); + }, + ), + _ThemeSlider( + title: 'Thickness', + value: _theme.connectorTheme.thickness ?? 0, + max: 100, + onChanged: (thickness) { + _updateTheme( + _theme.copyWith( + connectorTheme: _theme.connectorTheme + .copyWith(thickness: thickness), + ), + ); + }, + ), + ], + ), + ), + ), + ], + ), + Card( + elevation: 3, + margin: EdgeInsets.zero, + child: Container( + padding: EdgeInsets.all(20.0), + child: TimelineTheme( + data: _theme, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TimelineTile( + mainAxisExtent: 100, + crossAxisExtent: 100, + oppositeContents: Container(color: Colors.amber), + node: TimelineNode( + startConnector: SolidLineConnector(), + endConnector: SolidLineConnector(), + indicator: OutlinedDotIndicator(), + ), + contents: Container(color: Colors.teal), + ), + ], + ), + ), + ), + ), + ], + ), + ); + } +} + +class _ThemeDropdown extends StatelessWidget { + const _ThemeDropdown({ + Key key, + @required this.title, + @required this.items, + @required this.value, + @required this.onChanged, + }) : super(key: key); + + final String title; + final Map items; + final T value; + final ValueChanged onChanged; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Text(title), + SizedBox(width: 10.0), + DropdownButton( + items: items.entries.map((entry) { + return DropdownMenuItem( + value: entry.value, + child: Text(entry.key), + ); + }).toList(), + value: value, + onChanged: onChanged, + ), + ], + ); + } +} + +class _ThemeSlider extends StatelessWidget { + const _ThemeSlider({ + Key key, + @required this.title, + @required this.value, + @required this.onChanged, + this.max = 1.0, + }) : super(key: key); + + final String title; + final double value; + final ValueChanged onChanged; + final double max; + + @override + Widget build(BuildContext context) { + var label; + if (value == null) { + label = ''; + } else if (value > 1) { + label = value.toInt().toString(); + } else { + label = value.toString(); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title), + SizedBox(width: 10.0), + Slider( + label: label, + max: max, + divisions: 100, + value: value ?? 0, + onChanged: onChanged, + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/timelines/widget.dart b/FlutterHelper/flutter_helper/lib/samples/timelines/widget.dart new file mode 100644 index 00000000..8c005431 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/timelines/widget.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; + +typedef NavigateWidgetBuilder = Widget Function(); + +mixin NavigateMixin on Widget { + NavigateWidgetBuilder get navigationBuilder; + + Future navigate(BuildContext context) { + if (navigationBuilder == null) { + return Future.value(); + } else { + return Navigator.push( + context, + MaterialPageRoute( + builder: (context) => navigationBuilder(), + ), + ); + } + } +} + +const kNavigationCardRadius = 8.0; + +class NavigationCard extends StatelessWidget with NavigateMixin { + const NavigationCard({ + Key key, + this.margin, + this.borderRadius = + const BorderRadius.all(Radius.circular(kNavigationCardRadius)), + this.navigationBuilder, + @required this.child, + }) : super(key: key); + + final EdgeInsetsGeometry margin; + final BorderRadius borderRadius; + final Widget child; + final NavigateWidgetBuilder navigationBuilder; + + @override + Widget build(BuildContext context) { + return Card( + clipBehavior: Clip.antiAliasWithSaveLayer, + margin: margin, + shape: borderRadius != null + ? RoundedRectangleBorder(borderRadius: borderRadius) + : null, + child: InkWell( + borderRadius: borderRadius, + onTap: () => navigate(context), + child: child, + ), + ); + } +} + +class TitleAppBar extends StatelessWidget with PreferredSizeWidget { + TitleAppBar( + this.title, { + Key key, + }) : preferredSize = Size.fromHeight(kToolbarHeight), + super(key: key); + + @override + final Size preferredSize; + + final String title; + + @override + Widget build(BuildContext context) { + return AppBar( + title: Text(title), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/tinder_cards/cards_section_alignment.dart b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/cards_section_alignment.dart new file mode 100644 index 00000000..7f6e3528 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/cards_section_alignment.dart @@ -0,0 +1,207 @@ +import 'package:flutter/material.dart'; +import 'profile_card_alignment.dart'; +import 'dart:math'; + +List cardsAlign = [ + Alignment(0.0, 1.0), + Alignment(0.0, 0.8), + Alignment(0.0, 0.0) +]; +List cardsSize = List(3); + +class CardsSectionAlignment extends StatefulWidget { + CardsSectionAlignment(BuildContext context) { + cardsSize[0] = Size(MediaQuery.of(context).size.width * 0.9, + MediaQuery.of(context).size.height * 0.6); + cardsSize[1] = Size(MediaQuery.of(context).size.width * 0.85, + MediaQuery.of(context).size.height * 0.55); + cardsSize[2] = Size(MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.5); + } + + @override + _CardsSectionState createState() => _CardsSectionState(); +} + +class _CardsSectionState extends State + with SingleTickerProviderStateMixin { + int cardsCounter = 0; + + List cards = List(); + AnimationController _controller; + + final Alignment defaultFrontCardAlign = Alignment(0.0, 0.0); + Alignment frontCardAlign; + double frontCardRot = 0.0; + + @override + void initState() { + super.initState(); + + // Init cards + for (cardsCounter = 0; cardsCounter < 3; cardsCounter++) { + cards.add(ProfileCardAlignment(cardsCounter)); + } + + frontCardAlign = cardsAlign[2]; + + // Init the animation controller + _controller = + AnimationController(duration: Duration(milliseconds: 700), vsync: this); + _controller.addListener(() => setState(() {})); + _controller.addStatusListener((AnimationStatus status) { + if (status == AnimationStatus.completed) changeCardsOrder(); + }); + } + + @override + Widget build(BuildContext context) { + return Expanded( + child: Stack( + children: [ + backCard(), + middleCard(), + frontCard(), + + // Prevent swiping if the cards are animating + _controller.status != AnimationStatus.forward + ? SizedBox.expand( + child: GestureDetector( + // While dragging the first card + onPanUpdate: (DragUpdateDetails details) { + // Add what the user swiped in the last frame to the alignment of the card + setState(() { + // 20 is the "speed" at which moves the card + frontCardAlign = Alignment( + frontCardAlign.x + + 20 * + details.delta.dx / + MediaQuery.of(context).size.width, + frontCardAlign.y + + 40 * + details.delta.dy / + MediaQuery.of(context).size.height); + + frontCardRot = frontCardAlign.x; // * rotation speed; + }); + }, + // When releasing the first card + onPanEnd: (_) { + // If the front card was swiped far enough to count as swiped + if (frontCardAlign.x > 3.0 || frontCardAlign.x < -3.0) { + animateCards(); + } else { + // Return to the initial rotation and alignment + setState(() { + frontCardAlign = defaultFrontCardAlign; + frontCardRot = 0.0; + }); + } + }, + )) + : Container(), + ], + )); + } + + Widget backCard() { + return Align( + alignment: _controller.status == AnimationStatus.forward + ? CardsAnimation.backCardAlignmentAnim(_controller).value + : cardsAlign[0], + child: SizedBox.fromSize( + size: _controller.status == AnimationStatus.forward + ? CardsAnimation.backCardSizeAnim(_controller).value + : cardsSize[2], + child: cards[2]), + ); + } + + Widget middleCard() { + return Align( + alignment: _controller.status == AnimationStatus.forward + ? CardsAnimation.middleCardAlignmentAnim(_controller).value + : cardsAlign[1], + child: SizedBox.fromSize( + size: _controller.status == AnimationStatus.forward + ? CardsAnimation.middleCardSizeAnim(_controller).value + : cardsSize[1], + child: cards[1]), + ); + } + + Widget frontCard() { + return Align( + alignment: _controller.status == AnimationStatus.forward + ? CardsAnimation.frontCardDisappearAlignmentAnim( + _controller, frontCardAlign) + .value + : frontCardAlign, + child: Transform.rotate( + angle: (pi / 180.0) * frontCardRot, + child: SizedBox.fromSize(size: cardsSize[0], child: cards[0]), + )); + } + + void changeCardsOrder() { + setState(() { + // Swap cards (back card becomes the middle card; middle card becomes the front card, front card becomes a bottom card) + var temp = cards[0]; + cards[0] = cards[1]; + cards[1] = cards[2]; + cards[2] = temp; + + cards[2] = ProfileCardAlignment(cardsCounter); + cardsCounter++; + + frontCardAlign = defaultFrontCardAlign; + frontCardRot = 0.0; + }); + } + + void animateCards() { + _controller.stop(); + _controller.value = 0.0; + _controller.forward(); + } +} + +class CardsAnimation { + static Animation backCardAlignmentAnim( + AnimationController parent) { + return AlignmentTween(begin: cardsAlign[0], end: cardsAlign[1]).animate( + CurvedAnimation( + parent: parent, curve: Interval(0.4, 0.7, curve: Curves.easeIn))); + } + + static Animation backCardSizeAnim(AnimationController parent) { + return SizeTween(begin: cardsSize[2], end: cardsSize[1]).animate( + CurvedAnimation( + parent: parent, curve: Interval(0.4, 0.7, curve: Curves.easeIn))); + } + + static Animation middleCardAlignmentAnim( + AnimationController parent) { + return AlignmentTween(begin: cardsAlign[1], end: cardsAlign[2]).animate( + CurvedAnimation( + parent: parent, curve: Interval(0.2, 0.5, curve: Curves.easeIn))); + } + + static Animation middleCardSizeAnim(AnimationController parent) { + return SizeTween(begin: cardsSize[1], end: cardsSize[0]).animate( + CurvedAnimation( + parent: parent, curve: Interval(0.2, 0.5, curve: Curves.easeIn))); + } + + static Animation frontCardDisappearAlignmentAnim( + AnimationController parent, Alignment beginAlign) { + return AlignmentTween( + begin: beginAlign, + end: Alignment( + beginAlign.x > 0 ? beginAlign.x + 30.0 : beginAlign.x - 30.0, + 0.0) // Has swiped to the left or right? + ) + .animate(CurvedAnimation( + parent: parent, curve: Interval(0.0, 0.5, curve: Curves.easeIn))); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/tinder_cards/cards_section_draggable.dart b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/cards_section_draggable.dart new file mode 100644 index 00000000..7c8bd83c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/cards_section_draggable.dart @@ -0,0 +1,109 @@ +import 'package:flutter/material.dart'; +import 'profile_card_draggable.dart'; + +class CardsSectionDraggable extends StatefulWidget { + @override + _CardsSectionState createState() => _CardsSectionState(); +} + +class _CardsSectionState extends State { + bool dragOverTarget = false; + List cards = List(); + int cardsCounter = 0; + + @override + void initState() { + super.initState(); + + for (cardsCounter = 0; cardsCounter < 3; cardsCounter++) { + cards.add(ProfileCardDraggable(cardsCounter)); + } + } + + @override + Widget build(BuildContext context) { + return Expanded( + child: Stack( + children: [ + // Drag target row + Row( + mainAxisSize: MainAxisSize.max, + children: [ + dragTarget(), + Flexible(flex: 2, child: Container()), + dragTarget() + ], + ), + // Back card + Align( + alignment: Alignment(0.0, 1.0), + child: IgnorePointer( + child: SizedBox.fromSize( + size: Size(MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.5), + child: cards[2], + )), + ), + // Middle card + Align( + alignment: Alignment(0.0, 0.8), + child: IgnorePointer( + child: SizedBox.fromSize( + size: Size(MediaQuery.of(context).size.width * 0.85, + MediaQuery.of(context).size.height * 0.55), + child: cards[1], + )), + ), + // Front card + Align( + alignment: Alignment(0.0, 0.0), + child: Draggable( + feedback: SizedBox.fromSize( + size: Size(MediaQuery.of(context).size.width * 0.9, + MediaQuery.of(context).size.height * 0.6), + child: cards[0], + ), + child: SizedBox.fromSize( + size: Size(MediaQuery.of(context).size.width * 0.9, + MediaQuery.of(context).size.height * 0.6), + child: cards[0], + ), + childWhenDragging: Container(), + ), + ), + ], + )); + } + + void changeCardsOrder() { + setState(() { + // Swap cards + var temp = cards[0]; + cards[0] = cards[1]; + cards[1] = cards[2]; + cards[2] = temp; + + cards[2] = ProfileCardDraggable(cardsCounter); + cardsCounter++; + }); + } + + Widget dragTarget() { + return Flexible( + flex: 1, + child: DragTarget( + builder: (_, __, ___) { + return Container(); + }, + onWillAccept: (_) { + setState(() => dragOverTarget = true); + return true; + }, + onAccept: (_) { + changeCardsOrder(); + setState(() => dragOverTarget = false); + }, + onLeave: (_) => setState(() => dragOverTarget = false)), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/tinder_cards/main.dart b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/main.dart new file mode 100644 index 00000000..4922ac45 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/main.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'swipe_feed_page.dart'; + +void main() => runApp(TinderCardsApp()); + +class TinderCardsApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Tinder cards demo', + theme: ThemeData(primarySwatch: Colors.blue), + home: SwipeFeedPage(), + ); + } + + @override + High getHigh() => High(toStringShort(), """ + """); +} diff --git a/FlutterHelper/flutter_helper/lib/samples/tinder_cards/profile_card_alignment.dart b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/profile_card_alignment.dart new file mode 100644 index 00000000..2ac6ae5e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/profile_card_alignment.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class ProfileCardAlignment extends StatelessWidget { + final int cardNum; + ProfileCardAlignment(this.cardNum); + + @override + Widget build(BuildContext context) { + return Card( + child: Stack( + children: [ + SizedBox.expand( + child: Material( + borderRadius: BorderRadius.circular(12.0), + child: Image.asset('res/portrait.jpeg', fit: BoxFit.cover), + ), + ), + SizedBox.expand( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [Colors.transparent, Colors.black54], + begin: Alignment.center, + end: Alignment.bottomCenter)), + ), + ), + Align( + alignment: Alignment.bottomLeft, + child: Container( + padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Card number $cardNum', + style: TextStyle( + color: Colors.white, + fontSize: 20.0, + fontWeight: FontWeight.w700)), + Padding(padding: EdgeInsets.only(bottom: 8.0)), + Text('A short description.', + textAlign: TextAlign.start, + style: TextStyle(color: Colors.white)), + ], + )), + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/tinder_cards/profile_card_draggable.dart b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/profile_card_draggable.dart new file mode 100644 index 00000000..5a02051c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/profile_card_draggable.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; + +class ProfileCardDraggable extends StatelessWidget { + final int cardNum; + ProfileCardDraggable(this.cardNum); + + @override + Widget build(BuildContext context) { + return Card( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Image.asset('res/portrait.jpeg', fit: BoxFit.cover), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 32.0, horizontal: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Card number $cardNum', + style: TextStyle( + fontSize: 20.0, fontWeight: FontWeight.w700)), + Padding(padding: EdgeInsets.only(bottom: 8.0)), + Text('A short description.', textAlign: TextAlign.start), + ], + )) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/tinder_cards/swipe_feed_page.dart b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/swipe_feed_page.dart new file mode 100644 index 00000000..16db8070 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/tinder_cards/swipe_feed_page.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'cards_section_alignment.dart'; +import 'cards_section_draggable.dart'; + +class SwipeFeedPage extends StatefulWidget { + @override + _SwipeFeedPageState createState() => _SwipeFeedPageState(); +} + +class _SwipeFeedPageState extends State { + bool showAlignmentCards = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 0.0, + centerTitle: true, + backgroundColor: Colors.white, + leading: IconButton( + onPressed: () {}, icon: Icon(Icons.settings, color: Colors.grey)), + title: Switch( + onChanged: (bool value) => setState(() => showAlignmentCards = value), + value: showAlignmentCards, + activeColor: Colors.red, + ), + actions: [ + IconButton( + onPressed: () {}, + icon: Icon(Icons.question_answer, color: Colors.grey)), + ], + ), + backgroundColor: Colors.white, + body: Column( + children: [ + showAlignmentCards + ? CardsSectionAlignment(context) + : CardsSectionDraggable(), + buttonsRow() + ], + ), + ); + } + + Widget buttonsRow() { + return Container( + margin: EdgeInsets.symmetric(vertical: 48.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + FloatingActionButton( + mini: true, + onPressed: () {}, + backgroundColor: Colors.white, + child: Icon(Icons.loop, color: Colors.yellow), + ), + Padding(padding: EdgeInsets.only(right: 8.0)), + FloatingActionButton( + onPressed: () {}, + backgroundColor: Colors.white, + child: Icon(Icons.close, color: Colors.red), + ), + Padding(padding: EdgeInsets.only(right: 8.0)), + FloatingActionButton( + onPressed: () {}, + backgroundColor: Colors.white, + child: Icon(Icons.favorite, color: Colors.green), + ), + Padding(padding: EdgeInsets.only(right: 8.0)), + FloatingActionButton( + mini: true, + onPressed: () {}, + backgroundColor: Colors.white, + child: Icon(Icons.star, color: Colors.blue), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/typeahed/cupertino_app.dart b/FlutterHelper/flutter_helper/lib/samples/typeahed/cupertino_app.dart new file mode 100644 index 00000000..96d37794 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/typeahed/cupertino_app.dart @@ -0,0 +1,100 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/samples/typeahed/src/cupertino_flutter_typeahead.dart'; + +import 'data.dart'; + +class TypeAheadCupertinoApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return CupertinoApp( + title: 'flutter_typeahead demo', + home: CupertinoPageScaffold( + child: FavoriteCitiesPage(), + ), //MyHomePage(), + ); + } + + @override + High getHigh() => High(toStringShort(), "text"); +} + +class FavoriteCitiesPage extends StatefulWidget { + @override + _FavoriteCitiesPage createState() => _FavoriteCitiesPage(); +} + +class _FavoriteCitiesPage extends State { + final GlobalKey _formKey = GlobalKey(); + final TextEditingController _typeAheadController = TextEditingController(); + CupertinoSuggestionsBoxController _suggestionsBoxController = + CupertinoSuggestionsBoxController(); + String favoriteCity = 'Unavailable'; + + @override + Widget build(BuildContext context) { + return Form( + key: _formKey, + child: Padding( + padding: EdgeInsets.all(32.0), + child: Column( + children: [ + SizedBox( + height: 100.0, + ), + Text('What is your favorite city?'), + CupertinoTypeAheadFormField( + getImmediateSuggestions: true, + suggestionsBoxController: _suggestionsBoxController, + textFieldConfiguration: CupertinoTextFieldConfiguration( + controller: _typeAheadController, + ), + suggestionsCallback: (pattern) { + return Future.delayed( + Duration(seconds: 1), + () => CitiesService.getSuggestions(pattern), + ); + }, + itemBuilder: (context, String suggestion) { + return Padding( + padding: const EdgeInsets.all(4.0), + child: Text( + suggestion, + ), + ); + }, + onSuggestionSelected: (String suggestion) { + _typeAheadController.text = suggestion; + }, + validator: (value) => + value.isEmpty ? 'Please select a city' : null, + ), + SizedBox( + height: 10.0, + ), + CupertinoButton( + child: Text('Submit'), + onPressed: () { + if (_formKey.currentState.validate()) { + _formKey.currentState.save(); + setState(() { + favoriteCity = _typeAheadController.text; + }); + } + }, + ), + SizedBox( + height: 10.0, + ), + Text( + 'Your favorite city is $favoriteCity!', + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/typeahed/data.dart b/FlutterHelper/flutter_helper/lib/samples/typeahed/data.dart new file mode 100644 index 00000000..6c44ecb5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/typeahed/data.dart @@ -0,0 +1,41 @@ +import 'dart:async'; +import 'dart:math'; + +class BackendService { + static Future>> getSuggestions(String query) async { + await Future.delayed(Duration(seconds: 1)); + + return List.generate(3, (index) { + return { + 'name': query + index.toString(), + 'price': Random().nextInt(100).toString() + }; + }); + } +} + +class CitiesService { + static final List cities = [ + 'Beirut', + 'Damascus', + 'San Fransisco', + 'Rome', + 'Los Angeles', + 'Madrid', + 'Bali', + 'Barcelona', + 'Paris', + 'Bucharest', + 'New York City', + 'Philadelphia', + 'Sydney', + ]; + + static List getSuggestions(String query) { + List matches = []; + matches.addAll(cities); + + matches.retainWhere((s) => s.toLowerCase().contains(query.toLowerCase())); + return matches; + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/typeahed/flutter_typeahead.dart b/FlutterHelper/flutter_helper/lib/samples/typeahed/flutter_typeahead.dart new file mode 100644 index 00000000..c95d086c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/typeahed/flutter_typeahead.dart @@ -0,0 +1,5 @@ +library flutter_typeahead; + +export 'src/typedef.dart'; +export 'src/flutter_typeahead.dart'; +export 'src/cupertino_flutter_typeahead.dart'; diff --git a/FlutterHelper/flutter_helper/lib/samples/typeahed/main.dart b/FlutterHelper/flutter_helper/lib/samples/typeahed/main.dart new file mode 100644 index 00000000..2e08c232 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/typeahed/main.dart @@ -0,0 +1,8 @@ +import 'dart:io' show Platform; + +import 'package:flutter/material.dart'; + +import 'cupertino_app.dart'; +import 'material_app.dart'; + +void main() => runApp(Platform.isIOS ? TypeAheadCupertinoApp() : TypeAheadMaterialApp()); diff --git a/FlutterHelper/flutter_helper/lib/samples/typeahed/material_app.dart b/FlutterHelper/flutter_helper/lib/samples/typeahed/material_app.dart new file mode 100644 index 00000000..29b50f22 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/typeahed/material_app.dart @@ -0,0 +1,215 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/samples/typeahed/src/flutter_typeahead.dart'; + +import 'data.dart'; + +class TypeAheadMaterialApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'flutter_typeahead demo', + home: MyHomePage(), + ); + } + + @override + High getHigh() => High(toStringShort(), "text"); +} + +class MyHomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 3, + child: Scaffold( + appBar: AppBar( + title: TabBar(tabs: [ + Tab(text: 'Example 1: Navigation'), + Tab(text: 'Example 2: Form'), + Tab(text: 'Example 3: Scroll') + ]), + ), + body: TabBarView(children: [ + NavigationExample(), + FormExample(), + ScrollExample(), + ])), + ); + } +} + +class NavigationExample extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.all(32.0), + child: Column( + children: [ + SizedBox( + height: 10.0, + ), + TypeAheadField( + textFieldConfiguration: TextFieldConfiguration( + autofocus: true, + style: DefaultTextStyle.of(context) + .style + .copyWith(fontStyle: FontStyle.italic), + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: 'What are you looking for?'), + ), + suggestionsCallback: (pattern) async { + return await BackendService.getSuggestions(pattern); + }, + itemBuilder: (context, Map suggestion) { + return ListTile( + leading: Icon(Icons.shopping_cart), + title: Text(suggestion['name']), + subtitle: Text('\$${suggestion['price']}'), + ); + }, + onSuggestionSelected: (Map suggestion) { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => ProductPage(product: suggestion))); + }, + ), + ], + ), + ); + } +} + +class FormExample extends StatefulWidget { + @override + _FormExampleState createState() => _FormExampleState(); +} + +class _FormExampleState extends State { + final GlobalKey _formKey = GlobalKey(); + final TextEditingController _typeAheadController = TextEditingController(); + + String _selectedCity; + + @override + Widget build(BuildContext context) { + return Form( + key: this._formKey, + child: Padding( + padding: EdgeInsets.all(32.0), + child: Column( + children: [ + Text('What is your favorite city?'), + TypeAheadFormField( + textFieldConfiguration: TextFieldConfiguration( + decoration: InputDecoration(labelText: 'City'), + controller: this._typeAheadController, + ), + suggestionsCallback: (pattern) { + return CitiesService.getSuggestions(pattern); + }, + itemBuilder: (context, String suggestion) { + return ListTile( + title: Text(suggestion), + ); + }, + transitionBuilder: (context, suggestionsBox, controller) { + return suggestionsBox; + }, + onSuggestionSelected: (String suggestion) { + this._typeAheadController.text = suggestion; + }, + validator: (value) => + value.isEmpty ? 'Please select a city' : null, + onSaved: (value) => this._selectedCity = value, + ), + SizedBox( + height: 10.0, + ), + RaisedButton( + child: Text('Submit'), + onPressed: () { + if (this._formKey.currentState.validate()) { + this._formKey.currentState.save(); + Scaffold.of(context).showSnackBar( + SnackBar( + content: + Text('Your Favorite City is ${this._selectedCity}'), + ), + ); + } + }, + ) + ], + ), + ), + ); + } +} + +class ScrollExample extends StatelessWidget { + final List items = List.generate(5, (index) => "Item $index"); + + @override + Widget build(BuildContext context) { + return ListView(children: [ + Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text("Suggestion box will resize when scrolling"), + ), + ), + SizedBox(height: 200), + TypeAheadField( + getImmediateSuggestions: true, + textFieldConfiguration: TextFieldConfiguration( + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: 'What are you looking for?'), + ), + suggestionsCallback: (String pattern) async { + return items + .where((item) => + item.toLowerCase().startsWith(pattern.toLowerCase())) + .toList(); + }, + itemBuilder: (context, String suggestion) { + return ListTile( + title: Text(suggestion), + ); + }, + onSuggestionSelected: (String suggestion) { + print("Suggestion selected"); + }, + ), + SizedBox(height: 500), + ]); + } +} + +class ProductPage extends StatelessWidget { + final Map product; + + ProductPage({@required this.product}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(50.0), + child: Column( + children: [ + Text( + this.product['name'], + style: Theme.of(context).textTheme.headline5, + ), + Text( + this.product['price'] + ' USD', + style: Theme.of(context).textTheme.subtitle1, + ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/typeahed/src/cupertino_flutter_typeahead.dart b/FlutterHelper/flutter_helper/lib/samples/typeahed/src/cupertino_flutter_typeahead.dart new file mode 100644 index 00000000..81bd8a87 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/typeahed/src/cupertino_flutter_typeahead.dart @@ -0,0 +1,1523 @@ +/// # Flutter TypeAhead +/// A TypeAhead widget for Flutter, where you can show suggestions to +/// users as they type +/// +/// ## Features +/// * Shows suggestions in an overlay that floats on top of other widgets +/// * Allows you to specify what the suggestions will look like through a +/// builder function +/// * Allows you to specify what happens when the user taps a suggestion +/// * Accepts all the parameters that traditional TextFields accept, like +/// decoration, custom TextEditingController, text styling, etc. +/// * Provides two versions, a normal version and a [FormField](https://docs.flutter.io/flutter/widgets/FormField-class.html) +/// version that accepts validation, submitting, etc. +/// * Provides high customizability; you can customize the suggestion box decoration, +/// the loading bar, the animation, the debounce duration, etc. +import 'dart:async'; +import 'dart:core'; +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; + +import 'typedef.dart'; + +// Cupertino BoxDecoration taken from flutter/lib/src/cupertino/text_field.dart +const BorderSide _kDefaultRoundedBorderSide = BorderSide( + color: CupertinoDynamicColor.withBrightness( + color: Color(0x33000000), + darkColor: Color(0x33FFFFFF), + ), + style: BorderStyle.solid, + width: 0.0, +); +const Border _kDefaultRoundedBorder = Border( + top: _kDefaultRoundedBorderSide, + bottom: _kDefaultRoundedBorderSide, + left: _kDefaultRoundedBorderSide, + right: _kDefaultRoundedBorderSide, +); +const BoxDecoration _kDefaultRoundedBorderDecoration = BoxDecoration( + color: CupertinoDynamicColor.withBrightness( + color: CupertinoColors.white, + darkColor: CupertinoColors.black, + ), + border: _kDefaultRoundedBorder, + borderRadius: BorderRadius.all(Radius.circular(5.0)), +); + +/// A [FormField](https://docs.flutter.io/flutter/widgets/FormField-class.html) +/// implementation of [TypeAheadField], that allows the value to be saved, +/// validated, etc. +/// +/// See also: +/// +/// * [TypeAheadField], A [CupertinoTextField](https://docs.flutter.io/flutter/cupertino/CupertinoTextField-class.html) +/// that displays a list of suggestions as the user types +class CupertinoTypeAheadFormField extends FormField { + /// The configuration of the [CupertinoTextField](https://docs.flutter.io/flutter/cupertino/CupertinoTextField-class.html) + /// that the TypeAhead widget displays + final CupertinoTextFieldConfiguration textFieldConfiguration; + + /// Creates a [CupertinoTypeAheadFormField] + CupertinoTypeAheadFormField( + {Key key, + String initialValue, + bool getImmediateSuggestions: false, + @Deprecated('Use autoValidateMode parameter which provides more specific ' + 'behavior related to auto validation. ' + 'This feature was deprecated after Flutter v1.19.0.') + bool autovalidate: false, + bool enabled: true, + AutovalidateMode autovalidateMode, + FormFieldSetter onSaved, + FormFieldValidator validator, + ErrorBuilder errorBuilder, + WidgetBuilder noItemsFoundBuilder, + WidgetBuilder loadingBuilder, + Duration debounceDuration: const Duration(milliseconds: 300), + CupertinoSuggestionsBoxDecoration suggestionsBoxDecoration: + const CupertinoSuggestionsBoxDecoration(), + CupertinoSuggestionsBoxController suggestionsBoxController, + @required + SuggestionSelectionCallback onSuggestionSelected, + @required + ItemBuilder itemBuilder, + @required + SuggestionsCallback suggestionsCallback, + double suggestionsBoxVerticalOffset: 5.0, + this.textFieldConfiguration: const CupertinoTextFieldConfiguration(), + AnimationTransitionBuilder transitionBuilder, + Duration animationDuration: const Duration(milliseconds: 500), + double animationStart: 0.25, + AxisDirection direction: AxisDirection.down, + bool hideOnLoading: false, + bool hideOnEmpty: false, + bool hideOnError: false, + bool hideSuggestionsOnKeyboardHide: true, + bool keepSuggestionsOnLoading: true, + bool keepSuggestionsOnSuggestionSelected: false, + bool autoFlipDirection: false}) + : assert( + initialValue == null || textFieldConfiguration.controller == null), + super( + key: key, + onSaved: onSaved, + validator: validator, + initialValue: textFieldConfiguration.controller != null + ? textFieldConfiguration.controller.text + : (initialValue ?? ''), + enabled: enabled, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) { + final _CupertinoTypeAheadFormFieldState state = + field as _CupertinoTypeAheadFormFieldState; + + return CupertinoTypeAheadField( + getImmediateSuggestions: getImmediateSuggestions, + transitionBuilder: transitionBuilder, + errorBuilder: errorBuilder, + noItemsFoundBuilder: noItemsFoundBuilder, + loadingBuilder: loadingBuilder, + debounceDuration: debounceDuration, + suggestionsBoxDecoration: suggestionsBoxDecoration, + suggestionsBoxController: suggestionsBoxController, + textFieldConfiguration: textFieldConfiguration.copyWith( + onChanged: (text) { + state.didChange(text); + textFieldConfiguration.onChanged.call(text); + }, + controller: state._effectiveController, + ), + suggestionsBoxVerticalOffset: suggestionsBoxVerticalOffset, + onSuggestionSelected: onSuggestionSelected, + itemBuilder: itemBuilder, + suggestionsCallback: suggestionsCallback, + animationStart: animationStart, + animationDuration: animationDuration, + direction: direction, + hideOnLoading: hideOnLoading, + hideOnEmpty: hideOnEmpty, + hideOnError: hideOnError, + hideSuggestionsOnKeyboardHide: hideSuggestionsOnKeyboardHide, + keepSuggestionsOnLoading: keepSuggestionsOnLoading, + keepSuggestionsOnSuggestionSelected: + keepSuggestionsOnSuggestionSelected, + autoFlipDirection: autoFlipDirection, + ); + }); + + @override + _CupertinoTypeAheadFormFieldState createState() => + _CupertinoTypeAheadFormFieldState(); +} + +class _CupertinoTypeAheadFormFieldState extends FormFieldState { + TextEditingController _controller; + + TextEditingController get _effectiveController => + widget.textFieldConfiguration.controller ?? _controller; + + @override + CupertinoTypeAheadFormField get widget => + super.widget as CupertinoTypeAheadFormField; + + @override + void initState() { + super.initState(); + if (widget.textFieldConfiguration.controller == null) { + _controller = TextEditingController(text: widget.initialValue); + } else { + widget.textFieldConfiguration.controller + .addListener(_handleControllerChanged); + } + } + + @override + void didUpdateWidget(CupertinoTypeAheadFormField oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.textFieldConfiguration.controller != + oldWidget.textFieldConfiguration.controller) { + oldWidget.textFieldConfiguration.controller + ?.removeListener(_handleControllerChanged); + widget.textFieldConfiguration.controller + ?.addListener(_handleControllerChanged); + + if (oldWidget.textFieldConfiguration.controller != null && + widget.textFieldConfiguration.controller == null) + _controller = TextEditingController.fromValue( + oldWidget.textFieldConfiguration.controller.value); + if (widget.textFieldConfiguration.controller != null) { + setValue(widget.textFieldConfiguration.controller.text); + if (oldWidget.textFieldConfiguration.controller == null) + _controller = null; + } + } + } + + @override + void dispose() { + widget.textFieldConfiguration.controller + ?.removeListener(_handleControllerChanged); + super.dispose(); + } + + @override + void reset() { + super.reset(); + setState(() { + _effectiveController.text = widget.initialValue; + }); + } + + void _handleControllerChanged() { + // Suppress changes that originated from within this class. + // + // In the case where a controller has been passed in to this widget, we + // register this change listener. In these cases, we'll also receive change + // notifications for changes originating from within this class -- for + // example, the reset() method. In such cases, the FormField value will + // already have been set. + if (_effectiveController.text != value) + didChange(_effectiveController.text); + } +} + +/// A [CupertinoTextField](https://docs.flutter.io/flutter/cupertino/CupertinoTextField-class.html) +/// that displays a list of suggestions as the user types +/// +/// See also: +/// +/// * [TypeAheadFormField], a [FormField](https://docs.flutter.io/flutter/widgets/FormField-class.html) +/// implementation of [TypeAheadField] that allows the value to be saved, +/// validated, etc. +class CupertinoTypeAheadField extends StatefulWidget { + /// Called with the search pattern to get the search suggestions. + /// + /// This callback must not be null. It is be called by the TypeAhead widget + /// and provided with the search pattern. It should return a [List](https://api.dartlang.org/stable/2.0.0/dart-core/List-class.html) + /// of suggestions either synchronously, or asynchronously (as the result of a + /// [Future](https://api.dartlang.org/stable/dart-async/Future-class.html)). + /// Typically, the list of suggestions should not contain more than 4 or 5 + /// entries. These entries will then be provided to [itemBuilder] to display + /// the suggestions. + /// + /// Example: + /// ```dart + /// suggestionsCallback: (pattern) async { + /// return await _getSuggestions(pattern); + /// } + /// ``` + final SuggestionsCallback suggestionsCallback; + + /// Called when a suggestion is tapped. + /// + /// This callback must not be null. It is called by the TypeAhead widget and + /// provided with the value of the tapped suggestion. + /// + /// For example, you might want to navigate to a specific view when the user + /// tabs a suggestion: + /// ```dart + /// onSuggestionSelected: (suggestion) { + /// Navigator.of(context).push(MaterialPageRoute( + /// builder: (context) => SearchResult( + /// searchItem: suggestion + /// ) + /// )); + /// } + /// ``` + /// + /// Or to set the value of the text field: + /// ```dart + /// onSuggestionSelected: (suggestion) { + /// _controller.text = suggestion['name']; + /// } + /// ``` + final SuggestionSelectionCallback onSuggestionSelected; + + /// Called for each suggestion returned by [suggestionsCallback] to build the + /// corresponding widget. + /// + /// This callback must not be null. It is called by the TypeAhead widget for + /// each suggestion, and expected to build a widget to display this + /// suggestion's info. For example: + /// + /// ```dart + /// itemBuilder: (context, suggestion) { + /// return Padding( + /// padding: const EdgeInsets.all(4.0), + /// child: Text( + /// suggestion, + /// ), + /// ); + /// } + /// ``` + final ItemBuilder itemBuilder; + + /// The decoration of the material sheet that contains the suggestions. + final CupertinoSuggestionsBoxDecoration suggestionsBoxDecoration; + + /// Used to control the `_SuggestionsBox`. Allows manual control to + /// open, close, toggle, or resize the `_SuggestionsBox`. + final CupertinoSuggestionsBoxController suggestionsBoxController; + + /// The duration to wait after the user stops typing before calling + /// [suggestionsCallback] + /// + /// This is useful, because, if not set, a request for suggestions will be + /// sent for every character that the user types. + /// + /// This duration is set by default to 300 milliseconds + final Duration debounceDuration; + + /// Called when waiting for [suggestionsCallback] to return. + /// + /// It is expected to return a widget to display while waiting. + /// For example: + /// ```dart + /// (BuildContext context) { + /// return Text('Loading...'); + /// } + /// ``` + /// + /// If not specified, a [CupertinoActivityIndicator](https://docs.flutter.io/flutter/cupertino/CupertinoActivityIndicator-class.html) is shown + final WidgetBuilder loadingBuilder; + + /// Called when [suggestionsCallback] returns an empty array. + /// + /// It is expected to return a widget to display when no suggestions are + /// avaiable. + /// For example: + /// ```dart + /// (BuildContext context) { + /// return Text('No Items Found!'); + /// } + /// ``` + /// + /// If not specified, a simple text is shown + final WidgetBuilder noItemsFoundBuilder; + + /// Called when [suggestionsCallback] throws an exception. + /// + /// It is called with the error object, and expected to return a widget to + /// display when an exception is thrown + /// For example: + /// ```dart + /// (BuildContext context, error) { + /// return Text('$error'); + /// } + /// ``` + final ErrorBuilder errorBuilder; + + /// Called to display animations when [suggestionsCallback] returns suggestions + /// + /// It is provided with the suggestions box instance and the animation + /// controller, and expected to return some animation that uses the controller + /// to display the suggestion box. + /// + /// For example: + /// ```dart + /// transitionBuilder: (context, suggestionsBox, animationController) { + /// return FadeTransition( + /// child: suggestionsBox, + /// opacity: CurvedAnimation( + /// parent: animationController, + /// curve: Curves.fastOutSlowIn + /// ), + /// ); + /// } + /// ``` + /// This argument is best used with [animationDuration] and [animationStart] + /// to fully control the animation. + /// + /// To fully remove the animation, just return `suggestionsBox` + /// + /// If not specified, a [SizeTransition](https://docs.flutter.io/flutter/widgets/SizeTransition-class.html) is shown. + final AnimationTransitionBuilder transitionBuilder; + + /// The duration that [transitionBuilder] animation takes. + /// + /// This argument is best used with [transitionBuilder] and [animationStart] + /// to fully control the animation. + /// + /// Defaults to 500 milliseconds. + final Duration animationDuration; + + /// Determine the [SuggestionBox]'s direction. + /// + /// If [AxisDirection.down], the [SuggestionBox] will be below the [TextField] + /// and the [_SuggestionsList] will grow **down**. + /// + /// If [AxisDirection.up], the [SuggestionBox] will be above the [TextField] + /// and the [_SuggestionsList] will grow **up**. + /// + /// [AxisDirection.left] and [AxisDirection.right] are not allowed. + final AxisDirection direction; + + /// The value at which the [transitionBuilder] animation starts. + /// + /// This argument is best used with [transitionBuilder] and [animationDuration] + /// to fully control the animation. + /// + /// Defaults to 0.25. + final double animationStart; + + /// The configuration of the [CupertinoTextField](https://docs.flutter.io/flutter/cupertino/CupertinoTextField-class.html) + /// that the TypeAhead widget displays + final CupertinoTextFieldConfiguration textFieldConfiguration; + + /// How far below the text field should the suggestions box be + /// + /// Defaults to 5.0 + final double suggestionsBoxVerticalOffset; + + /// If set to true, suggestions will be fetched immediately when the field is + /// added to the view. + /// + /// But the suggestions box will only be shown when the field receives focus. + /// To make the field receive focus immediately, you can set the `autofocus` + /// property in the [textFieldConfiguration] to true + /// + /// Defaults to false + final bool getImmediateSuggestions; + + /// If set to true, no loading box will be shown while suggestions are + /// being fetched. [loadingBuilder] will also be ignored. + /// + /// Defaults to false. + final bool hideOnLoading; + + /// If set to true, nothing will be shown if there are no results. + /// [noItemsFoundBuilder] will also be ignored. + /// + /// Defaults to false. + final bool hideOnEmpty; + + /// If set to true, nothing will be shown if there is an error. + /// [errorBuilder] will also be ignored. + /// + /// Defaults to false. + final bool hideOnError; + + /// If set to false, the suggestions box will stay opened after + /// the keyboard is closed. + /// + /// Defaults to true. + final bool hideSuggestionsOnKeyboardHide; + + /// If set to false, the suggestions box will show a circular + /// progress indicator when retrieving suggestions. + /// + /// Defaults to true. + final bool keepSuggestionsOnLoading; + + /// If set to true, the suggestions box will remain opened even after + /// selecting a suggestion. + /// + /// Note that if this is enabled, the only way + /// to close the suggestions box is either manually via the + /// `SuggestionsBoxController` or when the user closes the software + /// keyboard if `hideSuggestionsOnKeyboardHide` is set to true. Users + /// with a physical keyboard will be unable to close the + /// box without a manual way via `SuggestionsBoxController`. + /// + /// Defaults to false. + final bool keepSuggestionsOnSuggestionSelected; + + /// If set to true, in the case where the suggestions box has less than + /// _SuggestionsBoxController.minOverlaySpace to grow in the desired [direction], the direction axis + /// will be temporarily flipped if there's more room available in the opposite + /// direction. + /// + /// Defaults to false + final bool autoFlipDirection; + + /// Creates a [CupertinoTypeAheadField] + CupertinoTypeAheadField( + {Key key, + @required this.suggestionsCallback, + @required this.itemBuilder, + @required this.onSuggestionSelected, + this.textFieldConfiguration: const CupertinoTextFieldConfiguration(), + this.suggestionsBoxDecoration: const CupertinoSuggestionsBoxDecoration(), + this.debounceDuration: const Duration(milliseconds: 300), + this.suggestionsBoxController, + this.loadingBuilder, + this.noItemsFoundBuilder, + this.errorBuilder, + this.transitionBuilder, + this.animationStart: 0.25, + this.animationDuration: const Duration(milliseconds: 500), + this.getImmediateSuggestions: false, + this.suggestionsBoxVerticalOffset: 5.0, + this.direction: AxisDirection.down, + this.hideOnLoading: false, + this.hideOnEmpty: false, + this.hideOnError: false, + this.hideSuggestionsOnKeyboardHide: true, + this.keepSuggestionsOnLoading: true, + this.keepSuggestionsOnSuggestionSelected: false, + this.autoFlipDirection: false}) + : assert(animationStart >= 0.0 && animationStart <= 1.0), + assert( + direction == AxisDirection.down || direction == AxisDirection.up), + super(key: key); + + @override + _CupertinoTypeAheadFieldState createState() => + _CupertinoTypeAheadFieldState(); +} + +class _CupertinoTypeAheadFieldState extends State> + with WidgetsBindingObserver { + FocusNode _focusNode; + TextEditingController _textEditingController; + _CupertinoSuggestionsBox _suggestionsBox; + + TextEditingController get _effectiveController => + widget.textFieldConfiguration.controller ?? _textEditingController; + + FocusNode get _effectiveFocusNode => + widget.textFieldConfiguration.focusNode ?? _focusNode; + VoidCallback _focusNodeListener; + + final LayerLink _layerLink = LayerLink(); + + // Timer that resizes the suggestion box on each tick. Only active when the user is scrolling. + Timer _resizeOnScrollTimer; + + // The rate at which the suggestion box will resize when the user is scrolling + final Duration _resizeOnScrollRefreshRate = const Duration(milliseconds: 500); + + // Will have a value if the typeahead is inside a scrollable widget + ScrollPosition _scrollPosition; + + // Keyboard detection + final Stream _keyboardVisibility = + KeyboardVisibilityController().onChange; + StreamSubscription _keyboardVisibilitySubscription; + + @override + void didChangeMetrics() { + // Catch keyboard event and orientation change; resize suggestions list + this._suggestionsBox.onChangeMetrics(); + } + + @override + void dispose() { + this._suggestionsBox.close(); + this._suggestionsBox.widgetMounted = false; + WidgetsBinding.instance.removeObserver(this); + _keyboardVisibilitySubscription.cancel(); + _effectiveFocusNode.removeListener(_focusNodeListener); + _focusNode.dispose(); + _resizeOnScrollTimer.cancel(); + _scrollPosition.removeListener(_scrollResizeListener); + _textEditingController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + + if (widget.textFieldConfiguration.controller == null) { + this._textEditingController = TextEditingController(); + } + + if (widget.textFieldConfiguration.focusNode == null) { + this._focusNode = FocusNode(); + } + + this._suggestionsBox = _CupertinoSuggestionsBox( + context, widget.direction, widget.autoFlipDirection); + widget.suggestionsBoxController?._suggestionsBox = this._suggestionsBox; + widget.suggestionsBoxController?._effectiveFocusNode = + this._effectiveFocusNode; + + this._focusNodeListener = () { + if (_effectiveFocusNode.hasFocus) { + this._suggestionsBox.open(); + } else { + this._suggestionsBox.close(); + } + }; + + this._effectiveFocusNode.addListener(_focusNodeListener); + + // hide suggestions box on keyboard closed + this._keyboardVisibilitySubscription = + _keyboardVisibility.listen((bool isVisible) { + if (widget.hideSuggestionsOnKeyboardHide && isVisible) { + _effectiveFocusNode.unfocus(); + } + }); + + WidgetsBinding.instance.addPostFrameCallback((duration) { + if (mounted) { + this._initOverlayEntry(); + // calculate initial suggestions list size + this._suggestionsBox.resize(); + + // in case we already missed the focus event + if (this._effectiveFocusNode.hasFocus) { + this._suggestionsBox.open(); + } + } + }); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + ScrollableState scrollableState = Scrollable.of(context); + if (scrollableState != null) { + // The TypeAheadField is inside a scrollable widget + _scrollPosition = scrollableState.position; + + _scrollPosition.removeListener(_scrollResizeListener); + _scrollPosition.isScrollingNotifier.addListener(_scrollResizeListener); + } + } + + void _scrollResizeListener() { + bool isScrolling = _scrollPosition.isScrollingNotifier.value; + _resizeOnScrollTimer?.cancel(); + if (isScrolling) { + // Scroll started + _resizeOnScrollTimer = + Timer.periodic(_resizeOnScrollRefreshRate, (timer) { + _suggestionsBox.resize(); + }); + } else { + // Scroll finished + _suggestionsBox.resize(); + } + } + + void _initOverlayEntry() { + this._suggestionsBox._overlayEntry = OverlayEntry(builder: (context) { + final suggestionsList = _SuggestionsList( + suggestionsBox: _suggestionsBox, + decoration: widget.suggestionsBoxDecoration, + debounceDuration: widget.debounceDuration, + controller: this._effectiveController, + loadingBuilder: widget.loadingBuilder, + noItemsFoundBuilder: widget.noItemsFoundBuilder, + errorBuilder: widget.errorBuilder, + transitionBuilder: widget.transitionBuilder, + suggestionsCallback: widget.suggestionsCallback, + animationDuration: widget.animationDuration, + animationStart: widget.animationStart, + getImmediateSuggestions: widget.getImmediateSuggestions, + onSuggestionSelected: (T selection) { + if (!widget.keepSuggestionsOnSuggestionSelected) { + this._effectiveFocusNode.unfocus(); + this._suggestionsBox.close(); + } + widget.onSuggestionSelected(selection); + }, + itemBuilder: widget.itemBuilder, + direction: _suggestionsBox.direction, + hideOnLoading: widget.hideOnLoading, + hideOnEmpty: widget.hideOnEmpty, + hideOnError: widget.hideOnError, + keepSuggestionsOnLoading: widget.keepSuggestionsOnLoading, + ); + + double w = _suggestionsBox.textBoxWidth; + if (widget.suggestionsBoxDecoration.constraints != null) { + if (widget.suggestionsBoxDecoration.constraints.minWidth != 0.0 && + widget.suggestionsBoxDecoration.constraints.maxWidth != + double.infinity) { + w = (widget.suggestionsBoxDecoration.constraints.minWidth + + widget.suggestionsBoxDecoration.constraints.maxWidth) / + 2; + } else if (widget.suggestionsBoxDecoration.constraints.minWidth != + 0.0 && + widget.suggestionsBoxDecoration.constraints.minWidth > w) { + w = widget.suggestionsBoxDecoration.constraints.minWidth; + } else if (widget.suggestionsBoxDecoration.constraints.maxWidth != + double.infinity && + widget.suggestionsBoxDecoration.constraints.maxWidth < w) { + w = widget.suggestionsBoxDecoration.constraints.maxWidth; + } + } + + return Positioned( + width: w, + child: CompositedTransformFollower( + link: this._layerLink, + showWhenUnlinked: false, + offset: Offset( + widget.suggestionsBoxDecoration.offsetX, + _suggestionsBox.direction == AxisDirection.down + ? _suggestionsBox.textBoxHeight + + widget.suggestionsBoxVerticalOffset + : _suggestionsBox.directionUpOffset), + child: _suggestionsBox.direction == AxisDirection.down + ? suggestionsList + : FractionalTranslation( + translation: + Offset(0.0, -1.0), // visually flips list to go up + child: suggestionsList, + ), + ), + ); + }); + } + + @override + Widget build(BuildContext context) { + return CompositedTransformTarget( + link: this._layerLink, + child: CupertinoTextField( + controller: this._effectiveController, + focusNode: this._effectiveFocusNode, + decoration: widget.textFieldConfiguration.decoration, + padding: widget.textFieldConfiguration.padding, + placeholder: widget.textFieldConfiguration.placeholder, + prefix: widget.textFieldConfiguration.prefix, + prefixMode: widget.textFieldConfiguration.prefixMode, + suffix: widget.textFieldConfiguration.suffix, + suffixMode: widget.textFieldConfiguration.suffixMode, + clearButtonMode: widget.textFieldConfiguration.clearButtonMode, + keyboardType: widget.textFieldConfiguration.keyboardType, + textInputAction: widget.textFieldConfiguration.textInputAction, + textCapitalization: widget.textFieldConfiguration.textCapitalization, + style: widget.textFieldConfiguration.style, + textAlign: widget.textFieldConfiguration.textAlign, + autofocus: widget.textFieldConfiguration.autofocus, + obscureText: widget.textFieldConfiguration.obscureText, + autocorrect: widget.textFieldConfiguration.autocorrect, + maxLines: widget.textFieldConfiguration.maxLines, + minLines: widget.textFieldConfiguration.minLines, + maxLength: widget.textFieldConfiguration.maxLength, + maxLengthEnforced: widget.textFieldConfiguration.maxLengthEnforced, + onChanged: widget.textFieldConfiguration.onChanged, + onEditingComplete: widget.textFieldConfiguration.onEditingComplete, + onTap: widget.textFieldConfiguration.onTap, + onSubmitted: widget.textFieldConfiguration.onSubmitted, + inputFormatters: widget.textFieldConfiguration.inputFormatters, + enabled: widget.textFieldConfiguration.enabled, + cursorWidth: widget.textFieldConfiguration.cursorWidth, + cursorRadius: widget.textFieldConfiguration.cursorRadius, + cursorColor: widget.textFieldConfiguration.cursorColor, + keyboardAppearance: widget.textFieldConfiguration.keyboardAppearance, + scrollPadding: widget.textFieldConfiguration.scrollPadding, + enableInteractiveSelection: + widget.textFieldConfiguration.enableInteractiveSelection, + ), + ); + } +} + +class _SuggestionsList extends StatefulWidget { + final _CupertinoSuggestionsBox suggestionsBox; + final TextEditingController controller; + final bool getImmediateSuggestions; + final SuggestionSelectionCallback onSuggestionSelected; + final SuggestionsCallback suggestionsCallback; + final ItemBuilder itemBuilder; + final CupertinoSuggestionsBoxDecoration decoration; + final Duration debounceDuration; + final WidgetBuilder loadingBuilder; + final WidgetBuilder noItemsFoundBuilder; + final ErrorBuilder errorBuilder; + final AnimationTransitionBuilder transitionBuilder; + final Duration animationDuration; + final double animationStart; + final AxisDirection direction; + final bool hideOnLoading; + final bool hideOnEmpty; + final bool hideOnError; + final bool keepSuggestionsOnLoading; + + _SuggestionsList({ + @required this.suggestionsBox, + this.controller, + this.getImmediateSuggestions: false, + this.onSuggestionSelected, + this.suggestionsCallback, + this.itemBuilder, + this.decoration, + this.debounceDuration, + this.loadingBuilder, + this.noItemsFoundBuilder, + this.errorBuilder, + this.transitionBuilder, + this.animationDuration, + this.animationStart, + this.direction, + this.hideOnLoading, + this.hideOnEmpty, + this.hideOnError, + this.keepSuggestionsOnLoading, + }); + + @override + _SuggestionsListState createState() => _SuggestionsListState(); +} + +class _SuggestionsListState extends State<_SuggestionsList> + with SingleTickerProviderStateMixin { + Iterable _suggestions; + bool _suggestionsValid; + VoidCallback _controllerListener; + Timer _debounceTimer; + bool _isLoading, _isQueued; + Object _error; + AnimationController _animationController; + String _lastTextValue; + + @override + void didUpdateWidget(_SuggestionsList oldWidget) { + super.didUpdateWidget(oldWidget); + _getSuggestions(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _getSuggestions(); + } + + @override + void initState() { + super.initState(); + + this._animationController = AnimationController( + vsync: this, + duration: widget.animationDuration, + ); + + this._suggestionsValid = false; + this._isLoading = false; + this._isQueued = false; + this._lastTextValue = widget.controller.text; + + if (widget.getImmediateSuggestions) { + this._getSuggestions(); + } + + this._controllerListener = () { + // If we came here because of a change in selected text, not because of + // actual change in text + if (widget.controller.text == this._lastTextValue) return; + + this._lastTextValue = widget.controller.text; + + this._debounceTimer.cancel(); + this._debounceTimer = Timer(widget.debounceDuration, () async { + if (this._debounceTimer.isActive) return; + if (_isLoading) { + _isQueued = true; + return; + } + + await this.invalidateSuggestions(); + while (_isQueued) { + _isQueued = false; + await this.invalidateSuggestions(); + } + }); + }; + + widget.controller.addListener(this._controllerListener); + } + + Future invalidateSuggestions() async { + _suggestionsValid = false; + _getSuggestions(); + } + + Future _getSuggestions() async { + if (_suggestionsValid) return; + _suggestionsValid = true; + + if (mounted) { + setState(() { + this._animationController.forward(from: 1.0); + + this._isLoading = true; + this._error = null; + }); + + Iterable suggestions; + Object error; + + try { + suggestions = await widget.suggestionsCallback(widget.controller.text); + } catch (e) { + error = e; + } + + if (this.mounted) { + // if it wasn't removed in the meantime + setState(() { + double animationStart = widget.animationStart; + // allow suggestionsCallback to return null and not throw error here + if (error != null || suggestions.isEmpty == true) { + animationStart = 1.0; + } + this._animationController.forward(from: animationStart); + + this._error = error; + this._isLoading = false; + this._suggestions = suggestions; + }); + } + } + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + bool isEmpty = + this._suggestions?.length == 0 && widget.controller.text == ""; + if ((this._suggestions == null || isEmpty) && this._isLoading == false) + return Container(); + + Widget child; + if (this._isLoading) { + if (widget.hideOnLoading) { + child = Container(height: 0); + } else { + child = createLoadingWidget(); + } + } else if (this._error != null) { + if (widget.hideOnError) { + child = Container(height: 0); + } else { + child = createErrorWidget(); + } + } else if (this._suggestions.isEmpty) { + if (widget.hideOnEmpty) { + child = Container(height: 0); + } else { + child = createNoItemsFoundWidget(); + } + } else { + child = createSuggestionsWidget(); + } + + var animationChild = widget.transitionBuilder != null + ? widget.transitionBuilder(context, child, this._animationController) + : SizeTransition( + axisAlignment: -1.0, + sizeFactor: CurvedAnimation( + parent: this._animationController, curve: Curves.fastOutSlowIn), + child: child, + ); + + BoxConstraints constraints; + if (widget.decoration.constraints == null) { + constraints = BoxConstraints( + maxHeight: widget.suggestionsBox.maxHeight, + ); + } else { + double maxHeight = min(widget.decoration.constraints.maxHeight, + widget.suggestionsBox.maxHeight); + constraints = widget.decoration.constraints.copyWith( + minHeight: min(widget.decoration.constraints.minHeight, maxHeight), + maxHeight: maxHeight, + ); + } + + return ConstrainedBox( + constraints: constraints, + child: animationChild, + ); + } + + Widget createLoadingWidget() { + Widget child; + + if (widget.keepSuggestionsOnLoading && this._suggestions != null) { + if (this._suggestions.isEmpty) { + child = createNoItemsFoundWidget(); + } else { + child = createSuggestionsWidget(); + } + } else { + child = widget.loadingBuilder != null + ? widget.loadingBuilder(context) + : Container( + decoration: BoxDecoration( + color: CupertinoColors.white, + border: Border.all( + color: CupertinoColors.extraLightBackgroundGray, + width: 1.0, + ), + ), + child: Align( + alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: CupertinoActivityIndicator(), + ), + ), + ); + } + + return child; + } + + Widget createErrorWidget() { + return widget.errorBuilder != null + ? widget.errorBuilder(context, this._error) + : Container( + decoration: BoxDecoration( + color: CupertinoColors.white, + border: Border.all( + color: CupertinoColors.extraLightBackgroundGray, + width: 1.0, + ), + ), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Text( + 'Error: ${this._error}', + textAlign: TextAlign.start, + style: TextStyle( + color: CupertinoColors.destructiveRed, + fontSize: 18.0, + ), + ), + ), + ); + } + + Widget createNoItemsFoundWidget() { + return widget.noItemsFoundBuilder != null + ? widget.noItemsFoundBuilder(context) + : Container( + decoration: BoxDecoration( + color: CupertinoColors.white, + border: Border.all( + color: CupertinoColors.extraLightBackgroundGray, + width: 1.0, + ), + ), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Text( + 'No Items Found!', + textAlign: TextAlign.start, + style: TextStyle( + color: CupertinoColors.inactiveGray, + fontSize: 18.0, + ), + ), + ), + ); + } + + Widget createSuggestionsWidget() { + Widget child = Container( + decoration: BoxDecoration( + color: widget.decoration.color != null + ? widget.decoration.color + : CupertinoColors.white, + border: widget.decoration.border != null + ? widget.decoration.border + : Border.all( + color: CupertinoColors.extraLightBackgroundGray, + width: 1.0, + ), + borderRadius: widget.decoration.borderRadius != null + ? widget.decoration.borderRadius + : null, + ), + child: ListView( + padding: EdgeInsets.zero, + primary: false, + shrinkWrap: true, + reverse: widget.suggestionsBox.direction == AxisDirection.down + ? false + : true, + // reverses the list to start at the bottom + children: this._suggestions.map((T suggestion) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + child: widget.itemBuilder(context, suggestion), + onTap: () { + widget.onSuggestionSelected(suggestion); + }, + ); + }).toList(), + ), + ); + + if (widget.decoration.hasScrollbar) { + child = CupertinoScrollbar(child: child); + } + + return child; + } +} + +/// Supply an instance of this class to the [TypeAhead.suggestionsBoxDecoration] +/// property to configure the suggestions box decoration +class CupertinoSuggestionsBoxDecoration { + /// Defines if a scrollbar will be displayed or not. + final bool hasScrollbar; + + /// The constraints to be applied to the suggestions box + final BoxConstraints constraints; + final Color color; + final BoxBorder border; + final BorderRadiusGeometry borderRadius; + + /// Adds an offset to the suggestions box + final double offsetX; + + /// Creates a [CupertinoSuggestionsBoxDecoration] + const CupertinoSuggestionsBoxDecoration( + {this.hasScrollbar: true, + this.constraints, + this.color, + this.border, + this.borderRadius, + this.offsetX: 0.0}); +} + +/// Supply an instance of this class to the [TypeAhead.textFieldConfiguration] +/// property to configure the displayed text field. See [documentation](https://docs.flutter.io/flutter/cupertino/CupertinoTextField-class.html) +/// for more information on properties. +class CupertinoTextFieldConfiguration { + final TextEditingController controller; + final FocusNode focusNode; + final BoxDecoration decoration; + final EdgeInsetsGeometry padding; + final String placeholder; + final Widget prefix; + final OverlayVisibilityMode prefixMode; + final Widget suffix; + final OverlayVisibilityMode suffixMode; + final OverlayVisibilityMode clearButtonMode; + final TextInputType keyboardType; + final TextInputAction textInputAction; + final TextCapitalization textCapitalization; + final TextStyle style; + final TextAlign textAlign; + final bool autofocus; + final bool obscureText; + final bool autocorrect; + final int maxLines; + final int minLines; + final int maxLength; + final bool maxLengthEnforced; + final ValueChanged onChanged; + final VoidCallback onEditingComplete; + final GestureTapCallback onTap; + final ValueChanged onSubmitted; + final List inputFormatters; + final bool enabled; + final bool enableSuggestions; + final double cursorWidth; + final Radius cursorRadius; + final Color cursorColor; + final Brightness keyboardAppearance; + final EdgeInsets scrollPadding; + final bool enableInteractiveSelection; + + /// Creates a CupertinoTextFieldConfiguration + const CupertinoTextFieldConfiguration({ + this.controller, + this.focusNode, + this.decoration = _kDefaultRoundedBorderDecoration, + this.padding = const EdgeInsets.all(6.0), + this.placeholder, + this.prefix, + this.prefixMode = OverlayVisibilityMode.always, + this.suffix, + this.suffixMode = OverlayVisibilityMode.always, + this.clearButtonMode = OverlayVisibilityMode.never, + this.keyboardType, + this.textInputAction, + this.textCapitalization = TextCapitalization.none, + this.style, + this.textAlign = TextAlign.start, + this.autofocus = false, + this.obscureText = false, + this.autocorrect = true, + this.maxLines = 1, + this.minLines, + this.maxLength, + this.maxLengthEnforced = true, + this.onChanged, + this.onEditingComplete, + this.onTap, + this.onSubmitted, + this.inputFormatters, + this.enabled: true, + this.enableSuggestions: true, + this.cursorWidth = 2.0, + this.cursorRadius = const Radius.circular(2.0), + this.cursorColor, + this.keyboardAppearance, + this.scrollPadding = const EdgeInsets.all(20.0), + this.enableInteractiveSelection = true, + }); + + /// Copies the [CupertinoTextFieldConfiguration] and only changes the specified properties + copyWith({ + TextEditingController controller, + FocusNode focusNode, + BoxDecoration decoration, + EdgeInsetsGeometry padding, + String placeholder, + Widget prefix, + OverlayVisibilityMode prefixMode, + Widget suffix, + OverlayVisibilityMode suffixMode, + OverlayVisibilityMode clearButtonMode, + TextInputType keyboardType, + TextInputAction textInputAction, + TextCapitalization textCapitalization, + TextStyle style, + TextAlign textAlign, + bool autofocus, + bool obscureText, + bool autocorrect, + int maxLines, + int minLines, + int maxLength, + bool maxLengthEnforced, + ValueChanged onChanged, + VoidCallback onEditingComplete, + GestureTapCallback onTap, + ValueChanged onSubmitted, + List inputFormatters, + bool enabled, + bool enableSuggestions, + double cursorWidth, + Radius cursorRadius, + Color cursorColor, + Brightness keyboardAppearance, + EdgeInsets scrollPadding, + bool enableInteractiveSelection, + }) { + return CupertinoTextFieldConfiguration( + controller: controller ?? this.controller, + focusNode: focusNode ?? this.focusNode, + decoration: decoration ?? this.decoration, + padding: padding ?? this.padding, + placeholder: placeholder ?? this.placeholder, + prefix: prefix ?? this.prefix, + prefixMode: prefixMode ?? this.prefixMode, + suffix: suffix ?? this.suffix, + suffixMode: suffixMode ?? this.suffixMode, + clearButtonMode: clearButtonMode ?? this.clearButtonMode, + keyboardType: keyboardType ?? this.keyboardType, + textInputAction: textInputAction ?? this.textInputAction, + textCapitalization: textCapitalization ?? this.textCapitalization, + style: style ?? this.style, + textAlign: textAlign ?? this.textAlign, + autofocus: autofocus ?? this.autofocus, + obscureText: obscureText ?? this.obscureText, + autocorrect: autocorrect ?? this.autocorrect, + maxLines: maxLines ?? this.maxLines, + minLines: minLines ?? this.minLines, + maxLength: maxLength ?? this.maxLength, + maxLengthEnforced: maxLengthEnforced ?? this.maxLengthEnforced, + onChanged: onChanged ?? this.onChanged, + onEditingComplete: onEditingComplete ?? this.onEditingComplete, + onTap: onTap ?? this.onTap, + onSubmitted: onSubmitted ?? this.onSubmitted, + inputFormatters: inputFormatters ?? this.inputFormatters, + enabled: enabled ?? this.enabled, + enableSuggestions: enableSuggestions ?? this.enableSuggestions, + cursorWidth: cursorWidth ?? this.cursorWidth, + cursorRadius: cursorRadius ?? this.cursorRadius, + cursorColor: cursorColor ?? this.cursorColor, + keyboardAppearance: keyboardAppearance ?? this.keyboardAppearance, + scrollPadding: scrollPadding ?? this.scrollPadding, + enableInteractiveSelection: + enableInteractiveSelection ?? this.enableInteractiveSelection, + ); + } +} + +class _CupertinoSuggestionsBox { + static const int waitMetricsTimeoutMillis = 1000; + static const double minOverlaySpace = 64.0; + + final BuildContext context; + final AxisDirection desiredDirection; + final bool autoFlipDirection; + + OverlayEntry _overlayEntry; + AxisDirection direction; + + bool isOpened = false; + bool widgetMounted = true; + double maxHeight = 300.0; + double textBoxWidth = 100.0; + double textBoxHeight = 100.0; + double directionUpOffset; + + _CupertinoSuggestionsBox(this.context, this.direction, this.autoFlipDirection) + : desiredDirection = direction; + + void open() { + if (this.isOpened) return; + assert(this._overlayEntry != null); + Overlay.of(context).insert(this._overlayEntry); + this.isOpened = true; + } + + void close() { + if (!this.isOpened) return; + assert(this._overlayEntry != null); + this._overlayEntry.remove(); + this.isOpened = false; + } + + void toggle() { + if (this.isOpened) { + this.close(); + } else { + this.open(); + } + } + + MediaQuery _findRootMediaQuery() { + MediaQuery rootMediaQuery; + context.visitAncestorElements((element) { + if (element.widget is MediaQuery) { + rootMediaQuery = element.widget as MediaQuery; + } + return true; + }); + + return rootMediaQuery; + } + + /// Delays until the keyboard has toggled or the orientation has fully changed + Future _waitChangeMetrics() async { + if (widgetMounted) { + // initial viewInsets which are before the keyboard is toggled + EdgeInsets initial = MediaQuery.of(context).viewInsets; + // initial MediaQuery for orientation change + MediaQuery initialRootMediaQuery = _findRootMediaQuery(); + + int timer = 0; + // viewInsets or MediaQuery have changed once keyboard has toggled or orientation has changed + while (widgetMounted && timer < waitMetricsTimeoutMillis) { + // double: reduce delay if showDialog ever exposes detection of animation end + await Future.delayed(const Duration(milliseconds: 170)); + timer += 170; + + if (widgetMounted && + (MediaQuery.of(context).viewInsets != initial || + _findRootMediaQuery() != initialRootMediaQuery)) { + return true; + } + } + } + + return false; + } + + void resize() { + // check to see if widget is still mounted + // user may have closed the widget with the keyboard still open + if (widgetMounted) { + _adjustMaxHeightAndOrientation(); + _overlayEntry.markNeedsBuild(); + } + } + + // See if there's enough room in the desired direction for the overlay to display + // correctly. If not, try the opposite direction if things look more roomy there + void _adjustMaxHeightAndOrientation() { + CupertinoTypeAheadField widget = context.widget as CupertinoTypeAheadField; + + RenderBox box = context.findRenderObject() as RenderBox; + textBoxWidth = box.size.width; + textBoxHeight = box.size.height; + + // top of text box + double textBoxAbsY = box.localToGlobal(Offset.zero).dy; + + // height of window + double windowHeight = MediaQuery.of(context).size.height; + + // we need to find the root MediaQuery for the unsafe area height + // we cannot use BuildContext.ancestorWidgetOfExactType because + // widgets like SafeArea creates a new MediaQuery with the padding removed + MediaQuery rootMediaQuery = _findRootMediaQuery(); + + // height of keyboard + double keyboardHeight = rootMediaQuery.data.viewInsets.bottom; + + double maxHDesired = _calculateMaxHeight(desiredDirection, box, widget, + windowHeight, rootMediaQuery, keyboardHeight, textBoxAbsY); + + // if there's enough room in the desired direction, update the direction and the max height + if (maxHDesired >= minOverlaySpace || !autoFlipDirection) { + direction = desiredDirection; + maxHeight = maxHDesired; + } else { + // There's not enough room in the desired direction so see how much room is in the opposite direction + AxisDirection flipped = flipAxisDirection(desiredDirection); + double maxHFlipped = _calculateMaxHeight(flipped, box, widget, + windowHeight, rootMediaQuery, keyboardHeight, textBoxAbsY); + + // if there's more room in this opposite direction, update the direction and maxHeight + if (maxHFlipped > maxHDesired) { + direction = flipped; + maxHeight = maxHFlipped; + } + } + + if (maxHeight < 0) maxHeight = 0; + } + + double _calculateMaxHeight( + AxisDirection direction, + RenderBox box, + CupertinoTypeAheadField widget, + double windowHeight, + MediaQuery rootMediaQuery, + double keyboardHeight, + double textBoxAbsY) { + return direction == AxisDirection.down + ? _calculateMaxHeightDown(box, widget, windowHeight, rootMediaQuery, + keyboardHeight, textBoxAbsY) + : _calculateMaxHeightUp(box, widget, windowHeight, rootMediaQuery, + keyboardHeight, textBoxAbsY); + } + + double _calculateMaxHeightDown( + RenderBox box, + CupertinoTypeAheadField widget, + double windowHeight, + MediaQuery rootMediaQuery, + double keyboardHeight, + double textBoxAbsY) { + // unsafe area, ie: iPhone X 'home button' + // keyboardHeight includes unsafeAreaHeight, if keyboard is showing, set to 0 + double unsafeAreaHeight = + keyboardHeight == 0 ? rootMediaQuery.data.padding.bottom : 0; + + return windowHeight - + keyboardHeight - + unsafeAreaHeight - + textBoxHeight - + textBoxAbsY - + 2 * widget.suggestionsBoxVerticalOffset; + } + + double _calculateMaxHeightUp( + RenderBox box, + CupertinoTypeAheadField widget, + double windowHeight, + MediaQuery rootMediaQuery, + double keyboardHeight, + double textBoxAbsY) { + // recalculate keyboard absolute y value + double keyboardAbsY = windowHeight - keyboardHeight; + + directionUpOffset = textBoxAbsY > keyboardAbsY + ? keyboardAbsY - textBoxAbsY - widget.suggestionsBoxVerticalOffset + : -widget.suggestionsBoxVerticalOffset; + + // unsafe area, ie: iPhone X notch + double unsafeAreaHeight = rootMediaQuery.data.padding.top; + + return textBoxAbsY > keyboardAbsY + ? keyboardAbsY - + unsafeAreaHeight - + 2 * widget.suggestionsBoxVerticalOffset + : textBoxAbsY - + unsafeAreaHeight - + 2 * widget.suggestionsBoxVerticalOffset; + } + + Future onChangeMetrics() async { + if (await _waitChangeMetrics()) { + resize(); + } + } +} + +/// Supply an instance of this class to the [TypeAhead.suggestionsBoxController] +/// property to manually control the suggestions box +class CupertinoSuggestionsBoxController { + _CupertinoSuggestionsBox _suggestionsBox; + FocusNode _effectiveFocusNode; + + /// Opens the suggestions box + void open() { + _effectiveFocusNode.requestFocus(); + } + + /// Closes the suggestions box + void close() { + _effectiveFocusNode.unfocus(); + } + + /// Opens the suggestions box if closed and vice-versa + void toggle() { + if (_suggestionsBox.isOpened) { + close(); + } else { + open(); + } + } + + /// Recalculates the height of the suggestions box + void resize() { + _suggestionsBox.resize(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/typeahed/src/flutter_typeahead.dart b/FlutterHelper/flutter_helper/lib/samples/typeahed/src/flutter_typeahead.dart new file mode 100644 index 00000000..3b2eff47 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/typeahed/src/flutter_typeahead.dart @@ -0,0 +1,1823 @@ +/// # Flutter TypeAhead +/// A TypeAhead widget for Flutter, where you can show suggestions to +/// users as they type +/// +/// ## Features +/// * Shows suggestions in an overlay that floats on top of other widgets +/// * Allows you to specify what the suggestions will look like through a +/// builder function +/// * Allows you to specify what happens when the user taps a suggestion +/// * Accepts all the parameters that traditional TextFields accept, like +/// decoration, custom TextEditingController, text styling, etc. +/// * Provides two versions, a normal version and a [FormField](https://docs.flutter.io/flutter/widgets/FormField-class.html) +/// version that accepts validation, submitting, etc. +/// * Provides high customizability; you can customize the suggestion box decoration, +/// the loading bar, the animation, the debounce duration, etc. +/// +/// ## Installation +/// See the [installation instructions on pub](https://pub.dartlang.org/packages/flutter_typeahead#-installing-tab-). +/// +/// ## Usage examples +/// You can import the package with: +/// ```dart +/// import 'package:flutter_typeahead/flutter_typeahead.dart'; +/// ``` +/// +/// and then use it as follows: +/// +/// ### Example 1: +/// ```dart +/// TypeAheadField( +/// textFieldConfiguration: TextFieldConfiguration( +/// autofocus: true, +/// style: DefaultTextStyle.of(context).style.copyWith( +/// fontStyle: FontStyle.italic +/// ), +/// decoration: InputDecoration( +/// border: OutlineInputBorder() +/// ) +/// ), +/// suggestionsCallback: (pattern) async { +/// return await BackendService.getSuggestions(pattern); +/// }, +/// itemBuilder: (context, suggestion) { +/// return ListTile( +/// leading: Icon(Icons.shopping_cart), +/// title: Text(suggestion['name']), +/// subtitle: Text('\$${suggestion['price']}'), +/// ); +/// }, +/// onSuggestionSelected: (suggestion) { +/// Navigator.of(context).push(MaterialPageRoute( +/// builder: (context) => ProductPage(product: suggestion) +/// )); +/// }, +/// ) +/// ``` +/// In the code above, the `textFieldConfiguration` property allows us to +/// configure the displayed `TextField` as we want. In this example, we are +/// configuring the `autofocus`, `style` and `decoration` properties. +/// +/// The `suggestionsCallback` is called with the search string that the user +/// types, and is expected to return a `List` of data either synchronously or +/// asynchronously. In this example, we are calling an asynchronous function +/// called `BackendService.getSuggestions` which fetches the list of +/// suggestions. +/// +/// The `itemBuilder` is called to build a widget for each suggestion. +/// In this example, we build a simple `ListTile` that shows the name and the +/// price of the item. Please note that you shouldn't provide an `onTap` +/// callback here. The TypeAhead widget takes care of that. +/// +/// The `onSuggestionSelected` is a callback called when the user taps a +/// suggestion. In this example, when the user taps a +/// suggestion, we navigate to a page that shows us the information of the +/// tapped product. +/// +/// ### Example 2: +/// Here's another example, where we use the TypeAheadFormField inside a `Form`: +/// ```dart +/// final GlobalKey _formKey = GlobalKey(); +/// final TextEditingController _typeAheadController = TextEditingController(); +/// String _selectedCity; +/// ... +/// Form( +/// key: this._formKey, +/// child: Padding( +/// padding: EdgeInsets.all(32.0), +/// child: Column( +/// children: [ +/// Text( +/// 'What is your favorite city?' +/// ), +/// TypeAheadFormField( +/// textFieldConfiguration: TextFieldConfiguration( +/// controller: this._typeAheadController, +/// decoration: InputDecoration( +/// labelText: 'City' +/// ) +/// ), +/// suggestionsCallback: (pattern) { +/// return CitiesService.getSuggestions(pattern); +/// }, +/// itemBuilder: (context, suggestion) { +/// return ListTile( +/// title: Text(suggestion), +/// ); +/// }, +/// transitionBuilder: (context, suggestionsBox, controller) { +/// return suggestionsBox; +/// }, +/// onSuggestionSelected: (suggestion) { +/// this._typeAheadController.text = suggestion; +/// }, +/// validator: (value) { +/// if (value.isEmpty) { +/// return 'Please select a city'; +/// } +/// }, +/// onSaved: (value) => this._selectedCity = value, +/// ), +/// SizedBox(height: 10.0,), +/// RaisedButton( +/// child: Text('Submit'), +/// onPressed: () { +/// if (this._formKey.currentState.validate()) { +/// this._formKey.currentState.save(); +/// Scaffold.of(context).showSnackBar(SnackBar( +/// content: Text('Your Favorite City is ${this._selectedCity}') +/// )); +/// } +/// }, +/// ) +/// ], +/// ), +/// ), +/// ) +/// ``` +/// Here, we assign to the `controller` property of the `textFieldConfiguration` +/// a `TextEditingController` that we call `_typeAheadController`. +/// We use this controller in the `onSuggestionSelected` callback to set the +/// value of the `TextField` to the selected suggestion. +/// +/// The `validator` callback can be used like any `FormField.validator` +/// function. In our example, it checks whether a value has been entered, +/// and displays an error message if not. The `onSaved` callback is used to +/// save the value of the field to the `_selectedCity` member variable. +/// +/// The `transitionBuilder` allows us to customize the animation of the +/// suggestion box. In this example, we are returning the suggestionsBox +/// immediately, meaning that we don't want any animation. +/// +/// ## Customizations +/// TypeAhead widgets consist of a TextField and a suggestion box that shows +/// as the user types. Both are highly customizable +/// +/// ### Customizing the TextField +/// You can customize the text field using the `textFieldConfiguration` property. +/// You provide this property with an instance of `TextFieldConfiguration`, +/// which allows you to configure all the usual properties of `TextField`, like +/// `decoration`, `style`, `controller`, `focusNode`, `autofocus`, `enabled`, +/// etc. +/// +/// ### Customizing the Suggestions Box +/// TypeAhead provides default configurations for the suggestions box. You can, +/// however, override most of them. +/// +/// #### Customizing the loader, the error and the "no items found" message +/// You can use the [loadingBuilder], [errorBuilder] and [noItemsFoundBuilder] to +/// customize their corresponding widgets. For example, to show a custom error +/// widget: +/// ```dart +/// errorBuilder: (BuildContext context, Object error) => +/// Text( +/// '$error', +/// style: TextStyle( +/// color: Theme.of(context).errorColor +/// ) +/// ) +/// ``` +/// #### Customizing the animation +/// You can customize the suggestion box animation through 3 parameters: the +/// `animationDuration`, the `animationStart`, and the `transitionBuilder`. +/// +/// The `animationDuration` specifies how long the animation should take, while the +/// `animationStart` specified what point (between 0.0 and 1.0) the animation +/// should start from. The `transitionBuilder` accepts the `suggestionsBox` and +/// `animationController` as parameters, and should return a widget that uses +/// the `animationController` to animate the display of the `suggestionsBox`. +/// For example: +/// ```dart +/// transitionBuilder: (context, suggestionsBox, animationController) => +/// FadeTransition( +/// child: suggestionsBox, +/// opacity: CurvedAnimation( +/// parent: animationController, +/// curve: Curves.fastOutSlowIn +/// ), +/// ) +/// ``` +/// This uses [FadeTransition](https://docs.flutter.io/flutter/widgets/FadeTransition-class.html) +/// to fade the `suggestionsBox` into the view. Note how the +/// `animationController` was provided as the parent of the animation. +/// +/// In order to fully remove the animation, `transitionBuilder` should simply +/// return the `suggestionsBox`. This callback could also be used to wrap the +/// `suggestionsBox` with any desired widgets, not necessarily for animation. +/// +/// #### Customizing the debounce duration +/// The suggestions box does not fire for each character the user types. Instead, +/// we wait until the user is idle for a duration of time, and then call the +/// `suggestionsCallback`. The duration defaults to 300 milliseconds, but can be +/// configured using the `debounceDuration` parameter. +/// +/// #### Customizing the offset of the suggestions box +/// By default, the suggestions box is displayed 5 pixels below the `TextField`. +/// You can change this by changing the `suggestionsBoxVerticalOffset` property. +/// +/// #### Customizing the decoration of the suggestions box +/// You can also customize the decoration of the suggestions box using the +/// `suggestionsBoxDecoration` property. For example, to remove the elevation +/// of the suggestions box, you can write: +/// ```dart +/// suggestionsBoxDecoration: SuggestionsBoxDecoration( +/// elevation: 0.0 +/// ) +/// ``` +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; + +import 'typedef.dart'; + +/// A [FormField](https://docs.flutter.io/flutter/widgets/FormField-class.html) +/// implementation of [TypeAheadField], that allows the value to be saved, +/// validated, etc. +/// +/// See also: +/// +/// * [TypeAheadField], A [TextField](https://docs.flutter.io/flutter/material/TextField-class.html) +/// that displays a list of suggestions as the user types +class TypeAheadFormField extends FormField { + /// The configuration of the [TextField](https://docs.flutter.io/flutter/material/TextField-class.html) + /// that the TypeAhead widget displays + final TextFieldConfiguration textFieldConfiguration; + + /// Creates a [TypeAheadFormField] + TypeAheadFormField( + {Key key, + String initialValue, + bool getImmediateSuggestions: false, + @Deprecated('Use autovalidateMode parameter which provides more specific ' + 'behavior related to auto validation. ' + 'This feature was deprecated after Flutter v1.19.0.') + bool autovalidate: false, + bool enabled: true, + AutovalidateMode autovalidateMode: AutovalidateMode.disabled, + FormFieldSetter onSaved, + FormFieldValidator validator, + ErrorBuilder errorBuilder, + WidgetBuilder noItemsFoundBuilder, + WidgetBuilder loadingBuilder, + Duration debounceDuration: const Duration(milliseconds: 300), + SuggestionsBoxDecoration suggestionsBoxDecoration: + const SuggestionsBoxDecoration(), + SuggestionsBoxController suggestionsBoxController, + @required + SuggestionSelectionCallback onSuggestionSelected, + @required + ItemBuilder itemBuilder, + @required + SuggestionsCallback suggestionsCallback, + double suggestionsBoxVerticalOffset: 5.0, + this.textFieldConfiguration: const TextFieldConfiguration(), + AnimationTransitionBuilder transitionBuilder, + Duration animationDuration: const Duration(milliseconds: 500), + double animationStart: 0.25, + AxisDirection direction: AxisDirection.down, + bool hideOnLoading: false, + bool hideOnEmpty: false, + bool hideOnError: false, + bool hideSuggestionsOnKeyboardHide: true, + bool keepSuggestionsOnLoading: true, + bool keepSuggestionsOnSuggestionSelected: false, + bool autoFlipDirection: false, + bool hideKeyboard: false}) + : assert( + initialValue == null || textFieldConfiguration.controller == null), + super( + key: key, + onSaved: onSaved, + validator: validator, + initialValue: textFieldConfiguration.controller != null + ? textFieldConfiguration.controller.text + : (initialValue ?? ''), + enabled: enabled, + autovalidateMode: autovalidateMode, + builder: (FormFieldState field) { + final _TypeAheadFormFieldState state = + field as _TypeAheadFormFieldState; + + return TypeAheadField( + getImmediateSuggestions: getImmediateSuggestions, + transitionBuilder: transitionBuilder, + errorBuilder: errorBuilder, + noItemsFoundBuilder: noItemsFoundBuilder, + loadingBuilder: loadingBuilder, + debounceDuration: debounceDuration, + suggestionsBoxDecoration: suggestionsBoxDecoration, + suggestionsBoxController: suggestionsBoxController, + textFieldConfiguration: textFieldConfiguration.copyWith( + decoration: textFieldConfiguration.decoration + .copyWith(errorText: state.errorText), + onChanged: (text) { + state.didChange(text); + textFieldConfiguration.onChanged?.call(text); + }, + controller: state._effectiveController, + ), + suggestionsBoxVerticalOffset: suggestionsBoxVerticalOffset, + onSuggestionSelected: onSuggestionSelected, + itemBuilder: itemBuilder, + suggestionsCallback: suggestionsCallback, + animationStart: animationStart, + animationDuration: animationDuration, + direction: direction, + hideOnLoading: hideOnLoading, + hideOnEmpty: hideOnEmpty, + hideOnError: hideOnError, + hideSuggestionsOnKeyboardHide: hideSuggestionsOnKeyboardHide, + keepSuggestionsOnLoading: keepSuggestionsOnLoading, + keepSuggestionsOnSuggestionSelected: + keepSuggestionsOnSuggestionSelected, + autoFlipDirection: autoFlipDirection, + hideKeyboard: hideKeyboard); + }); + + @override + _TypeAheadFormFieldState createState() => _TypeAheadFormFieldState(); +} + +class _TypeAheadFormFieldState extends FormFieldState { + TextEditingController _controller; + + TextEditingController get _effectiveController => + widget.textFieldConfiguration.controller ?? _controller; + + @override + TypeAheadFormField get widget => super.widget as TypeAheadFormField; + + @override + void initState() { + super.initState(); + if (widget.textFieldConfiguration.controller == null) { + _controller = TextEditingController(text: widget.initialValue); + } else { + widget.textFieldConfiguration.controller + .addListener(_handleControllerChanged); + } + } + + @override + void didUpdateWidget(TypeAheadFormField oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.textFieldConfiguration.controller != + oldWidget.textFieldConfiguration.controller) { + oldWidget.textFieldConfiguration.controller + ?.removeListener(_handleControllerChanged); + widget.textFieldConfiguration.controller + ?.addListener(_handleControllerChanged); + + if (oldWidget.textFieldConfiguration.controller != null && + widget.textFieldConfiguration.controller == null) + _controller = TextEditingController.fromValue( + oldWidget.textFieldConfiguration.controller.value); + if (widget.textFieldConfiguration.controller != null) { + setValue(widget.textFieldConfiguration.controller.text); + if (oldWidget.textFieldConfiguration.controller == null) + _controller = null; + } + } + } + + @override + void dispose() { + widget.textFieldConfiguration.controller + ?.removeListener(_handleControllerChanged); + super.dispose(); + } + + @override + void reset() { + super.reset(); + setState(() { + _effectiveController.text = widget.initialValue; + }); + } + + void _handleControllerChanged() { + // Suppress changes that originated from within this class. + // + // In the case where a controller has been passed in to this widget, we + // register this change listener. In these cases, we'll also receive change + // notifications for changes originating from within this class -- for + // example, the reset() method. In such cases, the FormField value will + // already have been set. + if (_effectiveController.text != value) + didChange(_effectiveController.text); + } +} + +/// A [TextField](https://docs.flutter.io/flutter/material/TextField-class.html) +/// that displays a list of suggestions as the user types +/// +/// See also: +/// +/// * [TypeAheadFormField], a [FormField](https://docs.flutter.io/flutter/widgets/FormField-class.html) +/// implementation of [TypeAheadField] that allows the value to be saved, +/// validated, etc. +class TypeAheadField extends StatefulWidget { + /// Called with the search pattern to get the search suggestions. + /// + /// This callback must not be null. It is be called by the TypeAhead widget + /// and provided with the search pattern. It should return a [List](https://api.dartlang.org/stable/2.0.0/dart-core/List-class.html) + /// of suggestions either synchronously, or asynchronously (as the result of a + /// [Future](https://api.dartlang.org/stable/dart-async/Future-class.html)). + /// Typically, the list of suggestions should not contain more than 4 or 5 + /// entries. These entries will then be provided to [itemBuilder] to display + /// the suggestions. + /// + /// Example: + /// ```dart + /// suggestionsCallback: (pattern) async { + /// return await _getSuggestions(pattern); + /// } + /// ``` + final SuggestionsCallback suggestionsCallback; + + /// Called when a suggestion is tapped. + /// + /// This callback must not be null. It is called by the TypeAhead widget and + /// provided with the value of the tapped suggestion. + /// + /// For example, you might want to navigate to a specific view when the user + /// tabs a suggestion: + /// ```dart + /// onSuggestionSelected: (suggestion) { + /// Navigator.of(context).push(MaterialPageRoute( + /// builder: (context) => SearchResult( + /// searchItem: suggestion + /// ) + /// )); + /// } + /// ``` + /// + /// Or to set the value of the text field: + /// ```dart + /// onSuggestionSelected: (suggestion) { + /// _controller.text = suggestion['name']; + /// } + /// ``` + final SuggestionSelectionCallback onSuggestionSelected; + + /// Called for each suggestion returned by [suggestionsCallback] to build the + /// corresponding widget. + /// + /// This callback must not be null. It is called by the TypeAhead widget for + /// each suggestion, and expected to build a widget to display this + /// suggestion's info. For example: + /// + /// ```dart + /// itemBuilder: (context, suggestion) { + /// return ListTile( + /// title: Text(suggestion['name']), + /// subtitle: Text('USD' + suggestion['price'].toString()) + /// ); + /// } + /// ``` + final ItemBuilder itemBuilder; + + /// The decoration of the material sheet that contains the suggestions. + /// + /// If null, default decoration with an elevation of 4.0 is used + final SuggestionsBoxDecoration suggestionsBoxDecoration; + + /// Used to control the `_SuggestionsBox`. Allows manual control to + /// open, close, toggle, or resize the `_SuggestionsBox`. + final SuggestionsBoxController suggestionsBoxController; + + /// The duration to wait after the user stops typing before calling + /// [suggestionsCallback] + /// + /// This is useful, because, if not set, a request for suggestions will be + /// sent for every character that the user types. + /// + /// This duration is set by default to 300 milliseconds + final Duration debounceDuration; + + /// Called when waiting for [suggestionsCallback] to return. + /// + /// It is expected to return a widget to display while waiting. + /// For example: + /// ```dart + /// (BuildContext context) { + /// return Text('Loading...'); + /// } + /// ``` + /// + /// If not specified, a [CircularProgressIndicator](https://docs.flutter.io/flutter/material/CircularProgressIndicator-class.html) is shown + final WidgetBuilder loadingBuilder; + + /// Called when [suggestionsCallback] returns an empty array. + /// + /// It is expected to return a widget to display when no suggestions are + /// avaiable. + /// For example: + /// ```dart + /// (BuildContext context) { + /// return Text('No Items Found!'); + /// } + /// ``` + /// + /// If not specified, a simple text is shown + final WidgetBuilder noItemsFoundBuilder; + + /// Called when [suggestionsCallback] throws an exception. + /// + /// It is called with the error object, and expected to return a widget to + /// display when an exception is thrown + /// For example: + /// ```dart + /// (BuildContext context, error) { + /// return Text('$error'); + /// } + /// ``` + /// + /// If not specified, the error is shown in [ThemeData.errorColor](https://docs.flutter.io/flutter/material/ThemeData/errorColor.html) + final ErrorBuilder errorBuilder; + + /// Called to display animations when [suggestionsCallback] returns suggestions + /// + /// It is provided with the suggestions box instance and the animation + /// controller, and expected to return some animation that uses the controller + /// to display the suggestion box. + /// + /// For example: + /// ```dart + /// transitionBuilder: (context, suggestionsBox, animationController) { + /// return FadeTransition( + /// child: suggestionsBox, + /// opacity: CurvedAnimation( + /// parent: animationController, + /// curve: Curves.fastOutSlowIn + /// ), + /// ); + /// } + /// ``` + /// This argument is best used with [animationDuration] and [animationStart] + /// to fully control the animation. + /// + /// To fully remove the animation, just return `suggestionsBox` + /// + /// If not specified, a [SizeTransition](https://docs.flutter.io/flutter/widgets/SizeTransition-class.html) is shown. + final AnimationTransitionBuilder transitionBuilder; + + /// The duration that [transitionBuilder] animation takes. + /// + /// This argument is best used with [transitionBuilder] and [animationStart] + /// to fully control the animation. + /// + /// Defaults to 500 milliseconds. + final Duration animationDuration; + + /// Determine the [SuggestionBox]'s direction. + /// + /// If [AxisDirection.down], the [SuggestionBox] will be below the [TextField] + /// and the [_SuggestionsList] will grow **down**. + /// + /// If [AxisDirection.up], the [SuggestionBox] will be above the [TextField] + /// and the [_SuggestionsList] will grow **up**. + /// + /// [AxisDirection.left] and [AxisDirection.right] are not allowed. + final AxisDirection direction; + + /// The value at which the [transitionBuilder] animation starts. + /// + /// This argument is best used with [transitionBuilder] and [animationDuration] + /// to fully control the animation. + /// + /// Defaults to 0.25. + final double animationStart; + + /// The configuration of the [TextField](https://docs.flutter.io/flutter/material/TextField-class.html) + /// that the TypeAhead widget displays + final TextFieldConfiguration textFieldConfiguration; + + /// How far below the text field should the suggestions box be + /// + /// Defaults to 5.0 + final double suggestionsBoxVerticalOffset; + + /// If set to true, suggestions will be fetched immediately when the field is + /// added to the view. + /// + /// But the suggestions box will only be shown when the field receives focus. + /// To make the field receive focus immediately, you can set the `autofocus` + /// property in the [textFieldConfiguration] to true + /// + /// Defaults to false + final bool getImmediateSuggestions; + + /// If set to true, no loading box will be shown while suggestions are + /// being fetched. [loadingBuilder] will also be ignored. + /// + /// Defaults to false. + final bool hideOnLoading; + + /// If set to true, nothing will be shown if there are no results. + /// [noItemsFoundBuilder] will also be ignored. + /// + /// Defaults to false. + final bool hideOnEmpty; + + /// If set to true, nothing will be shown if there is an error. + /// [errorBuilder] will also be ignored. + /// + /// Defaults to false. + final bool hideOnError; + + /// If set to false, the suggestions box will stay opened after + /// the keyboard is closed. + /// + /// Defaults to true. + final bool hideSuggestionsOnKeyboardHide; + + /// If set to false, the suggestions box will show a circular + /// progress indicator when retrieving suggestions. + /// + /// Defaults to true. + final bool keepSuggestionsOnLoading; + + /// If set to true, the suggestions box will remain opened even after + /// selecting a suggestion. + /// + /// Note that if this is enabled, the only way + /// to close the suggestions box is either manually via the + /// `SuggestionsBoxController` or when the user closes the software + /// keyboard if `hideSuggestionsOnKeyboardHide` is set to true. Users + /// with a physical keyboard will be unable to close the + /// box without a manual way via `SuggestionsBoxController`. + /// + /// Defaults to false. + final bool keepSuggestionsOnSuggestionSelected; + + /// If set to true, in the case where the suggestions box has less than + /// _SuggestionsBoxController.minOverlaySpace to grow in the desired [direction], the direction axis + /// will be temporarily flipped if there's more room available in the opposite + /// direction. + /// + /// Defaults to false + final bool autoFlipDirection; + final bool hideKeyboard; + + /// Creates a [TypeAheadField] + TypeAheadField( + {Key key, + @required this.suggestionsCallback, + @required this.itemBuilder, + @required this.onSuggestionSelected, + this.textFieldConfiguration: const TextFieldConfiguration(), + this.suggestionsBoxDecoration: const SuggestionsBoxDecoration(), + this.debounceDuration: const Duration(milliseconds: 300), + this.suggestionsBoxController, + this.loadingBuilder, + this.noItemsFoundBuilder, + this.errorBuilder, + this.transitionBuilder, + this.animationStart: 0.25, + this.animationDuration: const Duration(milliseconds: 500), + this.getImmediateSuggestions: false, + this.suggestionsBoxVerticalOffset: 5.0, + this.direction: AxisDirection.down, + this.hideOnLoading: false, + this.hideOnEmpty: false, + this.hideOnError: false, + this.hideSuggestionsOnKeyboardHide: true, + this.keepSuggestionsOnLoading: true, + this.keepSuggestionsOnSuggestionSelected: false, + this.autoFlipDirection: false, + this.hideKeyboard: false}) + : assert(animationStart >= 0.0 && animationStart <= 1.0), + assert( + direction == AxisDirection.down || direction == AxisDirection.up), + super(key: key); + + @override + _TypeAheadFieldState createState() => _TypeAheadFieldState(); +} + +class _TypeAheadFieldState extends State> + with WidgetsBindingObserver { + FocusNode _focusNode; + TextEditingController _textEditingController; + _SuggestionsBox _suggestionsBox; + + TextEditingController get _effectiveController => + widget.textFieldConfiguration.controller ?? _textEditingController; + + FocusNode get _effectiveFocusNode => + widget.textFieldConfiguration.focusNode ?? _focusNode; + VoidCallback _focusNodeListener; + + final LayerLink _layerLink = LayerLink(); + + // Timer that resizes the suggestion box on each tick. Only active when the user is scrolling. + Timer _resizeOnScrollTimer; + + // The rate at which the suggestion box will resize when the user is scrolling + final Duration _resizeOnScrollRefreshRate = const Duration(milliseconds: 500); + + // Will have a value if the typeahead is inside a scrollable widget + ScrollPosition _scrollPosition; + + // Keyboard detection + final Stream _keyboardVisibility = + KeyboardVisibilityController().onChange; + StreamSubscription _keyboardVisibilitySubscription; + + @override + void didChangeMetrics() { + // Catch keyboard event and orientation change; resize suggestions list + this._suggestionsBox.onChangeMetrics(); + } + + @override + void dispose() { + this._suggestionsBox.close(); + this._suggestionsBox.widgetMounted = false; + WidgetsBinding.instance.removeObserver(this); + _keyboardVisibilitySubscription.cancel(); + _effectiveFocusNode.removeListener(_focusNodeListener); + _focusNode.dispose(); + _resizeOnScrollTimer?.cancel(); + _scrollPosition?.removeListener(_scrollResizeListener); + _textEditingController?.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + + if (widget.textFieldConfiguration.controller == null) { + this._textEditingController = TextEditingController(); + } + + if (widget.textFieldConfiguration.focusNode == null) { + this._focusNode = FocusNode(); + } + + this._suggestionsBox = + _SuggestionsBox(context, widget.direction, widget.autoFlipDirection); + widget.suggestionsBoxController?._suggestionsBox = this._suggestionsBox; + widget.suggestionsBoxController?._effectiveFocusNode = + this._effectiveFocusNode; + + this._focusNodeListener = () { + if (_effectiveFocusNode.hasFocus) { + this._suggestionsBox.open(); + } else { + this._suggestionsBox.close(); + } + }; + + this._effectiveFocusNode.addListener(_focusNodeListener); + + // hide suggestions box on keyboard closed + this._keyboardVisibilitySubscription = + _keyboardVisibility.listen((bool isVisible) { + if (widget.hideSuggestionsOnKeyboardHide && isVisible) { + _effectiveFocusNode.unfocus(); + } + }); + + WidgetsBinding.instance.addPostFrameCallback((duration) { + if (mounted) { + this._initOverlayEntry(); + // calculate initial suggestions list size + this._suggestionsBox.resize(); + + // in case we already missed the focus event + if (this._effectiveFocusNode.hasFocus) { + this._suggestionsBox.open(); + } + } + }); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + ScrollableState scrollableState = Scrollable.of(context); + if (scrollableState != null) { + // The TypeAheadField is inside a scrollable widget + _scrollPosition = scrollableState.position; + + _scrollPosition.removeListener(_scrollResizeListener); + _scrollPosition.isScrollingNotifier.addListener(_scrollResizeListener); + } + } + + void _scrollResizeListener() { + bool isScrolling = _scrollPosition.isScrollingNotifier.value; + _resizeOnScrollTimer?.cancel(); + if (isScrolling) { + // Scroll started + _resizeOnScrollTimer = + Timer.periodic(_resizeOnScrollRefreshRate, (timer) { + _suggestionsBox.resize(); + }); + } else { + // Scroll finished + _suggestionsBox.resize(); + } + } + + void _initOverlayEntry() { + this._suggestionsBox._overlayEntry = OverlayEntry(builder: (context) { + final suggestionsList = _SuggestionsList( + suggestionsBox: _suggestionsBox, + decoration: widget.suggestionsBoxDecoration, + debounceDuration: widget.debounceDuration, + controller: this._effectiveController, + loadingBuilder: widget.loadingBuilder, + noItemsFoundBuilder: widget.noItemsFoundBuilder, + errorBuilder: widget.errorBuilder, + transitionBuilder: widget.transitionBuilder, + suggestionsCallback: widget.suggestionsCallback, + animationDuration: widget.animationDuration, + animationStart: widget.animationStart, + getImmediateSuggestions: widget.getImmediateSuggestions, + onSuggestionSelected: (T selection) { + if (!widget.keepSuggestionsOnSuggestionSelected) { + this._effectiveFocusNode.unfocus(); + this._suggestionsBox.close(); + } + widget.onSuggestionSelected(selection); + }, + itemBuilder: widget.itemBuilder, + direction: _suggestionsBox.direction, + hideOnLoading: widget.hideOnLoading, + hideOnEmpty: widget.hideOnEmpty, + hideOnError: widget.hideOnError, + keepSuggestionsOnLoading: widget.keepSuggestionsOnLoading, + ); + + double w = _suggestionsBox.textBoxWidth; + if (widget.suggestionsBoxDecoration.constraints != null) { + if (widget.suggestionsBoxDecoration.constraints.minWidth != 0.0 && + widget.suggestionsBoxDecoration.constraints.maxWidth != + double.infinity) { + w = (widget.suggestionsBoxDecoration.constraints.minWidth + + widget.suggestionsBoxDecoration.constraints.maxWidth) / + 2; + } else if (widget.suggestionsBoxDecoration.constraints.minWidth != + 0.0 && + widget.suggestionsBoxDecoration.constraints.minWidth > w) { + w = widget.suggestionsBoxDecoration.constraints.minWidth; + } else if (widget.suggestionsBoxDecoration.constraints.maxWidth != + double.infinity && + widget.suggestionsBoxDecoration.constraints.maxWidth < w) { + w = widget.suggestionsBoxDecoration.constraints.maxWidth; + } + } + + return Positioned( + width: w, + child: CompositedTransformFollower( + link: this._layerLink, + showWhenUnlinked: false, + offset: Offset( + widget.suggestionsBoxDecoration.offsetX, + _suggestionsBox.direction == AxisDirection.down + ? _suggestionsBox.textBoxHeight + + widget.suggestionsBoxVerticalOffset + : _suggestionsBox.directionUpOffset), + child: _suggestionsBox.direction == AxisDirection.down + ? suggestionsList + : FractionalTranslation( + translation: + Offset(0.0, -1.0), // visually flips list to go up + child: suggestionsList, + ), + ), + ); + }); + } + + @override + Widget build(BuildContext context) { + return CompositedTransformTarget( + link: this._layerLink, + child: TextField( + focusNode: this._effectiveFocusNode, + controller: this._effectiveController, + decoration: widget.textFieldConfiguration.decoration, + style: widget.textFieldConfiguration.style, + textAlign: widget.textFieldConfiguration.textAlign, + enabled: widget.textFieldConfiguration.enabled, + keyboardType: widget.textFieldConfiguration.keyboardType, + autofocus: widget.textFieldConfiguration.autofocus, + inputFormatters: widget.textFieldConfiguration.inputFormatters, + autocorrect: widget.textFieldConfiguration.autocorrect, + maxLines: widget.textFieldConfiguration.maxLines, + minLines: widget.textFieldConfiguration.minLines, + maxLength: widget.textFieldConfiguration.maxLength, + maxLengthEnforced: widget.textFieldConfiguration.maxLengthEnforced, + obscureText: widget.textFieldConfiguration.obscureText, + onChanged: widget.textFieldConfiguration.onChanged, + onSubmitted: widget.textFieldConfiguration.onSubmitted, + onEditingComplete: widget.textFieldConfiguration.onEditingComplete, + onTap: widget.textFieldConfiguration.onTap, + scrollPadding: widget.textFieldConfiguration.scrollPadding, + textInputAction: widget.textFieldConfiguration.textInputAction, + textCapitalization: widget.textFieldConfiguration.textCapitalization, + keyboardAppearance: widget.textFieldConfiguration.keyboardAppearance, + cursorWidth: widget.textFieldConfiguration.cursorWidth, + cursorRadius: widget.textFieldConfiguration.cursorRadius, + cursorColor: widget.textFieldConfiguration.cursorColor, + textDirection: widget.textFieldConfiguration.textDirection, + enableInteractiveSelection: + widget.textFieldConfiguration.enableInteractiveSelection, + readOnly: widget.hideKeyboard, + ), + ); + } +} + +class _SuggestionsList extends StatefulWidget { + final _SuggestionsBox suggestionsBox; + final TextEditingController controller; + final bool getImmediateSuggestions; + final SuggestionSelectionCallback onSuggestionSelected; + final SuggestionsCallback suggestionsCallback; + final ItemBuilder itemBuilder; + final SuggestionsBoxDecoration decoration; + final Duration debounceDuration; + final WidgetBuilder loadingBuilder; + final WidgetBuilder noItemsFoundBuilder; + final ErrorBuilder errorBuilder; + final AnimationTransitionBuilder transitionBuilder; + final Duration animationDuration; + final double animationStart; + final AxisDirection direction; + final bool hideOnLoading; + final bool hideOnEmpty; + final bool hideOnError; + final bool keepSuggestionsOnLoading; + + _SuggestionsList({ + @required this.suggestionsBox, + this.controller, + this.getImmediateSuggestions: false, + this.onSuggestionSelected, + this.suggestionsCallback, + this.itemBuilder, + this.decoration, + this.debounceDuration, + this.loadingBuilder, + this.noItemsFoundBuilder, + this.errorBuilder, + this.transitionBuilder, + this.animationDuration, + this.animationStart, + this.direction, + this.hideOnLoading, + this.hideOnEmpty, + this.hideOnError, + this.keepSuggestionsOnLoading, + }); + + @override + _SuggestionsListState createState() => _SuggestionsListState(); +} + +class _SuggestionsListState extends State<_SuggestionsList> + with SingleTickerProviderStateMixin { + Iterable _suggestions; + bool _suggestionsValid; + VoidCallback _controllerListener; + Timer _debounceTimer; + bool _isLoading, _isQueued; + Object _error; + AnimationController _animationController; + String _lastTextValue; + final _scrollController = ScrollController(); + + _SuggestionsListState() { + this._controllerListener = () { + // If we came here because of a change in selected text, not because of + // actual change in text + if (widget.controller.text == this._lastTextValue) return; + + this._lastTextValue = widget.controller.text; + + this._debounceTimer.cancel(); + this._debounceTimer = Timer(widget.debounceDuration, () async { + if (this._debounceTimer.isActive) return; + if (_isLoading) { + _isQueued = true; + return; + } + + await this.invalidateSuggestions(); + while (_isQueued) { + _isQueued = false; + await this.invalidateSuggestions(); + } + }); + }; + } + + @override + void didUpdateWidget(_SuggestionsList oldWidget) { + super.didUpdateWidget(oldWidget); + widget.controller.addListener(this._controllerListener); + _getSuggestions(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _getSuggestions(); + } + + @override + void initState() { + super.initState(); + + this._animationController = AnimationController( + vsync: this, + duration: widget.animationDuration, + ); + + this._suggestionsValid = false; + this._isLoading = false; + this._isQueued = false; + this._lastTextValue = widget.controller.text; + + if (widget.getImmediateSuggestions) { + this._getSuggestions(); + } + + widget.controller.addListener(this._controllerListener); + } + + Future invalidateSuggestions() async { + _suggestionsValid = false; + await _getSuggestions(); + } + + Future _getSuggestions() async { + if (_suggestionsValid) return; + _suggestionsValid = true; + + if (mounted) { + setState(() { + this._animationController.forward(from: 1.0); + + this._isLoading = true; + this._error = null; + }); + + Iterable suggestions; + Object error; + + try { + suggestions = await widget.suggestionsCallback(widget.controller.text); + } catch (e) { + error = e; + } + + if (this.mounted) { + // if it wasn't removed in the meantime + setState(() { + double animationStart = widget.animationStart; + // allow suggestionsCallback to return null and not throw error here + if (error != null || suggestions.isEmpty == true) { + animationStart = 1.0; + } + this._animationController.forward(from: animationStart); + + this._error = error; + this._isLoading = false; + this._suggestions = suggestions; + }); + } + } + } + + @override + void dispose() { + _animationController.dispose(); + _debounceTimer.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + bool isEmpty = + this._suggestions.length == 0 && widget.controller.text == ""; + if ((this._suggestions == null || isEmpty) && this._isLoading == false) + return Container(); + + Widget child; + if (this._isLoading) { + if (widget.hideOnLoading) { + child = Container(height: 0); + } else { + child = createLoadingWidget(); + } + } else if (this._error != null) { + if (widget.hideOnError) { + child = Container(height: 0); + } else { + child = createErrorWidget(); + } + } else if (this._suggestions.isEmpty) { + if (widget.hideOnEmpty) { + child = Container(height: 0); + } else { + child = createNoItemsFoundWidget(); + } + } else { + child = createSuggestionsWidget(); + } + + var animationChild = widget.transitionBuilder != null + ? widget.transitionBuilder(context, child, this._animationController) + : SizeTransition( + axisAlignment: -1.0, + sizeFactor: CurvedAnimation( + parent: this._animationController, curve: Curves.fastOutSlowIn), + child: child, + ); + + BoxConstraints constraints; + if (widget.decoration.constraints == null) { + constraints = BoxConstraints( + maxHeight: widget.suggestionsBox.maxHeight, + ); + } else { + double maxHeight = min(widget.decoration.constraints.maxHeight, + widget.suggestionsBox.maxHeight); + constraints = widget.decoration.constraints.copyWith( + minHeight: min(widget.decoration.constraints.minHeight, maxHeight), + maxHeight: maxHeight, + ); + } + + var container = Material( + elevation: widget.decoration.elevation, + color: widget.decoration.color, + shape: widget.decoration.shape, + borderRadius: widget.decoration.borderRadius, + shadowColor: widget.decoration.shadowColor, + clipBehavior: widget.decoration.clipBehavior, + child: ConstrainedBox( + constraints: constraints, + child: animationChild, + ), + ); + + return container; + } + + Widget createLoadingWidget() { + Widget child; + + if (widget.keepSuggestionsOnLoading && this._suggestions != null) { + if (this._suggestions.isEmpty) { + child = createNoItemsFoundWidget(); + } else { + child = createSuggestionsWidget(); + } + } else { + child = widget.loadingBuilder != null + ? widget.loadingBuilder(context) + : Align( + alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: CircularProgressIndicator(), + ), + ); + } + + return child; + } + + Widget createErrorWidget() { + return widget.errorBuilder != null + ? widget.errorBuilder(context, this._error) + : Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'Error: ${this._error}', + style: TextStyle(color: Theme.of(context).errorColor), + ), + ); + } + + Widget createNoItemsFoundWidget() { + return widget.noItemsFoundBuilder != null + ? widget.noItemsFoundBuilder(context) + : Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Text( + 'No Items Found!', + textAlign: TextAlign.center, + style: TextStyle( + color: Theme.of(context).disabledColor, fontSize: 18.0), + ), + ); + } + + Widget createSuggestionsWidget() { + Widget child = ListView( + padding: EdgeInsets.zero, + primary: false, + shrinkWrap: true, + controller: _scrollController, + reverse: + widget.suggestionsBox.direction == AxisDirection.down ? false : true, + // reverses the list to start at the bottom + children: this._suggestions.map((T suggestion) { + return InkWell( + child: widget.itemBuilder(context, suggestion), + onTap: () { + widget.onSuggestionSelected(suggestion); + }, + ); + }).toList(), + ); + + if (widget.decoration.hasScrollbar) { + child = Scrollbar( + controller: _scrollController, + child: child, + ); + } + + return child; + } +} + +/// Supply an instance of this class to the [TypeAhead.suggestionsBoxDecoration] +/// property to configure the suggestions box decoration +class SuggestionsBoxDecoration { + /// The z-coordinate at which to place the suggestions box. This controls the size + /// of the shadow below the box. + /// + /// Same as [Material.elevation](https://docs.flutter.io/flutter/material/Material/elevation.html) + final double elevation; + + /// The color to paint the suggestions box. + /// + /// Same as [Material.color](https://docs.flutter.io/flutter/material/Material/color.html) + final Color color; + + /// Defines the material's shape as well its shadow. + /// + /// Same as [Material.shape](https://docs.flutter.io/flutter/material/Material/shape.html) + final ShapeBorder shape; + + /// Defines if a scrollbar will be displayed or not. + final bool hasScrollbar; + + /// If non-null, the corners of this box are rounded by this [BorderRadius](https://docs.flutter.io/flutter/painting/BorderRadius-class.html). + /// + /// Same as [Material.borderRadius](https://docs.flutter.io/flutter/material/Material/borderRadius.html) + final BorderRadius borderRadius; + + /// The color to paint the shadow below the material. + /// + /// Same as [Material.shadowColor](https://docs.flutter.io/flutter/material/Material/shadowColor.html) + final Color shadowColor; + + /// The constraints to be applied to the suggestions box + final BoxConstraints constraints; + + /// Adds an offset to the suggestions box + final double offsetX; + + /// The content will be clipped (or not) according to this option. + /// + /// Same as [Material.clipBehavior](https://api.flutter.dev/flutter/material/Material/clipBehavior.html) + final Clip clipBehavior; + + /// Creates a SuggestionsBoxDecoration + const SuggestionsBoxDecoration( + {this.elevation: 4.0, + this.color, + this.shape, + this.hasScrollbar: true, + this.borderRadius, + this.shadowColor: const Color(0xFF000000), + this.constraints, + this.clipBehavior: Clip.none, + this.offsetX: 0.0}); +} + +/// Supply an instance of this class to the [TypeAhead.textFieldConfiguration] +/// property to configure the displayed text field +class TextFieldConfiguration { + /// The decoration to show around the text field. + /// + /// Same as [TextField.decoration](https://docs.flutter.io/flutter/material/TextField/decoration.html) + final InputDecoration decoration; + + /// Controls the text being edited. + /// + /// If null, this widget will create its own [TextEditingController](https://docs.flutter.io/flutter/widgets/TextEditingController-class.html). + /// A typical use case for this field in the TypeAhead widget is to set the + /// text of the widget when a suggestion is selected. For example: + /// + /// ```dart + /// final _controller = TextEditingController(); + /// ... + /// ... + /// TypeAheadField( + /// controller: _controller, + /// ... + /// ... + /// onSuggestionSelected: (suggestion) { + /// _controller.text = suggestion['city_name']; + /// } + /// ) + /// ``` + final TextEditingController controller; + + /// Controls whether this widget has keyboard focus. + /// + /// Same as [TextField.focusNode](https://docs.flutter.io/flutter/material/TextField/focusNode.html) + final FocusNode focusNode; + + /// The style to use for the text being edited. + /// + /// Same as [TextField.style](https://docs.flutter.io/flutter/material/TextField/style.html) + final TextStyle style; + + /// How the text being edited should be aligned horizontally. + /// + /// Same as [TextField.textAlign](https://docs.flutter.io/flutter/material/TextField/textAlign.html) + final TextAlign textAlign; + + /// Same as [TextField.textDirection](https://docs.flutter.io/flutter/material/TextField/textDirection.html) + /// + /// Defaults to null + final TextDirection textDirection; + + /// If false the textfield is "disabled": it ignores taps and its + /// [decoration] is rendered in grey. + /// + /// Same as [TextField.enabled](https://docs.flutter.io/flutter/material/TextField/enabled.html) + final bool enabled; + + /// Whether to show input suggestions as the user types. + /// + /// Same as [TextField.enableSuggestions](https://api.flutter.dev/flutter/material/TextField/enableSuggestions.html) + final bool enableSuggestions; + + /// The type of keyboard to use for editing the text. + /// + /// Same as [TextField.keyboardType](https://docs.flutter.io/flutter/material/TextField/keyboardType.html) + final TextInputType keyboardType; + + /// Whether this text field should focus itself if nothing else is already + /// focused. + /// + /// Same as [TextField.autofocus](https://docs.flutter.io/flutter/material/TextField/autofocus.html) + final bool autofocus; + + /// Optional input validation and formatting overrides. + /// + /// Same as [TextField.inputFormatters](https://docs.flutter.io/flutter/material/TextField/inputFormatters.html) + final List inputFormatters; + + /// Whether to enable autocorrection. + /// + /// Same as [TextField.autocorrect](https://docs.flutter.io/flutter/material/TextField/autocorrect.html) + final bool autocorrect; + + /// The maximum number of lines for the text to span, wrapping if necessary. + /// + /// Same as [TextField.maxLines](https://docs.flutter.io/flutter/material/TextField/maxLines.html) + final int maxLines; + + /// The minimum number of lines to occupy when the content spans fewer lines. + /// + /// Same as [TextField.minLines](https://docs.flutter.io/flutter/material/TextField/minLines.html) + final int minLines; + + /// The maximum number of characters (Unicode scalar values) to allow in the + /// text field. + /// + /// Same as [TextField.maxLength](https://docs.flutter.io/flutter/material/TextField/maxLength.html) + final int maxLength; + + /// If true, prevents the field from allowing more than [maxLength] + /// characters. + /// + /// Same as [TextField.maxLengthEnforced](https://docs.flutter.io/flutter/material/TextField/maxLengthEnforced.html) + final bool maxLengthEnforced; + + /// Whether to hide the text being edited (e.g., for passwords). + /// + /// Same as [TextField.obscureText](https://docs.flutter.io/flutter/material/TextField/obscureText.html) + final bool obscureText; + + /// Called when the text being edited changes. + /// + /// Same as [TextField.onChanged](https://docs.flutter.io/flutter/material/TextField/onChanged.html) + final ValueChanged onChanged; + + /// Called when the user indicates that they are done editing the text in the + /// field. + /// + /// Same as [TextField.onSubmitted](https://docs.flutter.io/flutter/material/TextField/onSubmitted.html) + final ValueChanged onSubmitted; + + /// The color to use when painting the cursor. + /// + /// Same as [TextField.cursorColor](https://docs.flutter.io/flutter/material/TextField/cursorColor.html) + final Color cursorColor; + + /// How rounded the corners of the cursor should be. By default, the cursor has a null Radius + /// + /// Same as [TextField.cursorRadius](https://docs.flutter.io/flutter/material/TextField/cursorRadius.html) + final Radius cursorRadius; + + /// How thick the cursor will be. + /// + /// Same as [TextField.cursorWidth](https://docs.flutter.io/flutter/material/TextField/cursorWidth.html) + final double cursorWidth; + + /// The appearance of the keyboard. + /// + /// Same as [TextField.keyboardAppearance](https://docs.flutter.io/flutter/material/TextField/keyboardAppearance.html) + final Brightness keyboardAppearance; + + /// Called when the user submits editable content (e.g., user presses the "done" button on the keyboard). + /// + /// Same as [TextField.onEditingComplete](https://docs.flutter.io/flutter/material/TextField/onEditingComplete.html) + final VoidCallback onEditingComplete; + + /// Called for each distinct tap except for every second tap of a double tap. + /// + /// Same as [TextField.onTap](https://docs.flutter.io/flutter/material/TextField/onTap.html) + final GestureTapCallback onTap; + + /// Configures padding to edges surrounding a Scrollable when the Textfield scrolls into view. + /// + /// Same as [TextField.scrollPadding](https://docs.flutter.io/flutter/material/TextField/scrollPadding.html) + final EdgeInsets scrollPadding; + + /// Configures how the platform keyboard will select an uppercase or lowercase keyboard. + /// + /// Same as [TextField.TextCapitalization](https://docs.flutter.io/flutter/material/TextField/textCapitalization.html) + final TextCapitalization textCapitalization; + + /// The type of action button to use for the keyboard. + /// + /// Same as [TextField.textInputAction](https://docs.flutter.io/flutter/material/TextField/textInputAction.html) + final TextInputAction textInputAction; + + final bool enableInteractiveSelection; + + /// Creates a TextFieldConfiguration + const TextFieldConfiguration({ + this.decoration: const InputDecoration(), + this.style, + this.controller, + this.onChanged, + this.onSubmitted, + this.obscureText: false, + this.maxLengthEnforced: true, + this.maxLength, + this.maxLines: 1, + this.minLines, + this.autocorrect: true, + this.inputFormatters, + this.autofocus: false, + this.keyboardType: TextInputType.text, + this.enabled: true, + this.enableSuggestions: true, + this.textAlign: TextAlign.start, + this.focusNode, + this.cursorColor, + this.cursorRadius, + this.textInputAction, + this.textCapitalization: TextCapitalization.none, + this.cursorWidth: 2.0, + this.keyboardAppearance, + this.onEditingComplete, + this.onTap, + this.textDirection, + this.scrollPadding: const EdgeInsets.all(20.0), + this.enableInteractiveSelection: true, + }); + + /// Copies the [TextFieldConfiguration] and only changes the specified + /// properties + copyWith( + {InputDecoration decoration, + TextStyle style, + TextEditingController controller, + ValueChanged onChanged, + ValueChanged onSubmitted, + bool obscureText, + bool maxLengthEnforced, + int maxLength, + int maxLines, + int minLines, + bool autocorrect, + List inputFormatters, + bool autofocus, + TextInputType keyboardType, + bool enabled, + bool enableSuggestions, + TextAlign textAlign, + FocusNode focusNode, + Color cursorColor, + Radius cursorRadius, + double cursorWidth, + Brightness keyboardAppearance, + VoidCallback onEditingComplete, + GestureTapCallback onTap, + EdgeInsets scrollPadding, + TextCapitalization textCapitalization, + TextDirection textDirection, + TextInputAction textInputAction, + bool enableInteractiveSelection}) { + return TextFieldConfiguration( + decoration: decoration ?? this.decoration, + style: style ?? this.style, + controller: controller ?? this.controller, + onChanged: onChanged ?? this.onChanged, + onSubmitted: onSubmitted ?? this.onSubmitted, + obscureText: obscureText ?? this.obscureText, + maxLengthEnforced: maxLengthEnforced ?? this.maxLengthEnforced, + maxLength: maxLength ?? this.maxLength, + maxLines: maxLines ?? this.maxLines, + minLines: minLines ?? this.minLines, + autocorrect: autocorrect ?? this.autocorrect, + inputFormatters: inputFormatters ?? this.inputFormatters, + autofocus: autofocus ?? this.autofocus, + keyboardType: keyboardType ?? this.keyboardType, + enabled: enabled ?? this.enabled, + enableSuggestions: enableSuggestions ?? this.enableSuggestions, + textAlign: textAlign ?? this.textAlign, + focusNode: focusNode ?? this.focusNode, + cursorColor: cursorColor ?? this.cursorColor, + cursorRadius: cursorRadius ?? this.cursorRadius, + cursorWidth: cursorWidth ?? this.cursorWidth, + keyboardAppearance: keyboardAppearance ?? this.keyboardAppearance, + onEditingComplete: onEditingComplete ?? this.onEditingComplete, + onTap: onTap ?? this.onTap, + scrollPadding: scrollPadding ?? this.scrollPadding, + textCapitalization: textCapitalization ?? this.textCapitalization, + textInputAction: textInputAction ?? this.textInputAction, + textDirection: textDirection ?? this.textDirection, + enableInteractiveSelection: + enableInteractiveSelection ?? this.enableInteractiveSelection, + ); + } +} + +class _SuggestionsBox { + static const int waitMetricsTimeoutMillis = 1000; + static const double minOverlaySpace = 64.0; + + final BuildContext context; + final AxisDirection desiredDirection; + final bool autoFlipDirection; + + OverlayEntry _overlayEntry; + AxisDirection direction; + + bool isOpened = false; + bool widgetMounted = true; + double maxHeight = 300.0; + double textBoxWidth = 100.0; + double textBoxHeight = 100.0; + double directionUpOffset; + + _SuggestionsBox(this.context, this.direction, this.autoFlipDirection) + : desiredDirection = direction; + + void open() { + if (this.isOpened) return; + assert(this._overlayEntry != null); + Overlay.of(context).insert(this._overlayEntry); + this.isOpened = true; + } + + void close() { + if (!this.isOpened) return; + assert(this._overlayEntry = null); + this._overlayEntry.remove(); + this.isOpened = false; + } + + void toggle() { + if (this.isOpened) { + this.close(); + } else { + this.open(); + } + } + + MediaQuery _findRootMediaQuery() { + MediaQuery rootMediaQuery; + context.visitAncestorElements((element) { + if (element.widget is MediaQuery) { + rootMediaQuery = element.widget as MediaQuery; + } + return true; + }); + + return rootMediaQuery; + } + + /// Delays until the keyboard has toggled or the orientation has fully changed + Future _waitChangeMetrics() async { + if (widgetMounted) { + // initial viewInsets which are before the keyboard is toggled + EdgeInsets initial = MediaQuery.of(context).viewInsets; + // initial MediaQuery for orientation change + MediaQuery initialRootMediaQuery = _findRootMediaQuery(); + + int timer = 0; + // viewInsets or MediaQuery have changed once keyboard has toggled or orientation has changed + while (widgetMounted && timer < waitMetricsTimeoutMillis) { + // double: reduce delay if showDialog ever exposes detection of animation end + await Future.delayed(const Duration(milliseconds: 170)); + timer += 170; + + if (widgetMounted && + (MediaQuery.of(context).viewInsets != initial || + _findRootMediaQuery() != initialRootMediaQuery)) { + return true; + } + } + } + + return false; + } + + void resize() { + // check to see if widget is still mounted + // user may have closed the widget with the keyboard still open + if (widgetMounted) { + _adjustMaxHeightAndOrientation(); + _overlayEntry.markNeedsBuild(); + } + } + + // See if there's enough room in the desired direction for the overlay to display + // correctly. If not, try the opposite direction if things look more roomy there + void _adjustMaxHeightAndOrientation() { + TypeAheadField widget = context.widget as TypeAheadField; + + RenderBox box = context.findRenderObject() as RenderBox; + if (box == null || box.hasSize == false) { + return; + } + + textBoxWidth = box.size.width; + textBoxHeight = box.size.height; + + // top of text box + double textBoxAbsY = box.localToGlobal(Offset.zero).dy; + + // height of window + double windowHeight = MediaQuery.of(context).size.height; + + // we need to find the root MediaQuery for the unsafe area height + // we cannot use BuildContext.ancestorWidgetOfExactType because + // widgets like SafeArea creates a new MediaQuery with the padding removed + MediaQuery rootMediaQuery = _findRootMediaQuery(); + + // height of keyboard + double keyboardHeight = rootMediaQuery.data.viewInsets.bottom; + + double maxHDesired = _calculateMaxHeight(desiredDirection, box, widget, + windowHeight, rootMediaQuery, keyboardHeight, textBoxAbsY); + + // if there's enough room in the desired direction, update the direction and the max height + if (maxHDesired >= minOverlaySpace || !autoFlipDirection) { + direction = desiredDirection; + maxHeight = maxHDesired; + } else { + // There's not enough room in the desired direction so see how much room is in the opposite direction + AxisDirection flipped = flipAxisDirection(desiredDirection); + double maxHFlipped = _calculateMaxHeight(flipped, box, widget, + windowHeight, rootMediaQuery, keyboardHeight, textBoxAbsY); + + // if there's more room in this opposite direction, update the direction and maxHeight + if (maxHFlipped > maxHDesired) { + direction = flipped; + maxHeight = maxHFlipped; + } + } + + if (maxHeight < 0) maxHeight = 0; + } + + double _calculateMaxHeight( + AxisDirection direction, + RenderBox box, + TypeAheadField widget, + double windowHeight, + MediaQuery rootMediaQuery, + double keyboardHeight, + double textBoxAbsY) { + return direction == AxisDirection.down + ? _calculateMaxHeightDown(box, widget, windowHeight, rootMediaQuery, + keyboardHeight, textBoxAbsY) + : _calculateMaxHeightUp(box, widget, windowHeight, rootMediaQuery, + keyboardHeight, textBoxAbsY); + } + + double _calculateMaxHeightDown( + RenderBox box, + TypeAheadField widget, + double windowHeight, + MediaQuery rootMediaQuery, + double keyboardHeight, + double textBoxAbsY) { + // unsafe area, ie: iPhone X 'home button' + // keyboardHeight includes unsafeAreaHeight, if keyboard is showing, set to 0 + double unsafeAreaHeight = + keyboardHeight == 0 ? rootMediaQuery.data.padding.bottom : 0; + + return windowHeight - + keyboardHeight - + unsafeAreaHeight - + textBoxHeight - + textBoxAbsY - + 2 * widget.suggestionsBoxVerticalOffset; + } + + double _calculateMaxHeightUp( + RenderBox box, + TypeAheadField widget, + double windowHeight, + MediaQuery rootMediaQuery, + double keyboardHeight, + double textBoxAbsY) { + // recalculate keyboard absolute y value + double keyboardAbsY = windowHeight - keyboardHeight; + + directionUpOffset = textBoxAbsY > keyboardAbsY + ? keyboardAbsY - textBoxAbsY - widget.suggestionsBoxVerticalOffset + : -widget.suggestionsBoxVerticalOffset; + + // unsafe area, ie: iPhone X notch + double unsafeAreaHeight = rootMediaQuery.data.padding.top; + + return textBoxAbsY > keyboardAbsY + ? keyboardAbsY - + unsafeAreaHeight - + 2 * widget.suggestionsBoxVerticalOffset + : textBoxAbsY - + unsafeAreaHeight - + 2 * widget.suggestionsBoxVerticalOffset; + } + + Future onChangeMetrics() async { + if (await _waitChangeMetrics()) { + resize(); + } + } +} + +/// Supply an instance of this class to the [TypeAhead.suggestionsBoxController] +/// property to manually control the suggestions box +class SuggestionsBoxController { + _SuggestionsBox _suggestionsBox; + FocusNode _effectiveFocusNode; + + /// Opens the suggestions box + void open() { + _effectiveFocusNode.requestFocus(); + } + + bool isOpened() { + return _suggestionsBox.isOpened; + } + + /// Closes the suggestions box + void close() { + _effectiveFocusNode.unfocus(); + } + + /// Opens the suggestions box if closed and vice-versa + void toggle() { + if (_suggestionsBox.isOpened) { + close(); + } else { + open(); + } + } + + /// Recalculates the height of the suggestions box + void resize() { + _suggestionsBox.resize(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/samples/typeahed/src/typedef.dart b/FlutterHelper/flutter_helper/lib/samples/typeahed/src/typedef.dart new file mode 100644 index 00000000..54141e29 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/samples/typeahed/src/typedef.dart @@ -0,0 +1,11 @@ +import 'dart:async'; + +import 'package:flutter/widgets.dart'; + +typedef FutureOr> SuggestionsCallback(String pattern); +typedef Widget ItemBuilder(BuildContext context, T itemData); +typedef void SuggestionSelectionCallback(T suggestion); +typedef Widget ErrorBuilder(BuildContext context, Object error); + +typedef AnimationTransitionBuilder( + BuildContext context, Widget child, AnimationController controller); diff --git a/FlutterHelper/flutter_helper/lib/templates/awesome_flutter/awesome.dart b/FlutterHelper/flutter_helper/lib/templates/awesome_flutter/awesome.dart new file mode 100644 index 00000000..87048777 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/awesome_flutter/awesome.dart @@ -0,0 +1,25 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; + +class AwesomeFlutterApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + home: _AwsomeApp(), + ); + } +} + +class _AwsomeApp extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return Scaffold( + body: WebView( + url: "https://github.com/Solido/awesome-flutter#components", + title: "Awesome-Flutter", + hideAppBar: true, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/di/dependency_injection.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/di/dependency_injection.dart new file mode 100644 index 00000000..89e808be --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/di/dependency_injection.dart @@ -0,0 +1,29 @@ +import '../services/abstract/i_otp_service.dart'; +import '../services/mock/mock_otp_service.dart'; +import '../services/real/real_otp_service.dart'; +import '../services/restclient.dart'; + +enum Flavor { MOCK, PRO } + +//Simple DI +class Injector { + static final Injector _singleton = new Injector._internal(); + static Flavor _flavor; + + static void configure(Flavor flavor) async { + _flavor = flavor; + } + + factory Injector() => _singleton; + + Injector._internal(); + + IOTPService get otpService { + switch (_flavor) { + case Flavor.MOCK: + return MockOTPService(); + default: + return OTPService(new RestClient()); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/inherited/login_provider.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/inherited/login_provider.dart new file mode 100644 index 00000000..39b308a6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/inherited/login_provider.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class LoginProvider extends InheritedWidget { + final Function validationErrorCallback; + final Widget child; + + LoginProvider({this.validationErrorCallback, this.child}) + : super(child: child); + + // static LoginProvider of(BuildContext context) => + // context.inheritFromWidgetOfExactType(LoginProvider); + + static LoginProvider of(BuildContext context) => + context.dependOnInheritedWidgetOfExactType(); + + @override + bool updateShouldNotify(LoginProvider oldWidget) => + validationErrorCallback != oldWidget.validationErrorCallback; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/inherited/product_provider.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/inherited/product_provider.dart new file mode 100644 index 00000000..18cd298f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/inherited/product_provider.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import '../logic/bloc/product_bloc.dart'; + +class ProductProvider extends InheritedWidget { + final ProductBloc productBloc; + final Widget child; + + ProductProvider({this.productBloc, this.child}) : super(child: child); + + static ProductProvider of(BuildContext context) => + context.dependOnInheritedWidgetOfExactType(); + + @override + bool updateShouldNotify(ProductProvider oldWidget) => + productBloc != oldWidget.productBloc; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/cart_bloc.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/cart_bloc.dart new file mode 100644 index 00000000..69c0a5a5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/cart_bloc.dart @@ -0,0 +1,36 @@ +import 'dart:async'; + +import '../../logic/viewmodel/cart_view_model.dart'; +import '../../model/product.dart'; + +class CartBloc { + CartViewModel _cartViewModel; + final additionalController = StreamController(); + final subtractionController = StreamController(); + final countController = StreamController(); + Sink get addItem => additionalController.sink; + Sink get subtractItem => subtractionController.sink; + Stream get getCount => countController.stream; + + CartBloc(Product p) { + _cartViewModel = CartViewModel(product: p); + additionalController.stream.listen(onAdd); + subtractionController.stream.listen(onDelete); + } + + void onAdd(bool done) { + _cartViewModel.addQuantity(); + countController.add(_cartViewModel.totalQuantity); + } + + void onDelete(bool done) { + _cartViewModel.deleteQuantity(); + countController.add(_cartViewModel.totalQuantity); + } + + void dispose() { + additionalController?.close(); + subtractionController?.close(); + countController?.close(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/credit_card_bloc.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/credit_card_bloc.dart new file mode 100644 index 00000000..f479dc33 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/credit_card_bloc.dart @@ -0,0 +1,58 @@ +import 'dart:async'; + +class CreditCardBloc { + final ccInputController = StreamController(); + final expInputController = StreamController(); + final cvvInputController = StreamController(); + final nameInputController = StreamController(); + + Sink get ccInputSink => ccInputController.sink; + Sink get expInputSink => expInputController.sink; + Sink get cvvInputSink => cvvInputController.sink; + Sink get nameInputSink => nameInputController.sink; + + final ccOutputController = StreamController(); + final expOutputController = StreamController(); + final cvvOutputController = StreamController(); + final nameOutputController = StreamController(); + + Stream get ccOutputStream => ccOutputController.stream; + Stream get expOutputStream => expOutputController.stream; + Stream get cvvOutputStream => cvvOutputController.stream; + Stream get nameOutputStream => nameOutputController.stream; + + CreditCardBloc() { + ccInputController.stream.listen(onCCInput); + expInputController.stream.listen(onExpInput); + cvvInputController.stream.listen(onCvvInput); + nameInputController.stream.listen(onNameInput); + } + + onCCInput(String input) { + ccOutputController.add(input.toString()); + } + + onExpInput(String input) { + expOutputController.add(input); + } + + onCvvInput(String input) { + cvvOutputController.add(input); + } + + onNameInput(String input) { + nameOutputController.add(input); + } + + void ccFormat(String s) { + print(s); + ccInputSink.add(s); + } + + void dispose() { + ccInputController?.close(); + cvvInputController?.close(); + expInputController?.close(); + nameInputController?.close(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/login_bloc.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/login_bloc.dart new file mode 100644 index 00000000..cf7be207 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/login_bloc.dart @@ -0,0 +1,55 @@ +import 'dart:async'; +import '../viewmodel/user_login_view_model.dart'; +import '../../model/fetch_process.dart'; +import 'package:rxdart/rxdart.dart'; + +class LoginBloc { + final otpController = StreamController(); + final loginController = StreamController(); + final apiController = BehaviorSubject(); + final otpResendController = StreamController(); + final otpResultController = BehaviorSubject(); + Sink get otpSink => otpController.sink; + Sink get loginSink => otpController.sink; + Sink get resendOtpSink => otpResendController.sink; + Stream get otpResult => otpResultController.stream; + Stream get apiResult => apiController.stream; + + LoginBloc() { + otpController.stream.listen(apiCall); + otpResendController.stream.listen(resendOtp); + loginController.stream.listen(apiCall); + } + + void apiCall(UserLoginViewModel userLogin) async { + FetchProcess process = new FetchProcess(loading: true); + //for progress loading + apiController.add(process); + if (userLogin.otp == null) { + process.type = ApiType.performOTP; + await userLogin.getOtp(userLogin.phonenumber); + otpResultController.add(userLogin.otpResult); + } else { + process.type = ApiType.performLogin; + await userLogin.performLogin(userLogin); + } + + process.loading = false; + process.response = userLogin.apiResult; + //for error dialog + apiController.add(process); + userLogin = null; + } + + void resendOtp(bool flag) { + otpResultController.add(false); + } + + void dispose() { + otpController.close(); + otpResendController.close(); + apiController.close(); + otpResultController.close(); + loginController.close(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/menu_bloc.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/menu_bloc.dart new file mode 100644 index 00000000..717690fa --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/menu_bloc.dart @@ -0,0 +1,15 @@ +import 'dart:async'; + +import '../viewmodel/menu_view_model.dart'; +import '../../model/menu.dart'; + +class MenuBloc { + final _menuVM = MenuViewModel(); + final menuController = StreamController>(); + + Stream> get menuItems => menuController.stream; + + MenuBloc() { + menuController.add(_menuVM.getMenuItems()); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/post_bloc.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/post_bloc.dart new file mode 100644 index 00000000..f6bec150 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/post_bloc.dart @@ -0,0 +1,28 @@ +import 'dart:async'; + +import '../viewmodel/post_view_model.dart'; +import '../../model/post.dart'; + +class PostBloc { + final PostViewModel postViewModel = PostViewModel(); + final postController = StreamController>(); + final fabController = StreamController(); + final fabVisibleController = StreamController(); + Sink get fabSink => fabController.sink; + Stream> get postItems => postController.stream; + Stream get fabVisible => fabVisibleController.stream; + + PostBloc() { + postController.add(postViewModel.getPosts()); + fabController.stream.listen(onScroll); + } + onScroll(bool visible) { + fabVisibleController.add(visible); + } + + void dispose() { + postController?.close(); + fabController?.close(); + fabVisibleController?.close(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/product_bloc.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/product_bloc.dart new file mode 100644 index 00000000..da30fcfe --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/bloc/product_bloc.dart @@ -0,0 +1,14 @@ +import 'dart:async'; + +import '../viewmodel/product_view_model.dart'; +import '../../model/product.dart'; + +class ProductBloc { + final ProductViewModel productViewModel = ProductViewModel(); + final productController = StreamController>(); + Stream> get productItems => productController.stream; + + ProductBloc() { + productController.add(productViewModel.getProducts()); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/cart_view_model.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/cart_view_model.dart new file mode 100644 index 00000000..21e55033 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/cart_view_model.dart @@ -0,0 +1,10 @@ +import '../../model/product.dart'; + +class CartViewModel { + final Product product; + int get totalQuantity => product.quantity; + void addQuantity() => product.quantity < 10 ? product.quantity++ : null; + void deleteQuantity() => product.quantity > 0 ? product.quantity-- : null; + + CartViewModel({this.product}); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/menu_view_model.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/menu_view_model.dart new file mode 100644 index 00000000..a77fc774 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/menu_view_model.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import '../../model/menu.dart'; +import '../../utils/uidata.dart'; + +class MenuViewModel { + List menuItems; + + MenuViewModel({this.menuItems}); + + getMenuItems() { + return menuItems = [ + Menu( + title: "Profile", + menuColor: Color(0xff050505), + icon: Icons.person, + image: UIData.profileImage, + items: ["View Profile", "Profile 2", "Profile 3", "Profile 4"]), + Menu( + title: "Shopping", + menuColor: Color(0xffc8c4bd), + icon: Icons.shopping_cart, + image: UIData.shoppingImage, + items: [ + "Shopping List", + "Shopping Details", + "Product Details", + "Shopping 4" + ]), + Menu( + title: "Login", + menuColor: Color(0xffc7d8f4), + icon: Icons.send, + image: UIData.loginImage, + items: ["Login With OTP", "Login 2", "Sign Up", "Login 4"]), + Menu( + title: "Timeline", + menuColor: Color(0xff7f5741), + icon: Icons.timeline, + image: UIData.timelineImage, + items: ["Feed", "Tweets", "Timeline 3", "Timeline 4"]), + Menu( + title: "Dashboard", + menuColor: Color(0xff261d33), + icon: Icons.dashboard, + image: UIData.dashboardImage, + items: ["Dashboard 1", "Dashboard 2", "Dashboard 3", "Dashboard 4"]), + Menu( + title: "Settings", + menuColor: Color(0xff2a8ccf), + icon: Icons.settings, + image: UIData.settingsImage, + items: ["Device Settings", "Settings 2", "Settings 3", "Settings 4"]), + Menu( + title: "No Item", + menuColor: Color(0xffe19b6b), + icon: Icons.not_interested, + image: UIData.blankImage, + items: ["No Search Result", "No Internet", "No Item 3", "No Item 4"]), + Menu( + title: "Payment", + menuColor: Color(0xffddcec2), + icon: Icons.payment, + image: UIData.paymentImage, + items: ["Credit Card", "Payment Success", "Payment 3", "Payment 4"]), + ]; + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/post_view_model.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/post_view_model.dart new file mode 100644 index 00000000..e2f835fe --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/post_view_model.dart @@ -0,0 +1,126 @@ +import '../../model/post.dart'; + +class PostViewModel { + List postItems; + + PostViewModel({this.postItems}); + + getPosts() => [ + Post( + personName: "Pawan", + address: "New Delhi, India", + likesCount: 100, + commentsCount: 10, + message: + "Google Developer Expert for Flutter. Passionate #Flutter, #Android Developer. #Entrepreneur #YouTuber", + personImage: + "https://avatars0.githubusercontent.com/u/12619420?s=460&v=4", + messageImage: + "https://cdn.pixabay.com/photo/2018/03/09/16/32/woman-3211957_1280.jpg", + postTime: "Just Now"), + Post( + personName: "Amanda", + address: "Canada", + likesCount: 123, + commentsCount: 78, + messageImage: + "https://cdn.pixabay.com/photo/2016/04/10/21/34/woman-1320810_960_720.jpg", + message: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", + personImage: + "https://cdn.pixabay.com/photo/2016/04/10/21/34/woman-1320810_960_720.jpg", + postTime: "5h ago"), + Post( + personName: "Eric", + address: "California", + likesCount: 50, + commentsCount: 5, + message: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", + personImage: + "https://cdn.pixabay.com/photo/2013/07/18/20/24/brad-pitt-164880_960_720.jpg", + postTime: "2h ago"), + Post( + personName: "Jack", + address: "California", + likesCount: 23, + commentsCount: 4, + messageImage: + "https://cdn.pixabay.com/photo/2014/09/07/16/53/hands-437968_960_720.jpg", + message: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", + personImage: + "https://cdn.pixabay.com/photo/2016/04/01/09/51/actor-1299629_960_720.png", + postTime: "3h ago"), + Post( + personName: "Neha", + address: "Punjab", + likesCount: 35, + commentsCount: 2, + messageImage: + "https://cdn.pixabay.com/photo/2015/11/26/00/14/fashion-1063100_960_720.jpg", + message: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", + personImage: + "https://cdn.pixabay.com/photo/2015/11/26/00/14/fashion-1063100_960_720.jpg", + postTime: "1d ago"), + Post( + personName: "Pawan", + address: "New Delhi, India", + likesCount: 100, + commentsCount: 10, + message: + "Google Developer Expert for Flutter. Passionate #Flutter, #Android Developer. #Entrepreneur #YouTuber", + personImage: + "https://avatars0.githubusercontent.com/u/12619420?s=460&v=4", + messageImage: + "https://cdn.pixabay.com/photo/2018/03/09/16/32/woman-3211957_1280.jpg", + postTime: "Just Now"), + Post( + personName: "Eric", + address: "California", + likesCount: 50, + commentsCount: 5, + message: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", + personImage: + "https://cdn.pixabay.com/photo/2013/07/18/20/24/brad-pitt-164880_960_720.jpg", + postTime: "2h ago"), + Post( + personName: "Jack", + address: "California", + likesCount: 23, + commentsCount: 4, + messageImage: + "https://cdn.pixabay.com/photo/2014/09/07/16/53/hands-437968_960_720.jpg", + message: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", + personImage: + "https://cdn.pixabay.com/photo/2016/04/01/09/51/actor-1299629_960_720.png", + postTime: "3h ago"), + Post( + personName: "Amanda", + address: "Canada", + likesCount: 123, + commentsCount: 78, + messageImage: + "https://cdn.pixabay.com/photo/2016/04/10/21/34/woman-1320810_960_720.jpg", + message: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", + personImage: + "https://cdn.pixabay.com/photo/2016/04/10/21/34/woman-1320810_960_720.jpg", + postTime: "5h ago"), + Post( + personName: "Neha", + address: "Punjab", + likesCount: 35, + commentsCount: 2, + messageImage: + "https://cdn.pixabay.com/photo/2015/11/26/00/14/fashion-1063100_960_720.jpg", + message: + "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s", + personImage: + "https://cdn.pixabay.com/photo/2015/11/26/00/14/fashion-1063100_960_720.jpg", + postTime: "1d ago"), + ]; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/product_view_model.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/product_view_model.dart new file mode 100644 index 00000000..23761bb5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/product_view_model.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; +import '../../model/product.dart'; + +class ProductViewModel { + + List productsItems; + + ProductViewModel({this.productsItems}); + + getProducts() => [ + Product( + brand: "Levis", + description: "Print T-shirt", + image: + "https://mosaic02.ztat.net/vgs/media/pdp-zoom/LE/22/1D/02/2A/12/LE221D022-A12@16.1.jpg", + name: "THE PERFECT", + price: "£19.99", + rating: 4.0, + colors: [ + ProductColor( + color: Colors.red, + colorName: "Red", + ), + ProductColor( + color: Colors.green, + colorName: "Green", + ), + ProductColor( + color: Colors.blue, + colorName: "Blue", + ), + ProductColor( + color: Colors.cyan, + colorName: "Cyan", + ) + ], + quantity: 0, + sizes: ["S", "M", "L", "XL"], + totalReviews: 170), + Product( + brand: "adidas Performance", + description: "Pool sliders", + image: + "https://mosaic02.ztat.net/vgs/media/catalog-lg/AD/58/1D/00/9Q/12/AD581D009-Q12@13.jpg", + name: "AQUALETTE", + price: "£13.49", + rating: 5.0, + totalReviews: 10), + Product( + brand: "Produkt", + description: "Men's Shirt", + image: + "https://mosaic01.ztat.net/vgs/media/pdp-zoom/PY/52/2D/01/FG/11/PY522D01F-G11@8.jpg", + name: "ROBI CHECK", + price: "£16.49", + rating: 4.5, + totalReviews: 0), + Product( + brand: "adidas Originals", + description: "Hoodie", + image: + "https://mosaic01.ztat.net/vgs/media/pdp-zoom/AD/12/2S/07/QN/11/AD122S07Q-N11@8.jpg", + name: "TREF OVER HOOD", + price: "£34.99", + rating: 4.0, + totalReviews: 5), + Product( + brand: "ION", + description: "Hydration rucksack", + image: + "https://mosaic01.ztat.net/vgs/media/packshot/pdp-zoom/N1/94/4E/00/4G/11/N1944E004-G11@10.jpg", + name: "BACKPACK VILLAIN 4", + price: "£55.99", + rating: 4.8, + totalReviews: 12), + Product( + brand: "Diesel", + description: "Straight leg jeans", + image: + "https://mosaic01.ztat.net/vgs/media/pdp-gallery/DI/12/2G/0H/5K/11/DI122G0H5-K11@10.jpg", + name: "THYTAN", + price: "£83.99", + rating: 4.2, + totalReviews: 28), + Product( + brand: "YOURTURN", + description: "Watch in budget", + image: + "https://mosaic02.ztat.net/vgs/media/packshot/pdp-zoom/YO/15/2M/00/6Q/11/YO152M006-Q11@6.jpg", + name: "Watch", + price: "£11.99", + rating: 4.7, + totalReviews: 120), + Product( + brand: "Vero Moda", + description: "Day dress - black/off", + image: + "https://mosaic01.ztat.net/vgs/media/pdp-zoom/VE/12/1C/1B/RQ/11/VE121C1BR-Q11@15.jpg", + name: "VMKANA", + price: "£26.59", + rating: 4.0, + totalReviews: 33), + Product( + brand: "ONLY", + description: "A-line skirt", + image: + "https://mosaic01.ztat.net/vgs/media/pdp-zoom/ON/32/1B/0B/JG/11/ON321B0BJ-G11@8.jpg", + name: "ONLTHAI FRILL", + price: "£25.59", + rating: 4.4, + totalReviews: 44), + Product( + brand: "MAI PIÙ SENZA", + description: "Awesome Heels", + image: + "https://mosaic01.ztat.net/vgs/media/pdp-zoom/M6/61/1B/02/9A/11/M6611B029-A11@13.jpg", + name: "HIGH HEELS", + price: "£59.99", + rating: 4.1, + totalReviews: 22), + ]; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/user_login_view_model.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/user_login_view_model.dart new file mode 100644 index 00000000..dad1df1e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/logic/viewmodel/user_login_view_model.dart @@ -0,0 +1,36 @@ +import 'dart:async'; + +import '../../di/dependency_injection.dart'; +import '../../model/login.dart'; +import '../../model/otp.dart'; +import '../../services/abstract/i_otp_service.dart'; +import '../../services/network_service_response.dart'; +import 'package:meta/meta.dart'; + +class UserLoginViewModel { + String phonenumber; + String otp; + bool otpResult = false; + NetworkServiceResponse apiResult; + IOTPService otpRepo = new Injector().otpService; + + //for otp + UserLoginViewModel({@required this.phonenumber}); + + //for login + UserLoginViewModel.withOTP({@required this.phonenumber, @required this.otp}); + + Future getOtp(String phoneNumber) async { + NetworkServiceResponse result = + await otpRepo.createOTP(phoneNumber); + this.otpResult = result.success; + this.apiResult = result; + } + + Future performLogin(UserLoginViewModel userLogin) async { + NetworkServiceResponse result = + await otpRepo.fetchOTPLoginResponse( + Login(phonenumber: userLogin.phonenumber, otp: userLogin.otp)); + this.apiResult = result; + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/main.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/main.dart new file mode 100644 index 00000000..56c16898 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/main.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +import 'di/dependency_injection.dart'; +import 'myapp.dart'; +// import 'package:flutter_uikit/di/dependency_injection.dart'; +// import 'package:flutter_uikit/myapp.dart'; + +void main() { + // SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + Injector.configure(Flavor.MOCK); + runApp(FlutterUiKitApp()); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/fetch_process.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/fetch_process.dart new file mode 100644 index 00000000..6f25a948 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/fetch_process.dart @@ -0,0 +1,11 @@ +import '../services/network_service_response.dart'; + +enum ApiType { performOTP, performLogin, getProductInfo } + +class FetchProcess { + ApiType type; + bool loading; + NetworkServiceResponse response; + + FetchProcess({this.loading, this.response, this.type}); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/login.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/login.dart new file mode 100644 index 00000000..58fa7e22 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/login.dart @@ -0,0 +1,11 @@ +class Login { + String phonenumber; + String otp; + + Login({this.phonenumber, this.otp}); + + Map toJson() => { + 'phonenumber': phonenumber, + 'otp': otp, + }; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/menu.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/menu.dart new file mode 100644 index 00000000..bcd4053f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/menu.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; + +class Menu { + String title; + IconData icon; + String image; + List items; + BuildContext context; + Color menuColor; + + Menu( + {this.title, + this.icon, + this.image, + this.items, + this.context, + this.menuColor = Colors.black}); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/otp.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/otp.dart new file mode 100644 index 00000000..4826ec8c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/otp.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +class CreateOTPResponse { + String status; + CreateOTPResponse({this.status}); + + CreateOTPResponse.fromJson(Map json) + : status = json['status']; +} + +class OTPResponse { + String status; + OTPData data; + OTPResponse({this.status, this.data}); + + OTPResponse.fromJson(Map json) + : status = json['status'], + data = OTPData.fromJson(json['data']); +} + +class OTPData { + final String authToken; + final String userId; + const OTPData({@required this.authToken, @required this.userId}); + + OTPData.fromJson(Map json) + : authToken = json['authToken'], + userId = json['userId']; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/post.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/post.dart new file mode 100644 index 00000000..7c77d9c4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/post.dart @@ -0,0 +1,22 @@ +class Post { + String personName; + String personImage; + String address; + String message; + String messageImage; + int likesCount; + int commentsCount; + String postTime; + List photos; + + Post( + {this.personName, + this.personImage, + this.address, + this.message, + this.commentsCount, + this.likesCount, + this.messageImage, + this.postTime, + this.photos}); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/product.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/product.dart new file mode 100644 index 00000000..45ff9d32 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/model/product.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class Product { + String name; + String image; + double rating; + String price; + String brand; + String description; + int totalReviews; + List sizes; + List colors; + int quantity = 0; + + + + Product( + {this.name, + this.image, + this.brand, + this.price, + this.rating, + this.description, + this.totalReviews, + this.sizes, + this.colors, + this.quantity}); + + +} + +class ProductColor { + final String colorName; + final MaterialColor color; + + ProductColor({this.colorName, this.color}); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/myapp.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/myapp.dart new file mode 100644 index 00000000..32beb54e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/myapp.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'ui/page/dashboard/dashboard_one.page.dart'; +import 'ui/page/dashboard/dashboard_two_page.dart'; +import 'ui/page/home_page.dart'; +import 'ui/page/login/login_page.dart'; +import 'ui/page/login/login_two_page.dart'; +import 'ui/page/notfound/notfound_page.dart'; +import 'ui/page/payment/credit_card_page.dart'; +import 'ui/page/payment/payment_success_page.dart'; +import 'ui/page/profile/profile_one_page.dart'; +import 'ui/page/profile/profile_two_page.dart'; +import 'ui/page/settings/settings_one_page.dart'; +import 'ui/page/shopping/product_detail_page.dart'; +import 'ui/page/shopping/shopping_details_page.dart'; +import 'ui/page/shopping/shopping_one_page.dart'; +import 'ui/page/timeline/timeline_one_page.dart'; +import 'ui/page/timeline/timeline_two_page.dart'; +import 'utils/translations.dart'; +import 'utils/uidata.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class FlutterUiKitApp extends StatelessWidget { + final materialApp = MaterialApp( + title: UIData.appName, + theme: ThemeData( + primaryColor: Colors.black, + fontFamily: UIData.quickFont, + primarySwatch: Colors.amber), + debugShowCheckedModeBanner: false, + showPerformanceOverlay: false, + home: HomePage(), + localizationsDelegates: [ + const TranslationsDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: [ + const Locale("en", "US"), + const Locale("hi", "IN"), + ], + // initialRoute: UIData.notFoundRoute, + + //routes + routes: { + UIData.homeRoute: (context) => HomePage(), + UIData.profileOneRoute: (context) => ProfileOnePage(), + UIData.profileTwoRoute: (context) => ProfileTwoPage(), + UIData.timelineOneRoute: (context) => TimelineOnePage(), + UIData.timelineTwoRoute: (context) => TimelineTwoPage(), + UIData.notFoundRoute: (context) => NotFoundPage(), + UIData.settingsOneRoute: (context) => SettingsOnePage(), + UIData.shoppingOneRoute: (context) => ShoppingOnePage(), + UIData.shoppingTwoRoute: (context) => ShoppingDetailsPage(), + UIData.shoppingThreeRoute: (context) => ProductDetailPage(), + UIData.loginOneRoute: (context) => LoginPage(), + UIData.loginTwoRoute: (context) => LoginTwoPage(), + UIData.paymentOneRoute: (context) => CreditCardPage(), + UIData.paymentTwoRoute: (context) => PaymentSuccessPage(), + UIData.dashboardOneRoute: (context) => DashboardOnePage(), + UIData.dashboardTwoRoute: (context) => DashboardTwoPage(), + }, + onUnknownRoute: (RouteSettings rs) => new MaterialPageRoute( + builder: (context) => new NotFoundPage( + appTitle: UIData.coming_soon, + icon: FontAwesomeIcons.solidSmile, + title: UIData.coming_soon, + message: "Under Development", + iconColor: Colors.green, + ))); + + @override + Widget build(BuildContext context) { + return materialApp; + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/abstract/i_otp_service.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/abstract/i_otp_service.dart new file mode 100644 index 00000000..431b6084 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/abstract/i_otp_service.dart @@ -0,0 +1,12 @@ +import 'dart:async'; + +import '../../model/login.dart'; +import '../../model/otp.dart'; +import '../../services/network_service_response.dart'; + +abstract class IOTPService { + Future> createOTP( + String phoneNumber); + Future> fetchOTPLoginResponse( + Login userLogin); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/fetch_exception.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/fetch_exception.dart new file mode 100644 index 00000000..04501a3d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/fetch_exception.dart @@ -0,0 +1,10 @@ +class FetchDataException implements Exception { + String message; + FetchDataException(this.message); + + @override + String toString() { + // TODO: implement toString + return "Exception: $message"; + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/mock/mock_otp_service.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/mock/mock_otp_service.dart new file mode 100644 index 00000000..5c500f02 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/mock/mock_otp_service.dart @@ -0,0 +1,33 @@ + +import 'dart:async'; + +import '../../model/login.dart'; +import '../../model/otp.dart'; +import '../../services/abstract/i_otp_service.dart'; +import '../../services/network_service_response.dart'; +import '../../utils/uidata.dart'; + +class MockOTPService implements IOTPService { + @override + Future> createOTP( + String phoneNumber) async { + await Future.delayed(Duration(seconds: 2)); + return Future.value(NetworkServiceResponse( + success: true, + content: null, + )); + } + + @override + Future> fetchOTPLoginResponse( + Login userLogin) async { + await Future.delayed(Duration(seconds: 2)); + return Future.value(NetworkServiceResponse( + success: true, + content: kOTPResponse, + message: UIData.something_went_wrong)); + } +} + +var kOTPResponse = new OTPResponse( + data: const OTPData(authToken: "abcd", userId: "1245"), status: "success"); diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/network_service.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/network_service.dart new file mode 100644 index 00000000..1bacc5a9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/network_service.dart @@ -0,0 +1,6 @@ +import '../services/restclient.dart'; + +abstract class NetworkService { + RestClient rest; + NetworkService(this.rest); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/network_service_response.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/network_service_response.dart new file mode 100644 index 00000000..02728521 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/network_service_response.dart @@ -0,0 +1,14 @@ +class NetworkServiceResponse { + T content; + bool success; + String message; + + NetworkServiceResponse({this.content, this.success, this.message}); +} + +class MappedNetworkServiceResponse { + dynamic mappedResult; + NetworkServiceResponse networkServiceResponse; + MappedNetworkServiceResponse( + {this.mappedResult, this.networkServiceResponse}); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/real/real_otp_service.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/real/real_otp_service.dart new file mode 100644 index 00000000..08cfe687 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/real/real_otp_service.dart @@ -0,0 +1,49 @@ +import 'dart:async'; + +import '../../model/login.dart'; +import '../../model/otp.dart'; +import '../../services/abstract/i_otp_service.dart'; +import '../../services/network_service.dart'; +import '../../services/network_service_response.dart'; +import '../../services/restclient.dart'; + +class OTPService extends NetworkService implements IOTPService { + static const _kCreateOtpUrl = "/createOtpForUser/{1}"; + static const _kUserOtpLogin = "/userotplogin"; + + OTPService(RestClient rest) : super(rest); + + @override + Future> createOTP( + String phoneNumber) async { + var result = await rest.getAsync( + Uri.parse(_kCreateOtpUrl.replaceFirst("{1}", phoneNumber)).toString()); + if (result.mappedResult != null) { + var res = CreateOTPResponse.fromJson(result.mappedResult); + return new NetworkServiceResponse( + content: res, + success: result.networkServiceResponse.success, + ); + } + return new NetworkServiceResponse( + success: result.networkServiceResponse.success, + message: result.networkServiceResponse.message); + } + + @override + Future> fetchOTPLoginResponse( + Login userLogin) async { + var result = await rest.postAsync(_kUserOtpLogin, userLogin); + + if (result.mappedResult != null) { + var res = OTPResponse.fromJson(result.mappedResult); + return new NetworkServiceResponse( + content: res, + success: result.networkServiceResponse.success, + ); + } + return new NetworkServiceResponse( + success: result.networkServiceResponse.success, + message: result.networkServiceResponse.message); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/restclient.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/restclient.dart new file mode 100644 index 00000000..76ce4a78 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/services/restclient.dart @@ -0,0 +1,44 @@ +import 'dart:async'; +import 'dart:convert'; +import '../services/network_service_response.dart'; +import 'package:http/http.dart' as http; + +class RestClient { + Map headers = { + "CONTENT_TYPE": 'application/json', + "ACCEPT": 'application/json', + }; + + Future> getAsync( + String resourcePath) async { + var response = await http.get(Uri.parse(resourcePath)); + return processResponse(response); + } + + Future> postAsync( + String resourcePath, dynamic data) async { + var content = json.encoder.convert(data); + var response = + await http.post(Uri.parse(resourcePath), body: content, headers: headers); + return processResponse(response); + } + + MappedNetworkServiceResponse processResponse(http.Response response) { + if (!((response.statusCode < 200) || + (response.statusCode >= 300) || + (response.body == null))) { + var jsonResult = response.body; + dynamic resultClass = jsonDecode(jsonResult); + + return new MappedNetworkServiceResponse( + mappedResult: resultClass, + networkServiceResponse: new NetworkServiceResponse(success: true)); + } else { + var errorResponse = response.body; + return new MappedNetworkServiceResponse( + networkServiceResponse: new NetworkServiceResponse( + success: false, + message: "(${response.statusCode}) ${errorResponse.toString()}")); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_one.page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_one.page.dart new file mode 100644 index 00000000..daa7727c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_one.page.dart @@ -0,0 +1,217 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/login_background.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/profile_tile.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +import 'dashboard_one/dashboard_menu_row.dart'; + +class DashboardOnePage extends StatelessWidget { + Size deviceSize; + Widget appBarColumn(BuildContext context) => SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 18.0), + child: new Column( + children: [ + new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new IconButton( + icon: new Icon( + defaultTargetPlatform == TargetPlatform.android + ? Icons.arrow_back + : Icons.arrow_back_ios, + color: Colors.white, + ), + onPressed: () => Navigator.canPop(context) + ? Navigator.pop(context) + : null, + ), + new ProfileTile( + title: "Hi, Pawan Kumar", + subtitle: "Welcome to the Flutter UIKit", + textColor: Colors.white, + ), + new IconButton( + icon: new Icon( + Icons.more_vert, + color: Colors.white, + ), + onPressed: () { + print("hi"); + }, + ) + ], + ), + ], + ), + ), + ); + + Widget searchCard() => Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + elevation: 2.0, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon(Icons.search), + SizedBox( + width: 10.0, + ), + Expanded( + child: TextField( + decoration: InputDecoration( + border: InputBorder.none, hintText: "Find our product"), + ), + ), + Icon(Icons.menu), + ], + ), + ), + ), + ); + + Widget actionMenuCard() => Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Card( + elevation: 2.0, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + DashboardMenuRow( + firstIcon: FontAwesomeIcons.solidUser, + firstLabel: "Friends", + firstIconCircleColor: Colors.blue, + secondIcon: FontAwesomeIcons.userFriends, + secondLabel: "Groups", + secondIconCircleColor: Colors.orange, + thirdIcon: FontAwesomeIcons.mapMarkerAlt, + thirdLabel: "Nearby", + thirdIconCircleColor: Colors.purple, + fourthIcon: FontAwesomeIcons.locationArrow, + fourthLabel: "Moment", + fourthIconCircleColor: Colors.indigo, + ), + DashboardMenuRow( + firstIcon: FontAwesomeIcons.images, + firstLabel: "Albums", + firstIconCircleColor: Colors.red, + secondIcon: FontAwesomeIcons.solidHeart, + secondLabel: "Likes", + secondIconCircleColor: Colors.teal, + thirdIcon: FontAwesomeIcons.solidNewspaper, + thirdLabel: "Articles", + thirdIconCircleColor: Colors.lime, + fourthIcon: FontAwesomeIcons.solidCommentDots, + fourthLabel: "Reviews", + fourthIconCircleColor: Colors.amber, + ), + DashboardMenuRow( + firstIcon: FontAwesomeIcons.footballBall, + firstLabel: "Sports", + firstIconCircleColor: Colors.cyan, + secondIcon: FontAwesomeIcons.solidStar, + secondLabel: "Fav", + secondIconCircleColor: Colors.redAccent, + thirdIcon: FontAwesomeIcons.blogger, + thirdLabel: "Blogs", + thirdIconCircleColor: Colors.pink, + fourthIcon: FontAwesomeIcons.wallet, + fourthLabel: "Wallet", + fourthIconCircleColor: Colors.brown, + ), + ], + ), + ), + ), + ), + ); + + Widget balanceCard() => Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + elevation: 2.0, + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Balance", + style: TextStyle(fontFamily: UIData.ralewayFont), + ), + Material( + color: Colors.black, + shape: StadiumBorder(), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "500 Points", + style: TextStyle( + color: Colors.white, + fontFamily: UIData.ralewayFont), + ), + ), + ) + ], + ), + Text( + "₹ 1000", + style: TextStyle( + fontFamily: UIData.ralewayFont, + fontWeight: FontWeight.w700, + color: Colors.green, + fontSize: 25.0), + ), + ], + ), + ), + ), + ); + + Widget allCards(BuildContext context) => SingleChildScrollView( + child: Column( + children: [ + appBarColumn(context), + SizedBox( + height: deviceSize.height * 0.01, + ), + searchCard(), + SizedBox( + height: deviceSize.height * 0.01, + ), + actionMenuCard(), + SizedBox( + height: deviceSize.height * 0.01, + ), + balanceCard(), + ], + ), + ); + + @override + Widget build(BuildContext context) { + deviceSize = MediaQuery.of(context).size; + return Scaffold( + body: Stack( + fit: StackFit.expand, + children: [ + LoginBackground( + showIcon: false, + ), + allCards(context), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_one/dashboard_menu_row.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_one/dashboard_menu_row.dart new file mode 100644 index 00000000..9a2055d8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_one/dashboard_menu_row.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/label_below_icon.dart'; + +class DashboardMenuRow extends StatelessWidget { + final firstLabel; + final IconData firstIcon; + final firstIconCircleColor; + final secondLabel; + final IconData secondIcon; + final secondIconCircleColor; + final thirdLabel; + final IconData thirdIcon; + final thirdIconCircleColor; + final fourthLabel; + final IconData fourthIcon; + final fourthIconCircleColor; + + const DashboardMenuRow( + {Key key, + this.firstLabel, + this.firstIcon, + this.firstIconCircleColor, + this.secondLabel, + this.secondIcon, + this.secondIconCircleColor, + this.thirdLabel, + this.thirdIcon, + this.thirdIconCircleColor, + this.fourthLabel, + this.fourthIcon, + this.fourthIconCircleColor}) + : super(key: key); + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 15.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisSize: MainAxisSize.max, + children: [ + LabelBelowIcon( + icon: firstIcon, + label: firstLabel, + circleColor: firstIconCircleColor, + ), + LabelBelowIcon( + icon: secondIcon, + label: secondLabel, + circleColor: secondIconCircleColor, + ), + LabelBelowIcon( + icon: thirdIcon, + label: thirdLabel, + circleColor: thirdIconCircleColor, + ), + LabelBelowIcon( + icon: fourthIcon, + label: fourthLabel, + circleColor: fourthIconCircleColor, + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_two/dashboard_menu_row_two.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_two/dashboard_menu_row_two.dart new file mode 100644 index 00000000..bfb7831c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_two/dashboard_menu_row_two.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/label_below_icon.dart'; + +class DashboardMenuRowTwo extends StatelessWidget { + final firstLabel; + final IconData firstIcon; + final secondLabel; + final IconData secondIcon; + final thirdLabel; + final IconData thirdIcon; + + const DashboardMenuRowTwo({ + Key key, + this.firstLabel, + this.firstIcon, + this.secondLabel, + this.secondIcon, + this.thirdLabel, + this.thirdIcon, + }) : super(key: key); + @override + Widget build(BuildContext context) { + Size deviceSize = MediaQuery.of(context).size; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox.fromSize( + size: Size.square(deviceSize.width / 3.3), + child: Card( + color: Colors.grey.shade300, + child: LabelBelowIcon( + betweenHeight: 15.0, + icon: firstIcon, + label: firstLabel, + iconColor: Colors.indigo.shade800, + isCircleEnabled: false, + ), + ), + ), + SizedBox.fromSize( + size: Size.square(deviceSize.width / 3.3), + child: Card( + color: Colors.grey.shade300, + child: LabelBelowIcon( + betweenHeight: 15.0, + icon: secondIcon, + label: secondLabel, + iconColor: Colors.indigo.shade800, + isCircleEnabled: false, + ), + ), + ), + SizedBox.fromSize( + size: Size.square(deviceSize.width / 3.3), + child: Card( + color: Colors.grey.shade300, + child: LabelBelowIcon( + betweenHeight: 15.0, + icon: thirdIcon, + label: thirdLabel, + iconColor: Colors.indigo.shade800, + isCircleEnabled: false, + ), + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_two_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_two_page.dart new file mode 100644 index 00000000..04316c01 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/dashboard/dashboard_two_page.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +import 'dashboard_two/dashboard_menu_row_two.dart'; + +class DashboardTwoPage extends StatelessWidget { + Widget bodyData() => SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Text( + "Pay Your Bills", + style: + TextStyle(fontWeight: FontWeight.w700, fontSize: 20.0), + ), + ), + ), + SizedBox( + height: 10.0, + ), + DashboardMenuRowTwo( + firstIcon: FontAwesomeIcons.bolt, + firstLabel: "ELECTRICITY", + secondIcon: FontAwesomeIcons.tint, + secondLabel: "WATER", + thirdIcon: FontAwesomeIcons.mobile, + thirdLabel: "MOBILE", + ), + DashboardMenuRowTwo( + firstIcon: Icons.phone, + firstLabel: "LANDLINE", + secondIcon: FontAwesomeIcons.tv, + secondLabel: "CABLE TV", + thirdIcon: FontAwesomeIcons.chrome, + thirdLabel: "INTERNET", + ), + SizedBox( + height: 10.0, + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Text( + "Purchase Tickets", + style: + TextStyle(fontWeight: FontWeight.w700, fontSize: 20.0), + ), + ), + ), + DashboardMenuRowTwo( + firstIcon: FontAwesomeIcons.film, + firstLabel: "MOVIE", + secondIcon: FontAwesomeIcons.calendarAlt, + secondLabel: "EVENT", + thirdIcon: FontAwesomeIcons.footballBall, + thirdLabel: "SPORT", + ), + ], + ), + ), + ); + + @override + Widget build(BuildContext context) { + return CommonScaffold( + appTitle: "Pay", + showFAB: false, + bodyData: bodyData(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/home_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/home_page.dart new file mode 100644 index 00000000..e7ce950a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/home_page.dart @@ -0,0 +1,349 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/menu_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/menu.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/about_tile.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/profile_tile.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/logic/bloc/menu_bloc.dart'; +// import 'package:flutter_uikit/model/menu.dart'; +// import 'package:flutter_uikit/ui/widgets/about_tile.dart'; +// import 'package:flutter_uikit/ui/widgets/profile_tile.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class HomePage extends StatelessWidget { + final _scaffoldState = GlobalKey(); + Size deviceSize; + BuildContext _context; + //menuStack + Widget menuStack(BuildContext context, Menu menu) => InkWell( + onTap: () => _showModalBottomSheet(context, menu), + splashColor: Colors.orange, + child: Card( + clipBehavior: Clip.antiAlias, + elevation: 2.0, + child: Stack( + fit: StackFit.expand, + children: [ + menuImage(menu), + menuColor(), + menuData(menu), + ], + ), + ), + ); + + //stack 1/3 + Widget menuImage(Menu menu) => Image.asset( + menu.image, + fit: BoxFit.cover, + ); + + //stack 2/3 + Widget menuColor() => new Container( + decoration: BoxDecoration(boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.8), + blurRadius: 5.0, + ), + ]), + ); + + //stack 3/3 + Widget menuData(Menu menu) => Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + menu.icon, + color: Colors.white, + ), + SizedBox( + height: 10.0, + ), + Text( + menu.title, + style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), + ) + ], + ); + + //appbar + Widget appBar() => SliverAppBar( + backgroundColor: Colors.black, + pinned: true, + elevation: 10.0, + forceElevated: true, + expandedHeight: 150.0, + flexibleSpace: FlexibleSpaceBar( + centerTitle: false, + background: Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: UIData.kitGradients)), + ), + title: Row( + children: [ + FlutterLogo( + // colors: Colors.yellow, + textColor: Colors.white, + ), + SizedBox( + width: 10.0, + ), + Text(UIData.appName) + ], + ), + ), + ); + + //bodygrid + Widget bodyGrid(List menu) => SliverGrid( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: + MediaQuery.of(_context).orientation == Orientation.portrait + ? 2 + : 3, + mainAxisSpacing: 0.0, + crossAxisSpacing: 0.0, + childAspectRatio: 1.0, + ), + delegate: SliverChildBuilderDelegate((BuildContext context, int index) { + return menuStack(context, menu[index]); + }, childCount: menu.length), + ); + + Widget homeScaffold(BuildContext context) => Theme( + data: Theme.of(context).copyWith( + canvasColor: Colors.transparent, + ), + child: Scaffold(key: _scaffoldState, body: bodySliverList()), + ); + + Widget bodySliverList() { + MenuBloc menuBloc = MenuBloc(); + return StreamBuilder>( + stream: menuBloc.menuItems, + builder: (context, snapshot) { + return snapshot.hasData + ? CustomScrollView( + slivers: [ + appBar(), + bodyGrid(snapshot.data), + ], + ) + : Center(child: CircularProgressIndicator()); + }); + } + + Widget header() => Ink( + decoration: BoxDecoration( + gradient: LinearGradient(colors: UIData.kitGradients2)), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + CircleAvatar( + radius: 25.0, + backgroundImage: AssetImage(UIData.pkImage), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: ProfileTile( + title: "Pawan Kumar", + subtitle: "mtechviral@gmail.com", + textColor: Colors.white, + ), + ) + ], + ), + ), + ); + + void _showModalBottomSheet(BuildContext context, Menu menu) { + showModalBottomSheet( + context: context, + builder: (context) => Material( + clipBehavior: Clip.antiAlias, + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: new BorderRadius.only( + topLeft: new Radius.circular(15.0), + topRight: new Radius.circular(15.0))), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisSize: MainAxisSize.max, + children: [ + header(), + Expanded( + child: ListView.builder( + shrinkWrap: false, + itemCount: menu.items.length, + itemBuilder: (context, i) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: ListTile( + title: Text( + menu.items[i], + ), + onTap: () { + Navigator.pop(context); + Navigator.pushNamed( + context, "/${menu.items[i]}"); + }), + ), + ), + ), + MyAboutTile() + ], + ))); + } + + Widget iosCardBottom(Menu menu, BuildContext context) => Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + width: 40.0, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.0), + border: Border.all(width: 3.0, color: Colors.white), + image: DecorationImage( + fit: BoxFit.cover, + image: AssetImage( + menu.image, + ))), + ), + SizedBox( + width: 20.0, + ), + Text( + menu.title, + textAlign: TextAlign.start, + style: TextStyle(color: Colors.white), + ), + SizedBox( + width: 20.0, + ), + FittedBox( + child: CupertinoButton( + onPressed: () => _showModalBottomSheet(context, menu), + borderRadius: BorderRadius.circular(50.0), + child: Text( + "Go", + textAlign: TextAlign.left, + style: TextStyle(color: CupertinoColors.activeBlue), + ), + color: Colors.white, + ), + ) + ], + ), + ); + + Widget menuIOS(Menu menu, BuildContext context) { + return Container( + height: deviceSize.height / 2, + decoration: ShapeDecoration( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), + ), + child: Card( + clipBehavior: Clip.antiAlias, + elevation: 3.0, + margin: EdgeInsets.all(16.0), + child: Stack( + fit: StackFit.expand, + children: [ + menuImage(menu), + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + menu.title, + style: TextStyle( + color: Colors.white, + fontSize: 28.0, + fontWeight: FontWeight.bold, + ), + ), + ), + Positioned( + bottom: 0.0, + left: 0.0, + right: 0.0, + height: 60.0, + child: Container( + width: double.infinity, + color: menu.menuColor, + child: iosCardBottom(menu, context), + ), + ) + ], + ), + ), + ); + } + + Widget bodyDataIOS(List data, BuildContext context) => SliverList( + delegate: SliverChildListDelegate( + data.map((menu) => menuIOS(menu, context)).toList()), + ); + + Widget homeBodyIOS(BuildContext context) { + MenuBloc menuBloc = MenuBloc(); + return StreamBuilder>( + stream: menuBloc.menuItems, + initialData: List(), + builder: (context, snapshot) { + return snapshot.hasData + ? bodyDataIOS(snapshot.data, context) + : Center( + child: CircularProgressIndicator(), + ); + }); + } + + Widget homeIOS(BuildContext context) => Theme( + data: ThemeData( + fontFamily: '.SF Pro Text', + ).copyWith(canvasColor: Colors.transparent), + child: CupertinoPageScaffold( + child: CustomScrollView( + slivers: [ + CupertinoSliverNavigationBar( + border: Border(bottom: BorderSide.none), + backgroundColor: CupertinoColors.white, + largeTitle: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(UIData.appName), + Padding( + padding: const EdgeInsets.only(right: 16.0), + child: CircleAvatar( + radius: 15.0, + backgroundColor: CupertinoColors.black, + child: FlutterLogo( + size: 15.0, + // colors: Colors.yellow, + ), + ), + ) + ], + ), + ), + homeBodyIOS(context) + ], + ), + ), + ); + + @override + Widget build(BuildContext context) { + _context = context; + deviceSize = MediaQuery.of(context).size; + return defaultTargetPlatform == TargetPlatform.iOS + ? homeIOS(context) + : homeScaffold(context); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_one/login_card.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_one/login_card.dart new file mode 100644 index 00000000..c79c036d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_one/login_card.dart @@ -0,0 +1,155 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/inherited/login_provider.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/login_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/viewmodel/user_login_view_model.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/fetch_process.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/api_subscription.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/gradient_button.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/translations.dart'; + +import '../login_page.dart'; + +class LoginCard extends StatefulWidget { + @override + _LoginCardState createState() => new _LoginCardState(); +} + +class _LoginCardState extends State + with SingleTickerProviderStateMixin { + var deviceSize; + AnimationController controller; + Animation animation; + LoginBloc loginBloc; + String phoneNumber, otp; + StreamSubscription apiStreamSubscription; + + Widget loginBuilder() => StreamBuilder( + stream: loginBloc.otpResult, + initialData: false, + builder: (context, snapshot) => Form( + child: Padding( + padding: const EdgeInsets.all(18.0), + child: SingleChildScrollView( + child: new Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisSize: MainAxisSize.min, + children: [ + new TextField( + onChanged: (phone) => phoneNumber = phone, + enabled: !snapshot.data, + style: + new TextStyle(fontSize: 15.0, color: Colors.black), + decoration: new InputDecoration( + hintText: Translations.of(context) + .text("enter_code_hint"), + labelText: Translations.of(context) + .text("enter_code_label"), + labelStyle: TextStyle(fontWeight: FontWeight.w700)), + ), + new SizedBox( + height: 10.0, + ), + snapshot.data == false + ? new Offstage() + : new TextField( + onChanged: (myotp) => otp = myotp, + keyboardType: TextInputType.number, + style: new TextStyle( + fontSize: 15.0, color: Colors.black), + decoration: new InputDecoration( + hintText: Translations.of(context) + .text("enter_otp_hint"), + labelText: Translations.of(context) + .text("enter_otp_label"), + labelStyle: + TextStyle(fontWeight: FontWeight.w700)), + obscureText: true, + ), + new SizedBox( + height: 30.0, + ), + Container( + child: snapshot.data == false + ? new GradientButton( + onPressed: () => phoneNumber?.length == 10 + ? loginBloc.otpSink.add(UserLoginViewModel( + phonenumber: phoneNumber)) + : showPhoneError(context), + text: Translations.of(context).text("get_otp")) + : new GradientButton( + onPressed: () { + otp?.length == 4 + ? loginBloc.loginSink.add( + new UserLoginViewModel.withOTP( + phonenumber: phoneNumber, + otp: otp)) + : showOTPError(context); + }, + text: Translations.of(context).text("login")), + ), + snapshot.data == true + ? new FlatButton( + child: Text( + Translations.of(context).text("resend_otp")), + onPressed: () => + loginBloc.resendOtpSink.add(true), + ) + : new Container() + ], + ), + ), + ), + ), + ); + + Widget loginCard() { + return Opacity( + opacity: animation.value, + child: SizedBox( + height: deviceSize.height / 2 - 20, + width: deviceSize.width * 0.85, + child: new Card( + color: Colors.white, elevation: 2.0, child: loginBuilder()), + ), + ); + } + + @override + initState() { + // TODO: implement initState + super.initState(); + loginBloc = new LoginBloc(); + apiStreamSubscription = apiSubscription(loginBloc.apiResult, context); + controller = new AnimationController( + vsync: this, duration: new Duration(milliseconds: 1500)); + animation = new Tween(begin: 0.0, end: 1.0).animate( + new CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn)); + animation.addListener(() => this.setState(() {})); + controller.forward(); + } + + @override + void dispose() { + controller?.dispose(); + loginBloc?.dispose(); + apiStreamSubscription?.cancel(); + super.dispose(); + } + + showPhoneError(BuildContext context) { + LoginProvider.of(context) + .validationErrorCallback(LoginValidationType.phone); + } + + showOTPError(BuildContext context) { + LoginProvider.of(context).validationErrorCallback(LoginValidationType.otp); + } + + @override + Widget build(BuildContext context) { + deviceSize = MediaQuery.of(context).size; + return loginCard(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_one/login_widget.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_one/login_widget.dart new file mode 100644 index 00000000..910a6b2f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_one/login_widget.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +import 'login_card.dart'; + +class LoginWidgets extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Center( + child: SingleChildScrollView( + child: Column( + children: [ + SizedBox( + height: 100.0, + ), + LoginCard(), + // new Padding( + // padding: const EdgeInsets.only(top: 30.0), + // child: new Text( + // ISRData.forgot_password, + // style: new TextStyle(fontWeight: FontWeight.normal), + // ), + // ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_page.dart new file mode 100644 index 00000000..9e030f84 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_page.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/inherited/login_provider.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/login_background.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; + +import 'login_one/login_widget.dart'; + +enum LoginValidationType { phone, otp } + +class LoginPage extends StatefulWidget { + @override + LoginPageState createState() { + return LoginPageState(); + } +} + +class LoginPageState extends State { + final scaffoldState = GlobalKey(); + Widget loginScaffold() => LoginProvider( + validationErrorCallback: showValidationError, + child: Scaffold( + key: scaffoldState, + backgroundColor: Color(0xffeeeeee), + body: Stack( + fit: StackFit.expand, + children: [LoginBackground(), LoginWidgets()], + ), + ), + ); + + showValidationError(LoginValidationType type) { + scaffoldState.currentState.showSnackBar(SnackBar( + content: Text(type == LoginValidationType.phone + ? UIData.enter_valid_number + : UIData.enter_valid_otp), + duration: Duration(seconds: 2), + )); + } + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return loginScaffold(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_two_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_two_page.dart new file mode 100644 index 00000000..ca71b6e1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/login/login_two_page.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; + +class LoginTwoPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: Center( + child: loginBody(), + ), + ); + } + + loginBody() => SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [loginHeader(), loginFields()], + ), + ); + + loginHeader() => Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FlutterLogo( + // colors: Colors.green, + size: 80.0, + ), + SizedBox( + height: 30.0, + ), + Text( + "Welcome to ${UIData.appName}", + style: TextStyle(fontWeight: FontWeight.w700, color: Colors.green), + ), + SizedBox( + height: 5.0, + ), + Text( + "Sign in to continue", + style: TextStyle(color: Colors.grey), + ), + ], + ); + + loginFields() => Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 30.0), + child: TextField( + maxLines: 1, + decoration: InputDecoration( + hintText: "Enter your username", + labelText: "Username", + ), + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 0.0, horizontal: 30.0), + child: TextField( + maxLines: 1, + obscureText: true, + decoration: InputDecoration( + hintText: "Enter your password", + labelText: "Password", + ), + ), + ), + SizedBox( + height: 30.0, + ), + Container( + padding: EdgeInsets.symmetric(vertical: 0.0, horizontal: 30.0), + width: double.infinity, + child: RaisedButton( + padding: EdgeInsets.all(12.0), + shape: StadiumBorder(), + child: Text( + "SIGN IN", + style: TextStyle(color: Colors.white), + ), + color: Colors.green, + onPressed: () {}, + ), + ), + SizedBox( + height: 5.0, + ), + Text( + "SIGN UP FOR AN ACCOUNT", + style: TextStyle(color: Colors.grey), + ), + ], + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/notfound/notfound_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/notfound/notfound_page.dart new file mode 100644 index 00000000..1302c499 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/notfound/notfound_page.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import '../../widgets/common_scaffold.dart'; +import '../../widgets/profile_tile.dart'; + +class NotFoundPage extends StatelessWidget { + final appTitle; + final title; + final message; + final IconData icon; + final String image; + final iconColor; + + NotFoundPage( + {this.appTitle = "Search", + this.title = "No Result", + this.message = "Try a more general keyword.", + this.icon = Icons.search, + this.image, + this.iconColor = Colors.black}); + + Widget bodyData() => Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 100.0, + color: iconColor, + ), + SizedBox( + height: 20.0, + ), + ProfileTile( + title: title, + subtitle: message, + ) + ], + ), + ); + + @override + Widget build(BuildContext context) { + return CommonScaffold( + appTitle: appTitle, + bodyData: bodyData(), + showDrawer: false, + showFAB: false, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/payment/credit_card_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/payment/credit_card_page.dart new file mode 100644 index 00000000..7112c938 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/payment/credit_card_page.dart @@ -0,0 +1,227 @@ +import 'package:extended_masked_text/extended_masked_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/credit_card_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/profile_tile.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class CreditCardPage extends StatelessWidget { + BuildContext _context; + CreditCardBloc cardBloc; + MaskedTextController ccMask = + MaskedTextController(mask: "0000 0000 0000 0000"); + MaskedTextController expMask = MaskedTextController(mask: "00/00"); + Widget bodyData() => SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [creditCardWidget(), fillEntries()], + ), + ); + Widget creditCardWidget() { + var deviceSize = MediaQuery.of(_context).size; + return Container( + height: deviceSize.height * 0.3, + color: Colors.grey.shade300, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + clipBehavior: Clip.antiAlias, + elevation: 3.0, + child: Stack( + fit: StackFit.expand, + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: UIData.kitGradients)), + ), + Opacity( + opacity: 0.1, + child: Image.asset( + "assets/images/map.png", + fit: BoxFit.cover, + ), + ), + MediaQuery.of(_context).orientation == Orientation.portrait + ? cardEntries() + : FittedBox( + child: cardEntries(), + ), + Positioned( + right: 10.0, + top: 10.0, + child: Icon( + FontAwesomeIcons.ccVisa, + size: 30.0, + color: Colors.white, + ), + ), + Positioned( + right: 10.0, + bottom: 10.0, + child: StreamBuilder( + stream: cardBloc.nameOutputStream, + initialData: "Your Name", + builder: (context, snapshot) => Text( + snapshot.data.length > 0 ? snapshot.data : "Your Name", + style: TextStyle( + color: Colors.white, + fontFamily: UIData.ralewayFont, + fontSize: 20.0), + ), + ), + ), + ], + ), + ), + ), + ); + } + + Widget cardEntries() => Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StreamBuilder( + stream: cardBloc.ccOutputStream, + initialData: "**** **** **** ****", + builder: (context, snapshot) { + snapshot.data.length > 0 + ? ccMask.updateText(snapshot.data) + : null; + return Text( + snapshot.data.length > 0 + ? snapshot.data + : "**** **** **** ****", + style: TextStyle(color: Colors.white, fontSize: 22.0), + ); + }), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + StreamBuilder( + stream: cardBloc.expOutputStream, + initialData: "MM/YY", + builder: (context, snapshot) { + snapshot.data.length > 0 + ? expMask.updateText(snapshot.data) + : null; + return ProfileTile( + textColor: Colors.white, + title: "Expiry", + subtitle: + snapshot.data.length > 0 ? snapshot.data : "MM/YY", + ); + }), + SizedBox( + width: 30.0, + ), + StreamBuilder( + stream: cardBloc.cvvOutputStream, + initialData: "***", + builder: (context, snapshot) => ProfileTile( + textColor: Colors.white, + title: "CVV", + subtitle: + snapshot.data.length > 0 ? snapshot.data : "***", + )), + ], + ), + ], + ), + ); + + Widget fillEntries() => Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: ccMask, + keyboardType: TextInputType.number, + maxLength: 19, + style: TextStyle( + fontFamily: UIData.ralewayFont, color: Colors.black), + onChanged: (out) => cardBloc.ccInputSink.add(ccMask.text), + decoration: InputDecoration( + labelText: "Credit Card Number", + labelStyle: TextStyle(fontWeight: FontWeight.bold), + border: OutlineInputBorder()), + ), + TextField( + controller: expMask, + keyboardType: TextInputType.number, + maxLength: 5, + style: TextStyle( + fontFamily: UIData.ralewayFont, color: Colors.black), + onChanged: (out) => cardBloc.expInputSink.add(expMask.text), + decoration: InputDecoration( + labelStyle: TextStyle( + fontWeight: FontWeight.bold, + ), + labelText: "MM/YY", + border: OutlineInputBorder()), + ), + TextField( + keyboardType: TextInputType.number, + maxLength: 3, + style: TextStyle( + fontFamily: UIData.ralewayFont, color: Colors.black), + onChanged: (out) => cardBloc.cvvInputSink.add(out), + decoration: InputDecoration( + labelStyle: TextStyle(fontWeight: FontWeight.bold), + labelText: "CVV", + border: OutlineInputBorder()), + ), + TextField( + keyboardType: TextInputType.text, + maxLength: 20, + style: TextStyle( + fontFamily: UIData.ralewayFont, color: Colors.black), + onChanged: (out) => cardBloc.nameInputSink.add(out), + decoration: InputDecoration( + labelStyle: TextStyle( + fontWeight: FontWeight.bold, + ), + labelText: "Name on card", + border: OutlineInputBorder()), + ), + ], + ), + ); + + Widget floatingBar() => Ink( + decoration: ShapeDecoration( + shape: StadiumBorder(), + gradient: LinearGradient(colors: UIData.kitGradients)), + child: FloatingActionButton.extended( + onPressed: () {}, + backgroundColor: Colors.transparent, + icon: Icon( + FontAwesomeIcons.amazonPay, + color: Colors.white, + ), + label: Text( + "Continue", + style: TextStyle(color: Colors.white), + ), + ), + ); + + @override + Widget build(BuildContext context) { + _context = context; + cardBloc = CreditCardBloc(); + return Scaffold( + resizeToAvoidBottomInset: true, + appBar: AppBar( + centerTitle: false, + title: Text("Credit Card"), + ), + body: bodyData(), + floatingActionButton: floatingBar(), + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/payment/payment_success_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/payment/payment_success_page.dart new file mode 100644 index 00000000..daa5b944 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/payment/payment_success_page.dart @@ -0,0 +1,130 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/profile_tile.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class PaymentSuccessPage extends StatefulWidget { + @override + PaymentSuccessPageState createState() { + return new PaymentSuccessPageState(); + } +} + +class PaymentSuccessPageState extends State { + bool isDataAvailable = true; + Widget bodyData() => Center( + child: isDataAvailable + ? RaisedButton( + shape: StadiumBorder(), + onPressed: () => showSuccessDialog(), + color: Colors.amber, + child: Text("Process Payment"), + ) + : CircularProgressIndicator(), + ); + + @override + Widget build(BuildContext context) { + return CommonScaffold( + appTitle: "Payment Success", + actionFirstIcon: null, + bodyData: bodyData(), + ); + } + + void showSuccessDialog() { + setState(() { + isDataAvailable = false; + Future.delayed(Duration(seconds: 3)).then((_) => goToDialog()); + }); + } + + goToDialog() { + setState(() { + isDataAvailable = true; + }); + showDialog( + context: context, + barrierDismissible: true, + builder: (context) => Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + successTicket(), + SizedBox( + height: 10.0, + ), + FloatingActionButton( + backgroundColor: Colors.black, + child: Icon( + Icons.clear, + color: Colors.white, + ), + onPressed: () { + Navigator.pop(context); + }, + ) + ], + ), + ), + )); + } + + successTicket() => Container( + width: double.infinity, + padding: const EdgeInsets.all(16.0), + child: Material( + clipBehavior: Clip.antiAlias, + elevation: 2.0, + borderRadius: BorderRadius.circular(4.0), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + ProfileTile( + title: "Thank You!", + textColor: Colors.purple, + subtitle: "Your transaction was successful", + ), + ListTile( + title: Text("Date"), + subtitle: Text("26 June 2018"), + trailing: Text("11:00 AM"), + ), + ListTile( + title: Text("Pawan Kumar"), + subtitle: Text("mtechviral@gmail.com"), + trailing: CircleAvatar( + radius: 20.0, + backgroundImage: NetworkImage( + "https://avatars0.githubusercontent.com/u/12619420?s=460&v=4"), + ), + ), + ListTile( + title: Text("Amount"), + subtitle: Text("\$299"), + trailing: Text("Completed"), + ), + Card( + clipBehavior: Clip.antiAlias, + elevation: 0.0, + color: Colors.grey.shade300, + child: ListTile( + leading: Icon( + FontAwesomeIcons.ccAmex, + color: Colors.blue, + ), + title: Text("Credit/Debit Card"), + subtitle: Text("Amex Card ending ***6"), + ), + ) + ], + ), + ), + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/profile/profile_one_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/profile/profile_one_page.dart new file mode 100644 index 00000000..c5f89ac5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/profile/profile_one_page.dart @@ -0,0 +1,199 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_divider.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/profile_tile.dart'; + +class ProfileOnePage extends StatelessWidget { + var deviceSize; + + //Column1 + Widget profileColumn() => Container( + height: deviceSize.height * 0.24, + child: FittedBox( + alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + ProfileTile( + title: "Pawan Kumar", + subtitle: "Developer", + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + icon: Icon(Icons.chat), + color: Colors.black, + onPressed: () {}, + ), + Container( + decoration: BoxDecoration( + borderRadius: + new BorderRadius.all(new Radius.circular(40.0)), + border: new Border.all( + color: Colors.black, + width: 2.0, + ), + ), + child: CircleAvatar( + backgroundImage: NetworkImage( + "https://avatars0.githubusercontent.com/u/12619420?s=460&v=4"), + foregroundColor: Colors.black, + radius: 30.0, + ), + ), + IconButton( + icon: Icon(Icons.call), + color: Colors.black, + onPressed: () {}, + ), + ], + ), + ) + ], + ), + ), + ), + ); + + //column2 + + //column3 + Widget descColumn() => Container( + height: deviceSize.height * 0.13, + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 50.0), + child: Text( + "Google Developer Expert for Flutter. Passionate #Flutter, #Android Developer. #Entrepreneur #YouTuber", + style: TextStyle(fontWeight: FontWeight.w700), + textAlign: TextAlign.center, + maxLines: 3, + softWrap: true, + ), + ), + ), + ); + //column4 + Widget accountColumn() => FittedBox( + fit: BoxFit.fill, + child: Container( + height: deviceSize.height * 0.3, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + FittedBox( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ProfileTile( + title: "Website", + subtitle: "about.me/imthepk", + ), + SizedBox( + height: 10.0, + ), + ProfileTile( + title: "Phone", + subtitle: "+919876543210", + ), + SizedBox( + height: 10.0, + ), + ProfileTile( + title: "YouTube", + subtitle: "youtube.com/mtechviral", + ), + ], + ), + ), + FittedBox( + fit: BoxFit.cover, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ProfileTile( + title: "Location", + subtitle: "New Delhi", + ), + SizedBox( + height: 10.0, + ), + ProfileTile( + title: "Email", + subtitle: "mtechviral@gmail.com", + ), + SizedBox( + height: 10.0, + ), + ProfileTile( + title: "Facebook", + subtitle: "fb.com/imthepk", + ), + ], + ), + ), + ], + ), + ), + ); + + Widget bodyData() { + return SingleChildScrollView( + child: Column( + children: [ + profileColumn(), + CommonDivider(), + followColumn(deviceSize), + CommonDivider(), + descColumn(), + CommonDivider(), + accountColumn() + ], + ), + ); + } + + Widget _scaffold() => CommonScaffold( + appTitle: "View Profile", + bodyData: bodyData(), + showFAB: true, + showDrawer: true, + floatingIcon: Icons.person_add, + ); + + @override + Widget build(BuildContext context) { + deviceSize = MediaQuery.of(context).size; + return _scaffold(); + } +} + +Widget followColumn(Size deviceSize) => Container( + height: deviceSize.height * 0.13, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ProfileTile( + title: "1.5K", + subtitle: "Posts", + ), + ProfileTile( + title: "2.5K", + subtitle: "Followers", + ), + ProfileTile( + title: "10K", + subtitle: "Comments", + ), + ProfileTile( + title: "1.2K", + subtitle: "Following", + ) + ], + ), + ); diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/profile/profile_two_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/profile/profile_two_page.dart new file mode 100644 index 00000000..3ccd377d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/profile/profile_two_page.dart @@ -0,0 +1,158 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/page/profile/profile_one_page.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart'; + +class ProfileTwoPage extends StatelessWidget { + Size deviceSize; + + Widget profileHeader() => Container( + height: deviceSize.height / 4, + width: double.infinity, + color: Colors.black, + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Card( + clipBehavior: Clip.antiAlias, + color: Colors.black, + child: FittedBox( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50.0), + border: Border.all(width: 2.0, color: Colors.white)), + child: CircleAvatar( + radius: 40.0, + backgroundImage: NetworkImage( + "https://avatars0.githubusercontent.com/u/12619420?s=460&v=4"), + ), + ), + Text( + "Pawan Kumar", + style: TextStyle(color: Colors.white, fontSize: 20.0), + ), + Text( + "Flutter Developer", + style: TextStyle(color: Colors.white), + ) + ], + ), + ), + ), + ), + ); + Widget imagesCard() => Container( + height: deviceSize.height / 6, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 5.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "Photos", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0), + ), + ), + Expanded( + child: Card( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: 5, + itemBuilder: (context, i) => Padding( + padding: const EdgeInsets.all(8.0), + child: Image.network( + "https://cdn.pixabay.com/photo/2016/10/31/18/14/ice-1786311_960_720.jpg"), + ), + ), + ), + ), + ], + ), + ), + ); + + Widget profileColumn() => Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + CircleAvatar( + backgroundImage: NetworkImage( + "https://avatars0.githubusercontent.com/u/12619420?s=460&v=4"), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Pawan Kumar posted a photo", + ), + SizedBox( + height: 5.0, + ), + Text( + "25 mins ago", + ) + ], + ), + )) + ], + ), + ); + + Widget postCard() => Container( + width: double.infinity, + height: deviceSize.height / 3, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 18.0, vertical: 5.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "Post", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0), + ), + ), + profileColumn(), + Expanded( + child: Card( + elevation: 2.0, + child: Image.network( + "https://cdn.pixabay.com/photo/2018/06/12/01/04/road-3469810_960_720.jpg", + fit: BoxFit.cover, + ), + ), + ), + ], + ), + ), + ); + Widget bodyData() => SingleChildScrollView( + child: Column( + children: [ + profileHeader(), + followColumn(deviceSize), + imagesCard(), + postCard(), + ], + ), + ); + + @override + Widget build(BuildContext context) { + deviceSize = MediaQuery.of(context).size; + return CommonScaffold( + appTitle: "Profile", + bodyData: bodyData(), + elevation: 0.0, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/settings/settings_one_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/settings/settings_one_page.dart new file mode 100644 index 00000000..b52c6ddb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/settings/settings_one_page.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_switch.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; + +class SettingsOnePage extends StatelessWidget { + Widget bodyData() => SingleChildScrollView( + child: Theme( + data: ThemeData(fontFamily: UIData.ralewayFont), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + //1 + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + "General Setting", + style: TextStyle(color: Colors.grey.shade700), + ), + ), + Card( + color: Colors.white, + elevation: 2.0, + child: Column( + children: [ + ListTile( + leading: Icon( + Icons.person, + color: Colors.grey, + ), + title: Text("Account"), + trailing: Icon(Icons.arrow_right), + ), + ListTile( + leading: Icon( + Icons.mail, + color: Colors.red, + ), + title: Text("Gmail"), + trailing: Icon(Icons.arrow_right), + ), + ListTile( + leading: Icon( + Icons.sync, + color: Colors.blue, + ), + title: Text("Sync Data"), + trailing: Icon(Icons.arrow_right), + ) + ], + ), + ), + + //2 + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + "Network", + style: TextStyle(color: Colors.grey.shade700), + ), + ), + Card( + color: Colors.white, + elevation: 2.0, + child: Column( + children: [ + ListTile( + leading: Icon( + Icons.sim_card, + color: Colors.grey, + ), + title: Text("Simcard & Network"), + trailing: Icon(Icons.arrow_right), + ), + ListTile( + leading: Icon( + Icons.wifi, + color: Colors.amber, + ), + title: Text("Wifi"), + trailing: CommonSwitch( + defValue: true, + )), + ListTile( + leading: Icon( + Icons.bluetooth, + color: Colors.blue, + ), + title: Text("Bluetooth"), + trailing: CommonSwitch( + defValue: false, + ), + ), + ListTile( + leading: Icon( + Icons.more_horiz, + color: Colors.grey, + ), + title: Text("More"), + trailing: Icon(Icons.arrow_right), + ), + ], + ), + ), + + //3 + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + "Sound", + style: TextStyle(color: Colors.grey.shade700), + ), + ), + Card( + color: Colors.white, + elevation: 2.0, + child: Column( + children: [ + ListTile( + leading: Icon( + Icons.do_not_disturb_off, + color: Colors.orange, + ), + title: Text("Silent Mode"), + trailing: CommonSwitch( + defValue: false, + ), + ), + ListTile( + leading: Icon( + Icons.vibration, + color: Colors.purple, + ), + title: Text("Vibrate Mode"), + trailing: CommonSwitch( + defValue: true, + ), + ), + ListTile( + leading: Icon( + Icons.volume_up, + color: Colors.green, + ), + title: Text("Sound Volume"), + trailing: Icon(Icons.arrow_right), + ), + ListTile( + leading: Icon( + Icons.phonelink_ring, + color: Colors.grey, + ), + title: Text("Ringtone"), + trailing: Icon(Icons.arrow_right), + ) + ], + ), + ), + ], + ), + ), + ); + + @override + Widget build(BuildContext context) { + return CommonScaffold( + appTitle: "Device Settings", + showDrawer: false, + showFAB: false, + backGroundColor: Colors.grey.shade300, + bodyData: bodyData(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/product_detail_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/product_detail_page.dart new file mode 100644 index 00000000..ee404e46 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/product_detail_page.dart @@ -0,0 +1,41 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/inherited/product_provider.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/product_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/product.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/login_background.dart'; + +import 'shopping_two/product_detail_widgets.dart'; +// import 'package:flutter_uikit/inherited/product_provider.dart'; +// import 'package:flutter_uikit/logic/bloc/product_bloc.dart'; +// import 'package:flutter_uikit/model/product.dart'; +// import 'package:flutter_uikit/ui/page/shopping/shopping_two/product_detail_widgets.dart'; +// import 'package:flutter_uikit/ui/widgets/login_background.dart'; + +class ProductDetailPage extends StatelessWidget { + Widget productScaffold(Stream> products) => new Scaffold( + backgroundColor: new Color(0xffeeeeee), + body: StreamBuilder>( + stream: products, + builder: (context, snapshot) { + return snapshot.hasData + ? Stack( + fit: StackFit.expand, + children: [ + LoginBackground( + showIcon: false, + ), + ProductDetailWidgets(product:snapshot.data[0]), + ], + ) + : Center(child: CircularProgressIndicator()); + })); + @override + Widget build(BuildContext context) { + ProductBloc productBloc = ProductBloc(); + return ProductProvider( + productBloc: productBloc, + child: productScaffold(productBloc.productItems)); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details/shopping_action.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details/shopping_action.dart new file mode 100644 index 00000000..6d8ef38e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details/shopping_action.dart @@ -0,0 +1,150 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/cart_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/product.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_divider.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/custom_float.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class ShoppingAction extends StatefulWidget { + final Product product; + ShoppingAction({this.product}); + + @override + ShoppingActionState createState() { + return new ShoppingActionState(); + } +} + +class ShoppingActionState extends State { + String _value = "Cyan"; + String _sizeValue = "M"; + + Widget colorsCard() => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Colors", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 20.0), + ), + SizedBox( + height: 10.0, + ), + Wrap( + alignment: WrapAlignment.spaceBetween, + children: widget.product.colors + .map((pc) => Padding( + padding: const EdgeInsets.all(8.0), + child: ChoiceChip( + selectedColor: pc.color, + label: Text( + pc.colorName, + style: TextStyle(fontWeight: FontWeight.bold), + ), + selected: _value == pc.colorName, + onSelected: (selected) { + setState(() { + _value = selected ? pc.colorName : null; + }); + }), + )) + .toList(), + ), + ], + ); + + Widget sizesCard() => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Sizes", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 20.0), + ), + SizedBox( + height: 10.0, + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: widget.product.sizes + .map((pc) => Padding( + padding: const EdgeInsets.all(8.0), + child: ChoiceChip( + selectedColor: Colors.yellow, + label: Text( + pc, + style: TextStyle(fontWeight: FontWeight.bold), + ), + selected: _sizeValue == pc, + onSelected: (selected) { + setState(() { + _sizeValue = selected ? pc : null; + }); + }), + )) + .toList(), + ), + ], + ); + + Widget quantityCard() { + CartBloc cartBloc = CartBloc(widget.product); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Sizes", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 20.0), + ), + SizedBox( + height: 10.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + CustomFloat( + isMini: true, + icon: FontAwesomeIcons.minus, + qrCallback: () => cartBloc.subtractionController.add(true), + ), + StreamBuilder( + stream: cartBloc.getCount, + initialData: 0, + builder: (context, snapshot) => Text( + snapshot.data.toString(), + style: + TextStyle(fontWeight: FontWeight.w700, fontSize: 20.0), + ), + ), + CustomFloat( + isMini: true, + icon: FontAwesomeIcons.plus, + qrCallback: () => cartBloc.additionalController.add(true), + ), + ], + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + colorsCard(), + CommonDivider(), + SizedBox( + height: 5.0, + ), + sizesCard(), + CommonDivider(), + SizedBox( + height: 5.0, + ), + quantityCard(), + SizedBox( + height: 20.0, + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details/shopping_widget.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details/shopping_widget.dart new file mode 100644 index 00000000..7dadcf88 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details/shopping_widget.dart @@ -0,0 +1,128 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/product.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/label_icon.dart'; + +import 'shopping_action.dart'; + +class ShoppingWidgets extends StatelessWidget { + Size deviceSize; + final Product product; + + ShoppingWidgets({Key key, this.product}) : super(key: key); + Widget mainCard() => Padding( + padding: const EdgeInsets.symmetric(horizontal: 18.0), + child: Card( + elevation: 2.0, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + product.name, + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 20.0), + ), + SizedBox( + height: 10.0, + ), + Text(product.brand), + SizedBox( + height: 10.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LabelIcon( + icon: Icons.star, + iconColor: Colors.cyan, + label: product.rating.toString(), + ), + Text( + product.price, + style: TextStyle( + color: Colors.orange.shade800, + fontWeight: FontWeight.w700, + fontSize: 25.0), + ) + ], + ) + ], + ), + ), + ), + ); + + Widget imagesCard() => SizedBox( + height: deviceSize.height / 5, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 18.0), + child: Card( + elevation: 2.0, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: 5, + itemBuilder: (context, i) => Padding( + padding: const EdgeInsets.all(8.0), + child: Image.network(product.image), + ), + ), + ), + ), + ); + + Widget descCard() => Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 18.0), + child: Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Description", + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.w700, + ), + ), + SizedBox( + height: 5.0, + ), + Text( + product.description, + style: + TextStyle(fontSize: 15.0, fontWeight: FontWeight.normal), + ), + ], + ), + ), + ), + ); + + Widget actionCard() => Padding( + padding: const EdgeInsets.symmetric(horizontal: 18.0), + child: Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ShoppingAction(product: product)), + ), + ); + @override + Widget build(BuildContext context) { + deviceSize = MediaQuery.of(context).size; + return SingleChildScrollView( + child: Column( + children: [ + SizedBox( + height: deviceSize.height / 4, + ), + mainCard(), + imagesCard(), + descCard(), + actionCard(), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details_page.dart new file mode 100644 index 00000000..32d28892 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_details_page.dart @@ -0,0 +1,57 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/inherited/product_provider.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/product_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/product.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/page/shopping/shopping_details/shopping_widget.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/login_background.dart'; +// import 'package:flutter_uikit/inherited/product_provider.dart'; +// import 'package:flutter_uikit/logic/bloc/product_bloc.dart'; +// import 'package:flutter_uikit/model/product.dart'; +// import 'package:flutter_uikit/ui/page/shopping/shopping_details/shopping_widget.dart'; +// import 'package:flutter_uikit/ui/widgets/common_scaffold.dart'; +// import 'package:flutter_uikit/ui/widgets/login_background.dart'; + +class ShoppingDetailsPage extends StatelessWidget { + final _scaffoldState = GlobalKey(); + + Widget bodyData(Stream> products) => + StreamBuilder>( + stream: products, + builder: (context, snapshot) { + return snapshot.hasData + ? Stack( + fit: StackFit.expand, + children: [ + LoginBackground( + showIcon: false, + image: snapshot.data[0].image, + ), + ShoppingWidgets(product: snapshot.data[0]), + ], + ) + : Center(child: CircularProgressIndicator()); + }); + + @override + Widget build(BuildContext context) { + ProductBloc productBloc = ProductBloc(); + return ProductProvider( + productBloc: productBloc, + child: CommonScaffold( + backGroundColor: Colors.grey.shade100, + actionFirstIcon: null, + appTitle: "Product Detail", + showFAB: true, + scaffoldKey: _scaffoldState, + showDrawer: false, + centerDocked: true, + floatingIcon: Icons.add_shopping_cart, + bodyData: bodyData(productBloc.productItems), + showBottomNav: true, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_one_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_one_page.dart new file mode 100644 index 00000000..a0ba386d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_one_page.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/product_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/product.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart'; +// import 'package:flutter_uikit/logic/bloc/product_bloc.dart'; +// import 'package:flutter_uikit/model/product.dart'; +// import 'package:flutter_uikit/ui/widgets/common_scaffold.dart'; + +class ShoppingOnePage extends StatelessWidget { + final scaffoldKey = GlobalKey(); + BuildContext _context; + + //stack1 + Widget imageStack(String img) => Image.network( + img, + fit: BoxFit.cover, + ); + + //stack2 + Widget descStack(Product product) => Positioned( + bottom: 0.0, + left: 0.0, + right: 0.0, + child: Container( + decoration: BoxDecoration(color: Colors.black.withOpacity(0.5)), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + product.name, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Colors.white), + ), + ), + Text(product.price, + style: TextStyle( + color: Colors.yellow, + fontSize: 18.0, + fontWeight: FontWeight.bold)) + ], + ), + ), + ), + ); + + //stack3 + Widget ratingStack(double rating) => Positioned( + top: 0.0, + left: 0.0, + child: Container( + padding: EdgeInsets.all(4.0), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.9), + borderRadius: BorderRadius.only( + topRight: Radius.circular(10.0), + bottomRight: Radius.circular(10.0))), + child: Row( + children: [ + Icon( + Icons.star, + color: Colors.cyanAccent, + size: 10.0, + ), + SizedBox( + width: 2.0, + ), + Text( + rating.toString(), + style: TextStyle(color: Colors.white, fontSize: 10.0), + ) + ], + ), + ), + ); + + Widget productGrid(List products) => GridView.count( + crossAxisCount: + MediaQuery.of(_context).orientation == Orientation.portrait ? 2 : 3, + shrinkWrap: true, + children: products + .map((product) => Padding( + padding: const EdgeInsets.all(8.0), + child: InkWell( + splashColor: Colors.yellow, + onDoubleTap: () => showSnackBar(), + child: Material( + clipBehavior: Clip.antiAlias, + elevation: 2.0, + child: Stack( + fit: StackFit.expand, + children: [ + imageStack(product.image), + descStack(product), + ratingStack(product.rating), + ], + ), + ), + ), + )) + .toList(), + ); + + Widget bodyData() { + ProductBloc productBloc = ProductBloc(); + return StreamBuilder>( + stream: productBloc.productItems, + builder: (context, snapshot) { + return snapshot.hasData + ? productGrid(snapshot.data) + : Center(child: CircularProgressIndicator()); + }); + } + + void showSnackBar() { + scaffoldKey.currentState.showSnackBar(SnackBar( + content: Text( + "Added to cart.", + ), + action: SnackBarAction( + label: "Undo", + onPressed: () {}, + ), + )); + } + + @override + Widget build(BuildContext context) { + _context = context; + return CommonScaffold( + scaffoldKey: scaffoldKey, + appTitle: "Products", + showDrawer: true, + showFAB: false, + actionFirstIcon: Icons.shopping_cart, + bodyData: bodyData(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_card.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_card.dart new file mode 100644 index 00000000..afb77be2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_card.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/product.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; + +import 'product_desc.dart'; +// import 'package:flutter_uikit/model/product.dart'; +// import 'package:flutter_uikit/ui/page/shopping/shopping_two/product_desc.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class ProductCard extends StatefulWidget { + final Product product; + + const ProductCard({Key key, this.product}) : super(key: key); + @override + _ProductCardState createState() => new _ProductCardState(); +} + +class _ProductCardState extends State + with SingleTickerProviderStateMixin { + var deviceSize; + AnimationController controller; + Animation animation; + + Widget productCard() { + var cardHeight = deviceSize.height * 0.8; + var cardWidth = deviceSize.width * 0.85; + return Card( + clipBehavior: Clip.antiAlias, + elevation: 1.0, + shape: new RoundedRectangleBorder( + borderRadius: new BorderRadius.circular(15.0)), + color: Colors.white, + child: Ink( + height: cardHeight, + width: cardWidth, + child: new Stack( + children: [ + Container( + height: cardHeight - cardHeight / 2 * 1.1, + width: double.infinity, + child: new Image.network( + widget.product.image, + fit: BoxFit.cover, + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: new Container( + width: double.infinity, + height: cardHeight / 2 * 1.2, + decoration: new BoxDecoration( + gradient: new LinearGradient(colors: UIData.kitGradients), + borderRadius: new BorderRadius.only( + topLeft: const Radius.circular(30.0), + topRight: const Radius.circular(30.0)), + color: Colors.white, + ), + child: new ProductDesc(product: widget.product), + ), + ), + ], + ), + ), + ); + } + + @override + initState() { + super.initState(); + controller = new AnimationController( + vsync: this, duration: new Duration(milliseconds: 1500)); + animation = new Tween(begin: 0.0, end: 1.0).animate( + new CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn)); + animation.addListener(() => this.setState(() {})); + controller.forward(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + deviceSize = MediaQuery.of(context).size; + return productCard(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_desc.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_desc.dart new file mode 100644 index 00000000..6c848e7e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_desc.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/product.dart'; +// import 'package:flutter_uikit/model/product.dart'; + +class ProductDesc extends StatelessWidget { + final Product product; + + const ProductDesc({Key key, this.product}) : super(key: key); + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: new Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: new ListTile( + title: new Text( + product.name, + style: new TextStyle( + fontSize: 18.0, + color: Colors.white, + fontWeight: FontWeight.w700), + ), + subtitle: new Text( + product.brand, + style: new TextStyle( + fontSize: 15.0, + color: Colors.white, + fontWeight: FontWeight.normal), + ), + trailing: new Text(product.price, + style: new TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.bold, + color: Colors.yellow)), + ), + ), + new SizedBox( + height: 10.0, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 28.0), + child: new Text( + product.description, + style: TextStyle(color: Colors.white), + textAlign: TextAlign.start, + ), + ), + new SizedBox( + height: 30.0, + ), + new Card( + clipBehavior: Clip.antiAlias, + shape: new RoundedRectangleBorder( + borderRadius: new BorderRadius.circular(8.0)), + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + new Text( + "Your Size", + style: TextStyle(fontWeight: FontWeight.w700), + ), + new RawChip( + label: new Text( + "M", + style: TextStyle(color: Colors.white), + ), + backgroundColor: Colors.cyan) + ], + ), + new Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + new Text("Color", + style: TextStyle(fontWeight: FontWeight.w700)), + new RawChip( + label: new Text( + "Red Blue", + style: TextStyle(color: Colors.white), + ), + backgroundColor: Colors.red, + ) + ], + ), + new Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + new Text("Product ID", + style: TextStyle(fontWeight: FontWeight.w700)), + new RawChip( + label: new Text( + "PQ1001", + style: TextStyle(color: Colors.white), + ), + backgroundColor: Colors.green, + ) + ], + ) + ], + ), + ), + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_detail_widgets.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_detail_widgets.dart new file mode 100644 index 00000000..c61cec46 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/shopping/shopping_two/product_detail_widgets.dart @@ -0,0 +1,115 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/cart_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/product.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; + +import 'product_card.dart'; +// import 'package:flutter_uikit/logic/bloc/cart_bloc.dart'; +// import 'package:flutter_uikit/model/product.dart'; +// import 'package:flutter_uikit/ui/page/shopping/shopping_two/product_card.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class ProductDetailWidgets extends StatelessWidget { + final Product product; + + const ProductDetailWidgets({Key key, this.product}) : super(key: key); + + Widget appBarColumn(BuildContext context) => new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new IconButton( + icon: new Icon( + defaultTargetPlatform == TargetPlatform.android + ? Icons.arrow_back + : Icons.arrow_back_ios, + color: Colors.white, + ), + onPressed: () => + Navigator.canPop(context) ? Navigator.pop(context) : null, + ), + new Text( + "Product Detail", + style: new TextStyle(color: Colors.white, fontSize: 20.0), + ), + new Opacity( + opacity: 0.0, + child: new IconButton( + icon: new Icon( + Icons.arrow_back, + color: Colors.white, + ), + onPressed: () {}, + ), + ) + ], + ), + new SizedBox( + height: 10.0, + ), + ProductCard(product: product) + ], + ); + Widget quantityCard(Size deviceSize, CartBloc cartBloc) => new Positioned( + top: (deviceSize.height - deviceSize.height * 0.1), + left: deviceSize.width / 2 - deviceSize.width / 5, + width: deviceSize.width / 2 - 30, + child: new Material( + clipBehavior: Clip.antiAlias, + shape: new StadiumBorder(), + shadowColor: Colors.black, + elevation: 2.0, + color: Colors.transparent, + child: Ink( + decoration: new BoxDecoration( + gradient: new LinearGradient(colors: UIData.kitGradients), + ), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new IconButton( + icon: new Icon( + Icons.remove, + color: Colors.white, + ), + onPressed: () => cartBloc.subtractionController.add(true), + ), + StreamBuilder( + stream: cartBloc.getCount, + initialData: 0, + builder: (context, snapshot) => new Text( + snapshot.data.toString(), + style: new TextStyle( + color: Colors.white, + fontSize: 18.0, + fontWeight: FontWeight.bold), + ), + ), + new IconButton( + icon: new Icon( + Icons.add, + color: Colors.white, + ), + onPressed: () => cartBloc.additionalController.add(true), + ) + ], + ), + ), + ), + ); + @override + Widget build(BuildContext context) { + var deviceSize = MediaQuery.of(context).size; + CartBloc cartBloc = CartBloc(product); + return Stack( + fit: StackFit.expand, + children: [ + appBarColumn(context), + quantityCard(deviceSize, cartBloc), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/timeline/timeline_one_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/timeline/timeline_one_page.dart new file mode 100644 index 00000000..ea7e1f19 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/timeline/timeline_one_page.dart @@ -0,0 +1,178 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/post_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/post.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_divider.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_drawer.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/label_icon.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/logic/bloc/post_bloc.dart'; +// import 'package:flutter_uikit/model/post.dart'; +// import 'package:flutter_uikit/ui/widgets/common_divider.dart'; +// import 'package:flutter_uikit/ui/widgets/common_drawer.dart'; +// import 'package:flutter_uikit/ui/widgets/label_icon.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class TimelineOnePage extends StatelessWidget { + //column1 + Widget profileColumn(BuildContext context, Post post) => Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + CircleAvatar( + backgroundImage: NetworkImage(post.personImage), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + post.personName, + style: Theme.of(context) + .textTheme + .body1 + .apply(fontWeightDelta: 700), + ), + SizedBox( + height: 5.0, + ), + Text( + post.address, + style: Theme.of(context).textTheme.caption.apply( + fontFamily: UIData.ralewayFont, color: Colors.pink), + ) + ], + ), + )) + ], + ); + + //column last + Widget actionColumn(Post post) => FittedBox( + fit: BoxFit.contain, + child: ButtonBar( + alignment: MainAxisAlignment.center, + children: [ + LabelIcon( + label: "${post.likesCount} Likes", + icon: FontAwesomeIcons.solidThumbsUp, + iconColor: Colors.green, + ), + LabelIcon( + label: "${post.commentsCount} Comments", + icon: FontAwesomeIcons.comment, + iconColor: Colors.blue, + ), + Text( + post.postTime, + style: TextStyle(fontFamily: UIData.ralewayFont), + ) + ], + ), + ); + + //post cards + Widget postCard(BuildContext context, Post post) { + return Card( + elevation: 2.0, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: profileColumn(context, post), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + post.message, + style: TextStyle( + fontWeight: FontWeight.normal, + fontFamily: UIData.ralewayFont), + ), + ), + SizedBox( + height: 10.0, + ), + post.messageImage != null + ? Image.network( + post.messageImage, + fit: BoxFit.cover, + ) + : Container(), + post.messageImage != null ? Container() : CommonDivider(), + actionColumn(post), + ], + ), + ); + } + + //allposts dropdown + Widget bottomBar() => PreferredSize( + preferredSize: Size(double.infinity, 50.0), + child: Container( + color: Colors.black, + child: Align( + alignment: Alignment.bottomCenter, + child: Container( + height: 50.0, + padding: const EdgeInsets.symmetric(horizontal: 10.0), + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "All Posts", + style: TextStyle( + color: Colors.black, fontWeight: FontWeight.w700), + ), + Icon(Icons.arrow_drop_down) + ], + ), + ), + ))); + + Widget appBar() => SliverAppBar( + backgroundColor: Colors.black, + elevation: 2.0, + title: Text("Feed"), + forceElevated: true, + pinned: true, + floating: true, + bottom: bottomBar(), + ); + + Widget bodyList(List posts) => SliverList( + delegate: SliverChildBuilderDelegate((BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: postCard(context, posts[index]), + ); + }, childCount: posts.length), + ); + + Widget bodySliverList() { + PostBloc postBloc = PostBloc(); + return StreamBuilder>( + stream: postBloc.postItems, + builder: (context, snapshot) { + return snapshot.hasData + ? CustomScrollView( + slivers: [ + appBar(), + bodyList(snapshot.data), + ], + ) + : Center(child: CircularProgressIndicator()); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + drawer: CommonDrawer(), + body: bodySliverList(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/timeline/timeline_two_page.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/timeline/timeline_two_page.dart new file mode 100644 index 00000000..3829edfd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/page/timeline/timeline_two_page.dart @@ -0,0 +1,232 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/logic/bloc/post_bloc.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/post.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/widgets/common_drawer.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/logic/bloc/post_bloc.dart'; +// import 'package:flutter_uikit/model/post.dart'; +// import 'package:flutter_uikit/ui/widgets/common_drawer.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class TimelineTwoPage extends StatefulWidget { + @override + TimelineTwoPageState createState() { + return new TimelineTwoPageState(); + } +} + +class TimelineTwoPageState extends State { + ScrollController scrollController; + PostBloc postBloc; + + Widget bodyData() { + return StreamBuilder>( + stream: postBloc.postItems, + builder: (context, snapshot) { + return snapshot.hasData + ? bodyList(snapshot.data) + : Center(child: CircularProgressIndicator()); + }); + } + + Widget actionRow(Post post) => Padding( + padding: const EdgeInsets.only(right: 50.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon( + FontAwesomeIcons.comment, + size: 15.0, + color: Colors.grey, + ), + Icon( + FontAwesomeIcons.retweet, + size: 15.0, + color: Colors.grey, + ), + Icon( + FontAwesomeIcons.heart, + size: 15.0, + color: Colors.grey, + ), + Icon( + FontAwesomeIcons.share, + size: 15.0, + color: Colors.grey, + ) + ], + ), + ); + + Widget rightColumn(Post post) => Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 16.0, right: 4.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: RichText( + maxLines: 1, + text: TextSpan(children: [ + TextSpan( + text: "${post.personName} ", + ), + TextSpan( + text: "@${post.address} · ", + style: TextStyle(color: Colors.grey)), + TextSpan( + text: "${post.postTime}", + style: TextStyle(color: Colors.grey)) + ]), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + post.message, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.normal, + fontFamily: UIData.quickFont), + ), + ), + SizedBox( + height: 10.0, + ), + post.messageImage != null + ? Material( + borderRadius: BorderRadius.circular(8.0), + child: Image.network( + post.messageImage, + gaplessPlayback: true, + fit: BoxFit.cover, + ), + ) + : Container(), + SizedBox( + height: 20.0, + ), + actionRow(post), + ], + ), + ), + ); + + Widget bodyList(List posts) => ListView.builder( + controller: scrollController, + itemCount: posts.length, + itemBuilder: (context, i) { + Post post = posts[i]; + return Card( + color: Colors.grey.shade900, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CircleAvatar( + radius: 25.0, + backgroundImage: NetworkImage( + post.personImage, + )), + rightColumn(post), + ], + ), + ), + ); + }, + ); + + @override + void initState() { + // TODO: implement initState + super.initState(); + scrollController = ScrollController(); + postBloc = PostBloc(); + scrollController.addListener(() { + if (scrollController.position.userScrollDirection == + ScrollDirection.reverse) postBloc.fabSink.add(false); + if (scrollController.position.userScrollDirection == + ScrollDirection.forward) postBloc.fabSink.add(true); + }); + } + + @override + void dispose() { + // TODO: implement dispose + postBloc?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey.shade900, + appBar: AppBar( + centerTitle: false, + title: Text("Tweet"), + ), + body: bodyData(), + drawer: CommonDrawer(), + floatingActionButton: StreamBuilder( + stream: postBloc.fabVisible, + initialData: true, + builder: (context, snapshot) => AnimatedOpacity( + duration: Duration(milliseconds: 200), + opacity: snapshot.data ? 1.0 : 0.0, + child: FloatingActionButton( + onPressed: () {}, + backgroundColor: Colors.white, + child: CustomPaint( + child: Container(), + foregroundPainter: FloatingPainter(), + ), + ), + ), + ), + ); + } +} + +class FloatingPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + Paint amberPaint = Paint() + ..color = Colors.amber + ..strokeWidth = 5; + + Paint greenPaint = Paint() + ..color = Colors.green + ..strokeWidth = 5; + + Paint bluePaint = Paint() + ..color = Colors.blue + ..strokeWidth = 5; + + Paint redPaint = Paint() + ..color = Colors.red + ..strokeWidth = 5; + + canvas.drawLine(Offset(size.width * 0.27, size.height * 0.5), + Offset(size.width * 0.5, size.height * 0.5), amberPaint); + canvas.drawLine( + Offset(size.width * 0.5, size.height * 0.5), + Offset(size.width * 0.5, size.height - (size.height * 0.27)), + greenPaint); + canvas.drawLine(Offset(size.width * 0.5, size.height * 0.5), + Offset(size.width - (size.width * 0.27), size.height * 0.5), bluePaint); + canvas.drawLine(Offset(size.width * 0.5, size.height * 0.5), + Offset(size.width * 0.5, size.height * 0.27), redPaint); + } + + @override + bool shouldRepaint(FloatingPainter oldDelegate) => false; + + @override + bool shouldRebuildSemantics(FloatingPainter oldDelegate) => false; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/tools/arc_clipper.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/tools/arc_clipper.dart new file mode 100644 index 00000000..f3e508ec --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/tools/arc_clipper.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +class ArcClipper extends CustomClipper { + @override + Path getClip(Size size) { + var path = new Path(); + path.lineTo(0.0, size.height - 30); + + var firstControlPoint = new Offset(size.width / 4, size.height); + var firstPoint = new Offset(size.width / 2, size.height); + path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy, + firstPoint.dx, firstPoint.dy); + + var secondControlPoint = + new Offset(size.width - (size.width / 4), size.height); + var secondPoint = new Offset(size.width, size.height - 30); + path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy, + secondPoint.dx, secondPoint.dy); + + path.lineTo(size.width, 0.0); + path.close(); + + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) => false; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/about_tile.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/about_tile.dart new file mode 100644 index 00000000..72196b3b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/about_tile.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; + +class MyAboutTile extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AboutListTile( + applicationIcon: FlutterLogo( + // colors: Colors.yellow, + ), + icon: FlutterLogo( + // colors: Colors.yellow, + ), + aboutBoxChildren: [ + SizedBox( + height: 10.0, + ), + Text( + "Developed By Pawan Kumar", + ), + Text( + "MTechViral", + ), + ], + applicationName: UIData.appName, + applicationVersion: "1.0.1", + applicationLegalese: "Apache License 2.0", + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/api_subscription.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/api_subscription.dart new file mode 100644 index 00000000..565c6ffa --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/api_subscription.dart @@ -0,0 +1,42 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/model/fetch_process.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/model/fetch_process.dart'; +// import 'package:flutter_uikit/ui/widgets/common_dialogs.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +import 'common_dialogs.dart'; + +apiSubscription(Stream apiResult, BuildContext context) { + apiResult.listen((FetchProcess p) { + if (p.loading) { + showProgress(context); + } else { + hideProgress(context); + if (p.response.success == false) { + fetchApiResult(context, p.response); + } else { + switch (p.type) { + case ApiType.performLogin: + showSuccess(context, UIData.success, FontAwesomeIcons.check); + break; + case ApiType.getProductInfo: + break; + case ApiType.performOTP: + break; + } + } + } + }); +} + +// void afterLogin(FetchProcess p, BuildContext context) { +// NetworkServiceResponse res = p.response; +// ISRData.prefs.setString(ISRData.pref_auth_token, res.content.data.authToken); +// ISRData.prefs.setString(ISRData.pref_user_id, res.content.data.userId); +// ISRData.prefs.setBool(ISRData.pref_logged_in, true); +// Navigator.of(context).pushReplacementNamed(ISRData.homeRoute); +// } diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_dialogs.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_dialogs.dart new file mode 100644 index 00000000..42f85b1d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_dialogs.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/services/network_service_response.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/services/network_service_response.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +fetchApiResult(BuildContext context, NetworkServiceResponse snapshot) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(UIData.error), + content: Text(snapshot.message), + actions: [ + FlatButton( + child: Text(UIData.ok), + onPressed: () => Navigator.pop(context), + ) + ], + ), + ); +} + +showSuccess(BuildContext context, String message, IconData icon) { + showDialog( + context: context, + builder: (context) => Center( + child: Material( + borderRadius: BorderRadius.circular(8.0), + color: Colors.black, + elevation: 5.0, + child: Padding( + padding: const EdgeInsets.all(32.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + color: Colors.green, + ), + SizedBox( + height: 10.0, + ), + Text( + message, + style: TextStyle( + fontFamily: UIData.ralewayFont, color: Colors.white), + ) + ], + ), + ), + ), + )); +} + +showProgress(BuildContext context) { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => Center( + child: CircularProgressIndicator( + backgroundColor: Colors.yellow, + ), + )); +} + +hideProgress(BuildContext context) { + Navigator.pop(context); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_divider.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_divider.dart new file mode 100644 index 00000000..88bcf7be --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_divider.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; + +class CommonDivider extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Divider( + color: Colors.grey.shade300, + height: 8.0, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_drawer.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_drawer.dart new file mode 100644 index 00000000..015e32b7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_drawer.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; + +import 'about_tile.dart'; +// import 'package:flutter_uikit/ui/widgets/about_tile.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class CommonDrawer extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Drawer( + child: ListView( + padding: EdgeInsets.zero, + children: [ + UserAccountsDrawerHeader( + accountName: Text( + "Pawan Kumar", + ), + accountEmail: Text( + "mtechviral@gmail.com", + ), + currentAccountPicture: new CircleAvatar( + backgroundImage: new AssetImage(UIData.pkImage), + ), + ), + new ListTile( + title: Text( + "Profile", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0), + ), + leading: Icon( + Icons.person, + color: Colors.blue, + ), + ), + new ListTile( + title: Text( + "Shopping", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0), + ), + leading: Icon( + Icons.shopping_cart, + color: Colors.green, + ), + ), + new ListTile( + title: Text( + "Dashboard", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0), + ), + leading: Icon( + Icons.dashboard, + color: Colors.red, + ), + ), + new ListTile( + title: Text( + "Timeline", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0), + ), + leading: Icon( + Icons.timeline, + color: Colors.cyan, + ), + ), + Divider(), + new ListTile( + title: Text( + "Settings", + style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0), + ), + leading: Icon( + Icons.settings, + color: Colors.brown, + ), + ), + Divider(), + MyAboutTile() + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart new file mode 100644 index 00000000..faa81c7c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_scaffold.dart @@ -0,0 +1,132 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; + +import 'common_drawer.dart'; +import 'custom_float.dart'; +// import 'package:flutter_uikit/ui/widgets/common_drawer.dart'; +// import 'package:flutter_uikit/ui/widgets/custom_float.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class CommonScaffold extends StatelessWidget { + final appTitle; + final Widget bodyData; + final showFAB; + final showDrawer; + final backGroundColor; + final actionFirstIcon; + final scaffoldKey; + final showBottomNav; + final floatingIcon; + final centerDocked; + final elevation; + + CommonScaffold( + {this.appTitle, + this.bodyData, + this.showFAB = false, + this.showDrawer = false, + this.backGroundColor, + this.actionFirstIcon = Icons.search, + this.scaffoldKey, + this.showBottomNav = false, + this.centerDocked = false, + this.floatingIcon, + this.elevation = 4.0}); + + Widget myBottomBar() => BottomAppBar( + clipBehavior: Clip.antiAlias, + shape: CircularNotchedRectangle(), + child: Ink( + height: 50.0, + decoration: new BoxDecoration( + gradient: new LinearGradient(colors: UIData.kitGradients)), + child: new Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: double.infinity, + child: new InkWell( + radius: 10.0, + splashColor: Colors.yellow, + onTap: () {}, + child: Center( + child: new Text( + "ADD TO WISHLIST", + style: new TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ), + ), + ), + new SizedBox( + width: 20.0, + ), + SizedBox( + height: double.infinity, + child: new InkWell( + onTap: () {}, + radius: 10.0, + splashColor: Colors.yellow, + child: Center( + child: new Text( + "ORDER PAGE", + style: new TextStyle( + fontSize: 12.0, + fontWeight: FontWeight.bold, + color: Colors.white), + ), + ), + ), + ), + ], + ), + ), + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + key: scaffoldKey != null ? scaffoldKey : null, + backgroundColor: backGroundColor != null ? backGroundColor : null, + appBar: AppBar( + elevation: elevation, + backgroundColor: Colors.black, + title: Text(appTitle), + actions: [ + SizedBox( + width: 5.0, + ), + IconButton( + onPressed: () {}, + icon: Icon(actionFirstIcon), + ), + IconButton( + onPressed: () {}, + icon: Icon(Icons.more_vert), + ) + ], + ), + drawer: showDrawer ? CommonDrawer() : null, + body: bodyData, + floatingActionButton: showFAB + ? CustomFloat( + builder: centerDocked + ? Text( + "5", + style: TextStyle(color: Colors.white, fontSize: 10.0), + ) + : null, + icon: floatingIcon, + qrCallback: () {}, + ) + : null, + floatingActionButtonLocation: centerDocked + ? FloatingActionButtonLocation.centerDocked + : FloatingActionButtonLocation.endFloat, + bottomNavigationBar: showBottomNav ? myBottomBar() : null, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_switch.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_switch.dart new file mode 100644 index 00000000..8f98ab3b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/common_switch.dart @@ -0,0 +1,20 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; + +class CommonSwitch extends StatelessWidget { + final defValue; + CommonSwitch({this.defValue = false}); + @override + Widget build(BuildContext context) { + return defaultTargetPlatform == TargetPlatform.android + ? Switch( + value: defValue, + onChanged: (val) {}, + ) + : CupertinoSwitch( + value: defValue, + onChanged: (val) {}, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/custom_float.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/custom_float.dart new file mode 100644 index 00000000..2e4c2f84 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/custom_float.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class CustomFloat extends StatelessWidget { + final IconData icon; + final Widget builder; + final VoidCallback qrCallback; + final isMini; + + CustomFloat({this.icon, this.builder, this.qrCallback, this.isMini = false}); + + @override + Widget build(BuildContext context) { + return FloatingActionButton( + clipBehavior: Clip.antiAlias, + mini: isMini, + onPressed: qrCallback, + child: Ink( + decoration: new BoxDecoration( + gradient: new LinearGradient(colors: UIData.kitGradients)), + child: Stack( + fit: StackFit.expand, + children: [ + Icon( + icon, + color: Colors.white, + ), + builder != null + ? Positioned( + right: 7.0, + top: 7.0, + child: CircleAvatar( + backgroundColor: Colors.red, + child: builder, + radius: 10.0, + ), + ) + : Container(), + // builder + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/gradient_button.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/gradient_button.dart new file mode 100644 index 00000000..6194a30c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/gradient_button.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class GradientButton extends StatelessWidget { + final GestureTapCallback onPressed; + final String text; + + GradientButton({@required this.onPressed, @required this.text}); + + @override + Widget build(BuildContext context) { + return Material( + elevation: 10.0, + color: Colors.transparent, + shape: const StadiumBorder(), + child: InkWell( + onTap: onPressed, + splashColor: Colors.yellow, + child: Ink( + height: 50.0, + decoration: ShapeDecoration( + shape: const StadiumBorder(), + gradient: LinearGradient( + colors: UIData.kitGradients, + )), + child: Center( + child: Text( + text, + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.normal, + fontSize: 20.0), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/label_below_icon.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/label_below_icon.dart new file mode 100644 index 00000000..fd6af372 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/label_below_icon.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class LabelBelowIcon extends StatelessWidget { + final label; + final IconData icon; + final iconColor; + final onPressed; + final circleColor; + final isCircleEnabled; + final betweenHeight; + + LabelBelowIcon( + {this.label, + this.icon, + this.onPressed, + this.iconColor = Colors.white, + this.circleColor, + this.isCircleEnabled = true, + this.betweenHeight = 5.0}); + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => onPressed, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + isCircleEnabled + ? CircleAvatar( + backgroundColor: circleColor, + radius: 20.0, + child: Icon( + icon, + size: 12.0, + color: iconColor, + ), + ) + : Icon( + icon, + size: 23.0, + color: iconColor, + ), + SizedBox( + height: betweenHeight, + ), + Text( + label, + textAlign: TextAlign.center, + style: TextStyle(fontFamily: UIData.ralewayFont), + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/label_icon.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/label_icon.dart new file mode 100644 index 00000000..f85c9a9c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/label_icon.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class LabelIcon extends StatelessWidget { + final label; + final icon; + final iconColor; + final onPressed; + + LabelIcon( + {this.label, this.icon, this.onPressed, this.iconColor = Colors.grey}); + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => onPressed, + child: Row( + children: [ + Icon( + icon, + color: iconColor, + ), + SizedBox( + width: 5.0, + ), + Text( + label, + style: TextStyle(fontWeight: FontWeight.w700), + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/login_background.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/login_background.dart new file mode 100644 index 00000000..bb384f0e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/login_background.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/ui/tools/arc_clipper.dart'; +import 'package:flutter_helper/templates/flutter_ui_kit/utils/uidata.dart'; +// import 'package:flutter_uikit/ui/tools/arc_clipper.dart'; +// import 'package:flutter_uikit/utils/uidata.dart'; + +class LoginBackground extends StatelessWidget { + final showIcon; + final image; + LoginBackground({this.showIcon = true, this.image}); + + Widget topHalf(BuildContext context) { + var deviceSize = MediaQuery.of(context).size; + return new Flexible( + flex: 2, + child: ClipPath( + clipper: new ArcClipper(), + child: Stack( + children: [ + new Container( + decoration: new BoxDecoration( + gradient: new LinearGradient( + colors: UIData.kitGradients, + )), + ), + showIcon + ? new Center( + child: SizedBox( + height: deviceSize.height / 8, + width: deviceSize.width / 2, + child: FlutterLogo( + // colors: Colors.yellow, + )), + ) + : new Container( + width: double.infinity, + child: image != null + ? Image.network( + image, + fit: BoxFit.cover, + ) + : new Container()) + ], + ), + ), + ); + } + + final bottomHalf = new Flexible( + flex: 3, + child: new Container(), + ); + + @override + Widget build(BuildContext context) { + return new Column( + children: [topHalf(context), bottomHalf], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/profile_tile.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/profile_tile.dart new file mode 100644 index 00000000..9855927f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/ui/widgets/profile_tile.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class ProfileTile extends StatelessWidget { + final title; + final subtitle; + final textColor; + ProfileTile({this.title, this.subtitle, this.textColor = Colors.black}); + @override + Widget build(BuildContext context) { + return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + title, + style: TextStyle( + fontSize: 20.0, fontWeight: FontWeight.w700, color: textColor), + ), + SizedBox( + height: 5.0, + ), + Text( + subtitle, + style: TextStyle( + fontSize: 15.0, fontWeight: FontWeight.normal, color: textColor), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/utils/translations.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/utils/translations.dart new file mode 100644 index 00000000..fc1885f7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/utils/translations.dart @@ -0,0 +1,46 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart' show rootBundle; + +class Translations { + Translations(Locale locale) { + this.locale = locale; + _localizedValues = null; + } + + Locale locale; + static Map _localizedValues; + + static Translations of(BuildContext context) { + return Localizations.of(context, Translations); + } + + String text(String key) { + return _localizedValues[key] ?? '** $key not found'; + } + + static Future load(Locale locale) async { + Translations translations = new Translations(locale); + String jsonContent = + await rootBundle.loadString("locale/i18n_${locale.languageCode}.json"); + _localizedValues = json.decode(jsonContent); + return translations; + } + + get currentLanguage => locale.languageCode; +} + +class TranslationsDelegate extends LocalizationsDelegate { + const TranslationsDelegate(); + + @override + bool isSupported(Locale locale) => ['en', 'hi'].contains(locale.languageCode); + + @override + Future load(Locale locale) => Translations.load(locale); + + @override + bool shouldReload(TranslationsDelegate old) => false; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/utils/uidata.dart b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/utils/uidata.dart new file mode 100644 index 00000000..3c653dec --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/flutter_ui_kit/utils/uidata.dart @@ -0,0 +1,89 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +class UIData { + //routes + static const String homeRoute = "/home"; + static const String profileOneRoute = "/View Profile"; + static const String profileTwoRoute = "/Profile 2"; + static const String notFoundRoute = "/No Search Result"; + static const String timelineOneRoute = "/Feed"; + static const String timelineTwoRoute = "/Tweets"; + static const String settingsOneRoute = "/Device Settings"; + static const String shoppingOneRoute = "/Shopping List"; + static const String shoppingTwoRoute = "/Shopping Details"; + static const String shoppingThreeRoute = "/Product Details"; + static const String paymentOneRoute = "/Credit Card"; + static const String paymentTwoRoute = "/Payment Success"; + static const String loginOneRoute = "/Login With OTP"; + static const String loginTwoRoute = "/Login 2"; + static const String dashboardOneRoute = "/Dashboard 1"; + static const String dashboardTwoRoute = "/Dashboard 2"; + + //strings + static const String appName = "Flutter UIKit"; + + //fonts + static const String quickFont = "Quicksand"; + static const String ralewayFont = "Raleway"; + static const String quickBoldFont = "Quicksand_Bold.otf"; + static const String quickNormalFont = "Quicksand_Book.otf"; + static const String quickLightFont = "Quicksand_Light.otf"; + + //images + static const String imageDir = "assets/images"; + static const String pkImage = "$imageDir/pk.jpg"; + static const String profileImage = "$imageDir/profile.jpg"; + static const String blankImage = "$imageDir/blank.jpg"; + static const String dashboardImage = "$imageDir/dashboard.jpg"; + static const String loginImage = "$imageDir/login.jpg"; + static const String paymentImage = "$imageDir/payment.jpg"; + static const String settingsImage = "$imageDir/setting.jpeg"; + static const String shoppingImage = "$imageDir/shopping.jpeg"; + static const String timelineImage = "$imageDir/timeline.jpeg"; + static const String verifyImage = "$imageDir/verification.jpg"; + + //login + static const String enter_code_label = "Phone Number"; + static const String enter_code_hint = "10 Digit Phone Number"; + static const String enter_otp_label = "OTP"; + static const String enter_otp_hint = "4 Digit OTP"; + static const String get_otp = "Get OTP"; + static const String resend_otp = "Resend OTP"; + static const String login = "Login"; + static const String enter_valid_number = "Enter 10 digit phone number"; + static const String enter_valid_otp = "Enter 4 digit otp"; + + //gneric + static const String error = "Error"; + static const String success = "Success"; + static const String ok = "OK"; + static const String forgot_password = "Forgot Password?"; + static const String something_went_wrong = "Something went wrong"; + static const String coming_soon = "Coming Soon"; + + static const MaterialColor ui_kit_color = Colors.grey; + +//colors + static List kitGradients = [ + // new Color.fromRGBO(103, 218, 255, 1.0), + // new Color.fromRGBO(3, 169, 244, 1.0), + // new Color.fromRGBO(0, 122, 193, 1.0), + Colors.blueGrey.shade800, + Colors.black87, + ]; + static List kitGradients2 = [ + Colors.cyan.shade600, + Colors.blue.shade900 + ]; + + //randomcolor + static final Random _random = new Random(); + + /// Returns a random color. + static Color next() { + return new Color(0xFF000000 + _random.nextInt(0x00FFFFFF)); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/lib/google_fonts.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/google_fonts.dart new file mode 100644 index 00000000..c21de4c0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/google_fonts.dart @@ -0,0 +1,101826 @@ +// GENERATED CODE - DO NOT EDIT + +// Copyright 2019 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui' as ui; +import 'package:flutter/material.dart'; +import 'src/google_fonts_base.dart'; +import 'src/google_fonts_descriptor.dart'; +import 'src/google_fonts_variant.dart'; + +/// A collection of properties used to specify custom behavior of the +/// GoogleFonts library. +class _Config { + /// Whether or not the GoogleFonts library can make requests to + /// [fonts.google.com](https://fonts.google.com/) to retrieve font files. + var allowRuntimeFetching = true; +} + +class GoogleFonts { + /// Configuration for the [GoogleFonts] library. + /// + /// Use this to define custom behavior of the GoogleFonts library in your app. + /// For example, if you do not want the GoogleFonts library to make any http + /// requests for fonts, add the following snippet to your app's `main` method. + /// + /// ```dart + /// GoogleFonts.config.allowRuntimeFetching = false; + /// ``` + static final config = _Config(); + + /// Get a map of all available fonts. + /// + /// Returns a map where the key is the name of the font family and the value + /// is the corresponding [GoogleFonts] method. + static Map< + String, + TextStyle Function({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + })> asMap() => const { + 'ABeeZee': GoogleFonts.aBeeZee, + 'Abel': GoogleFonts.abel, + 'Abhaya Libre': GoogleFonts.abhayaLibre, + 'Abril Fatface': GoogleFonts.abrilFatface, + 'Aclonica': GoogleFonts.aclonica, + 'Acme': GoogleFonts.acme, + 'Actor': GoogleFonts.actor, + 'Adamina': GoogleFonts.adamina, + 'Advent Pro': GoogleFonts.adventPro, + 'Aguafina Script': GoogleFonts.aguafinaScript, + 'Akronim': GoogleFonts.akronim, + 'Aladin': GoogleFonts.aladin, + 'Alata': GoogleFonts.alata, + 'Alatsi': GoogleFonts.alatsi, + 'Aldrich': GoogleFonts.aldrich, + 'Alef': GoogleFonts.alef, + 'Alegreya': GoogleFonts.alegreya, + 'Alegreya SC': GoogleFonts.alegreyaSc, + 'Alegreya Sans': GoogleFonts.alegreyaSans, + 'Alegreya Sans SC': GoogleFonts.alegreyaSansSc, + 'Aleo': GoogleFonts.aleo, + 'Alex Brush': GoogleFonts.alexBrush, + 'Alfa Slab One': GoogleFonts.alfaSlabOne, + 'Alice': GoogleFonts.alice, + 'Alike': GoogleFonts.alike, + 'Alike Angular': GoogleFonts.alikeAngular, + 'Allan': GoogleFonts.allan, + 'Allerta': GoogleFonts.allerta, + 'Allerta Stencil': GoogleFonts.allertaStencil, + 'Allura': GoogleFonts.allura, + 'Almarai': GoogleFonts.almarai, + 'Almendra': GoogleFonts.almendra, + 'Almendra Display': GoogleFonts.almendraDisplay, + 'Almendra SC': GoogleFonts.almendraSc, + 'Amarante': GoogleFonts.amarante, + 'Amaranth': GoogleFonts.amaranth, + 'Amatic SC': GoogleFonts.amaticSc, + 'Amatica SC': GoogleFonts.amaticaSc, + 'Amethysta': GoogleFonts.amethysta, + 'Amiko': GoogleFonts.amiko, + 'Amiri': GoogleFonts.amiri, + 'Amita': GoogleFonts.amita, + 'Anaheim': GoogleFonts.anaheim, + 'Andada': GoogleFonts.andada, + 'Andika': GoogleFonts.andika, + 'Andika New Basic': GoogleFonts.andikaNewBasic, + 'Annie Use Your Telescope': GoogleFonts.annieUseYourTelescope, + 'Anonymous Pro': GoogleFonts.anonymousPro, + 'Antic': GoogleFonts.antic, + 'Antic Didone': GoogleFonts.anticDidone, + 'Antic Slab': GoogleFonts.anticSlab, + 'Anton': GoogleFonts.anton, + 'Arapey': GoogleFonts.arapey, + 'Arbutus': GoogleFonts.arbutus, + 'Arbutus Slab': GoogleFonts.arbutusSlab, + 'Architects Daughter': GoogleFonts.architectsDaughter, + 'Archivo': GoogleFonts.archivo, + 'Archivo Black': GoogleFonts.archivoBlack, + 'Archivo Narrow': GoogleFonts.archivoNarrow, + 'Aref Ruqaa': GoogleFonts.arefRuqaa, + 'Arima Madurai': GoogleFonts.arimaMadurai, + 'Arimo': GoogleFonts.arimo, + 'Arizonia': GoogleFonts.arizonia, + 'Armata': GoogleFonts.armata, + 'Arsenal': GoogleFonts.arsenal, + 'Artifika': GoogleFonts.artifika, + 'Arvo': GoogleFonts.arvo, + 'Arya': GoogleFonts.arya, + 'Asap': GoogleFonts.asap, + 'Asar': GoogleFonts.asar, + 'Asset': GoogleFonts.asset, + 'Assistant': GoogleFonts.assistant, + 'Astloch': GoogleFonts.astloch, + 'Asul': GoogleFonts.asul, + 'Athiti': GoogleFonts.athiti, + 'Atma': GoogleFonts.atma, + 'Atomic Age': GoogleFonts.atomicAge, + 'Aubrey': GoogleFonts.aubrey, + 'Audiowide': GoogleFonts.audiowide, + 'Autour One': GoogleFonts.autourOne, + 'Average': GoogleFonts.average, + 'Average Sans': GoogleFonts.averageSans, + 'Averia Gruesa Libre': GoogleFonts.averiaGruesaLibre, + 'Averia Libre': GoogleFonts.averiaLibre, + 'Averia Sans Libre': GoogleFonts.averiaSansLibre, + 'Averia Serif Libre': GoogleFonts.averiaSerifLibre, + 'B612': GoogleFonts.b612, + 'B612 Mono': GoogleFonts.b612Mono, + 'Bad Script': GoogleFonts.badScript, + 'Bahiana': GoogleFonts.bahiana, + 'Bahianita': GoogleFonts.bahianita, + 'Bai Jamjuree': GoogleFonts.baiJamjuree, + 'Baloo': GoogleFonts.baloo, + 'Baloo Bhai': GoogleFonts.balooBhai, + 'Baloo Bhaijaan': GoogleFonts.balooBhaijaan, + 'Baloo Bhaina': GoogleFonts.balooBhaina, + 'Baloo Chettan': GoogleFonts.balooChettan, + 'Baloo Da': GoogleFonts.balooDa, + 'Baloo Paaji': GoogleFonts.balooPaaji, + 'Baloo Tamma': GoogleFonts.balooTamma, + 'Baloo Tammudu': GoogleFonts.balooTammudu, + 'Baloo Thambi': GoogleFonts.balooThambi, + 'Balsamiq Sans': GoogleFonts.balsamiqSans, + 'Balthazar': GoogleFonts.balthazar, + 'Bangers': GoogleFonts.bangers, + 'Barlow': GoogleFonts.barlow, + 'Barlow Condensed': GoogleFonts.barlowCondensed, + 'Barlow Semi Condensed': GoogleFonts.barlowSemiCondensed, + 'Barriecito': GoogleFonts.barriecito, + 'Barrio': GoogleFonts.barrio, + 'Basic': GoogleFonts.basic, + 'Baskervville': GoogleFonts.baskervville, + 'Baumans': GoogleFonts.baumans, + 'Be Vietnam': GoogleFonts.beVietnam, + 'Bebas Neue': GoogleFonts.bebasNeue, + 'Belgrano': GoogleFonts.belgrano, + 'Bellefair': GoogleFonts.bellefair, + 'Belleza': GoogleFonts.belleza, + 'Bellota': GoogleFonts.bellota, + 'Bellota Text': GoogleFonts.bellotaText, + 'BenchNine': GoogleFonts.benchNine, + 'Bentham': GoogleFonts.bentham, + 'Berkshire Swash': GoogleFonts.berkshireSwash, + 'Beth Ellen': GoogleFonts.bethEllen, + 'Bevan': GoogleFonts.bevan, + 'Big Shoulders Display': GoogleFonts.bigShouldersDisplay, + 'Big Shoulders Inline Display': GoogleFonts.bigShouldersInlineDisplay, + 'Big Shoulders Inline Text': GoogleFonts.bigShouldersInlineText, + 'Big Shoulders Stencil Display': GoogleFonts.bigShouldersStencilDisplay, + 'Big Shoulders Stencil Text': GoogleFonts.bigShouldersStencilText, + 'Big Shoulders Text': GoogleFonts.bigShouldersText, + 'Bigelow Rules': GoogleFonts.bigelowRules, + 'Bigshot One': GoogleFonts.bigshotOne, + 'Bilbo': GoogleFonts.bilbo, + 'Bilbo Swash Caps': GoogleFonts.bilboSwashCaps, + 'BioRhyme': GoogleFonts.bioRhyme, + 'BioRhyme Expanded': GoogleFonts.bioRhymeExpanded, + 'Biryani': GoogleFonts.biryani, + 'Bitter': GoogleFonts.bitter, + 'Black And White Picture': GoogleFonts.blackAndWhitePicture, + 'Black Han Sans': GoogleFonts.blackHanSans, + 'Black Ops One': GoogleFonts.blackOpsOne, + 'Blinker': GoogleFonts.blinker, + 'Bonbon': GoogleFonts.bonbon, + 'Boogaloo': GoogleFonts.boogaloo, + 'Bowlby One': GoogleFonts.bowlbyOne, + 'Bowlby One SC': GoogleFonts.bowlbyOneSc, + 'Brawler': GoogleFonts.brawler, + 'Bree Serif': GoogleFonts.breeSerif, + 'Bubblegum Sans': GoogleFonts.bubblegumSans, + 'Bubbler One': GoogleFonts.bubblerOne, + 'Buda': GoogleFonts.buda, + 'Buenard': GoogleFonts.buenard, + 'Bungee': GoogleFonts.bungee, + 'Bungee Hairline': GoogleFonts.bungeeHairline, + 'Bungee Inline': GoogleFonts.bungeeInline, + 'Bungee Outline': GoogleFonts.bungeeOutline, + 'Bungee Shade': GoogleFonts.bungeeShade, + 'Butcherman': GoogleFonts.butcherman, + 'Butterfly Kids': GoogleFonts.butterflyKids, + 'Cabin': GoogleFonts.cabin, + 'Cabin Condensed': GoogleFonts.cabinCondensed, + 'Cabin Sketch': GoogleFonts.cabinSketch, + 'Caesar Dressing': GoogleFonts.caesarDressing, + 'Cagliostro': GoogleFonts.cagliostro, + 'Cairo': GoogleFonts.cairo, + 'Caladea': GoogleFonts.caladea, + 'Calistoga': GoogleFonts.calistoga, + 'Calligraffitti': GoogleFonts.calligraffitti, + 'Cambay': GoogleFonts.cambay, + 'Cambo': GoogleFonts.cambo, + 'Candal': GoogleFonts.candal, + 'Cantarell': GoogleFonts.cantarell, + 'Cantata One': GoogleFonts.cantataOne, + 'Cantora One': GoogleFonts.cantoraOne, + 'Capriola': GoogleFonts.capriola, + 'Cardo': GoogleFonts.cardo, + 'Carme': GoogleFonts.carme, + 'Carrois Gothic': GoogleFonts.carroisGothic, + 'Carrois Gothic SC': GoogleFonts.carroisGothicSc, + 'Carter One': GoogleFonts.carterOne, + 'Castoro': GoogleFonts.castoro, + 'Catamaran': GoogleFonts.catamaran, + 'Caudex': GoogleFonts.caudex, + 'Caveat': GoogleFonts.caveat, + 'Caveat Brush': GoogleFonts.caveatBrush, + 'Cedarville Cursive': GoogleFonts.cedarvilleCursive, + 'Ceviche One': GoogleFonts.cevicheOne, + 'Chakra Petch': GoogleFonts.chakraPetch, + 'Changa': GoogleFonts.changa, + 'Changa One': GoogleFonts.changaOne, + 'Chango': GoogleFonts.chango, + 'Charm': GoogleFonts.charm, + 'Charmonman': GoogleFonts.charmonman, + 'Chathura': GoogleFonts.chathura, + 'Chau Philomene One': GoogleFonts.chauPhilomeneOne, + 'Chela One': GoogleFonts.chelaOne, + 'Chelsea Market': GoogleFonts.chelseaMarket, + 'Cherry Cream Soda': GoogleFonts.cherryCreamSoda, + 'Cherry Swash': GoogleFonts.cherrySwash, + 'Chewy': GoogleFonts.chewy, + 'Chicle': GoogleFonts.chicle, + 'Chilanka': GoogleFonts.chilanka, + 'Chivo': GoogleFonts.chivo, + 'Chonburi': GoogleFonts.chonburi, + 'Cinzel': GoogleFonts.cinzel, + 'Cinzel Decorative': GoogleFonts.cinzelDecorative, + 'Clicker Script': GoogleFonts.clickerScript, + 'Coda': GoogleFonts.coda, + 'Coda Caption': GoogleFonts.codaCaption, + 'Codystar': GoogleFonts.codystar, + 'Coiny': GoogleFonts.coiny, + 'Combo': GoogleFonts.combo, + 'Comfortaa': GoogleFonts.comfortaa, + 'Comic Neue': GoogleFonts.comicNeue, + 'Coming Soon': GoogleFonts.comingSoon, + 'Commissioner': GoogleFonts.commissioner, + 'Concert One': GoogleFonts.concertOne, + 'Condiment': GoogleFonts.condiment, + 'Contrail One': GoogleFonts.contrailOne, + 'Convergence': GoogleFonts.convergence, + 'Cookie': GoogleFonts.cookie, + 'Copse': GoogleFonts.copse, + 'Corben': GoogleFonts.corben, + 'Cormorant': GoogleFonts.cormorant, + 'Cormorant Garamond': GoogleFonts.cormorantGaramond, + 'Cormorant Infant': GoogleFonts.cormorantInfant, + 'Cormorant SC': GoogleFonts.cormorantSc, + 'Cormorant Unicase': GoogleFonts.cormorantUnicase, + 'Cormorant Upright': GoogleFonts.cormorantUpright, + 'Courgette': GoogleFonts.courgette, + 'Courier Prime': GoogleFonts.courierPrime, + 'Cousine': GoogleFonts.cousine, + 'Coustard': GoogleFonts.coustard, + 'Covered By Your Grace': GoogleFonts.coveredByYourGrace, + 'Crafty Girls': GoogleFonts.craftyGirls, + 'Creepster': GoogleFonts.creepster, + 'Crete Round': GoogleFonts.creteRound, + 'Crimson Pro': GoogleFonts.crimsonPro, + 'Crimson Text': GoogleFonts.crimsonText, + 'Croissant One': GoogleFonts.croissantOne, + 'Crushed': GoogleFonts.crushed, + 'Cuprum': GoogleFonts.cuprum, + 'Cute Font': GoogleFonts.cuteFont, + 'Cutive': GoogleFonts.cutive, + 'Cutive Mono': GoogleFonts.cutiveMono, + 'DM Mono': GoogleFonts.dmMono, + 'DM Sans': GoogleFonts.dmSans, + 'DM Serif Display': GoogleFonts.dmSerifDisplay, + 'DM Serif Text': GoogleFonts.dmSerifText, + 'Damion': GoogleFonts.damion, + 'Dancing Script': GoogleFonts.dancingScript, + 'Darker Grotesque': GoogleFonts.darkerGrotesque, + 'David Libre': GoogleFonts.davidLibre, + 'Dawning of a New Day': GoogleFonts.dawningOfANewDay, + 'Days One': GoogleFonts.daysOne, + 'Dekko': GoogleFonts.dekko, + 'Delius': GoogleFonts.delius, + 'Delius Swash Caps': GoogleFonts.deliusSwashCaps, + 'Delius Unicase': GoogleFonts.deliusUnicase, + 'Della Respira': GoogleFonts.dellaRespira, + 'Denk One': GoogleFonts.denkOne, + 'Devonshire': GoogleFonts.devonshire, + 'Dhurjati': GoogleFonts.dhurjati, + 'Didact Gothic': GoogleFonts.didactGothic, + 'Diplomata': GoogleFonts.diplomata, + 'Diplomata SC': GoogleFonts.diplomataSc, + 'Do Hyeon': GoogleFonts.doHyeon, + 'Dokdo': GoogleFonts.dokdo, + 'Domine': GoogleFonts.domine, + 'Donegal One': GoogleFonts.donegalOne, + 'Doppio One': GoogleFonts.doppioOne, + 'Dorsa': GoogleFonts.dorsa, + 'Dosis': GoogleFonts.dosis, + 'Dr Sugiyama': GoogleFonts.drSugiyama, + 'Droid Sans': GoogleFonts.droidSans, + 'Droid Sans Mono': GoogleFonts.droidSansMono, + 'Droid Serif': GoogleFonts.droidSerif, + 'Duru Sans': GoogleFonts.duruSans, + 'Dynalight': GoogleFonts.dynalight, + 'EB Garamond': GoogleFonts.ebGaramond, + 'Eagle Lake': GoogleFonts.eagleLake, + 'East Sea Dokdo': GoogleFonts.eastSeaDokdo, + 'Eater': GoogleFonts.eater, + 'Economica': GoogleFonts.economica, + 'Eczar': GoogleFonts.eczar, + 'El Messiri': GoogleFonts.elMessiri, + 'Electrolize': GoogleFonts.electrolize, + 'Elsie': GoogleFonts.elsie, + 'Elsie Swash Caps': GoogleFonts.elsieSwashCaps, + 'Emblema One': GoogleFonts.emblemaOne, + 'Emilys Candy': GoogleFonts.emilysCandy, + 'Encode Sans': GoogleFonts.encodeSans, + 'Encode Sans Condensed': GoogleFonts.encodeSansCondensed, + 'Encode Sans Expanded': GoogleFonts.encodeSansExpanded, + 'Encode Sans Semi Condensed': GoogleFonts.encodeSansSemiCondensed, + 'Encode Sans Semi Expanded': GoogleFonts.encodeSansSemiExpanded, + 'Engagement': GoogleFonts.engagement, + 'Englebert': GoogleFonts.englebert, + 'Enriqueta': GoogleFonts.enriqueta, + 'Epilogue': GoogleFonts.epilogue, + 'Erica One': GoogleFonts.ericaOne, + 'Esteban': GoogleFonts.esteban, + 'Euphoria Script': GoogleFonts.euphoriaScript, + 'Ewert': GoogleFonts.ewert, + 'Exo': GoogleFonts.exo, + 'Exo 2': GoogleFonts.exo2, + 'Expletus Sans': GoogleFonts.expletusSans, + 'Fahkwang': GoogleFonts.fahkwang, + 'Fanwood Text': GoogleFonts.fanwoodText, + 'Farro': GoogleFonts.farro, + 'Farsan': GoogleFonts.farsan, + 'Fascinate': GoogleFonts.fascinate, + 'Fascinate Inline': GoogleFonts.fascinateInline, + 'Faster One': GoogleFonts.fasterOne, + 'Fauna One': GoogleFonts.faunaOne, + 'Faustina': GoogleFonts.faustina, + 'Federant': GoogleFonts.federant, + 'Federo': GoogleFonts.federo, + 'Felipa': GoogleFonts.felipa, + 'Fenix': GoogleFonts.fenix, + 'Finger Paint': GoogleFonts.fingerPaint, + 'Fira Code': GoogleFonts.firaCode, + 'Fira Mono': GoogleFonts.firaMono, + 'Fira Sans': GoogleFonts.firaSans, + 'Fira Sans Condensed': GoogleFonts.firaSansCondensed, + 'Fira Sans Extra Condensed': GoogleFonts.firaSansExtraCondensed, + 'Fjalla One': GoogleFonts.fjallaOne, + 'Fjord One': GoogleFonts.fjordOne, + 'Flamenco': GoogleFonts.flamenco, + 'Flavors': GoogleFonts.flavors, + 'Fondamento': GoogleFonts.fondamento, + 'Fontdiner Swanky': GoogleFonts.fontdinerSwanky, + 'Forum': GoogleFonts.forum, + 'Francois One': GoogleFonts.francoisOne, + 'Frank Ruhl Libre': GoogleFonts.frankRuhlLibre, + 'Fraunces': GoogleFonts.fraunces, + 'Freckle Face': GoogleFonts.freckleFace, + 'Fredericka the Great': GoogleFonts.frederickaTheGreat, + 'Fredoka One': GoogleFonts.fredokaOne, + 'Fresca': GoogleFonts.fresca, + 'Frijole': GoogleFonts.frijole, + 'Fruktur': GoogleFonts.fruktur, + 'Fugaz One': GoogleFonts.fugazOne, + 'GFS Didot': GoogleFonts.gfsDidot, + 'GFS Neohellenic': GoogleFonts.gfsNeohellenic, + 'Gabriela': GoogleFonts.gabriela, + 'Gaegu': GoogleFonts.gaegu, + 'Gafata': GoogleFonts.gafata, + 'Galada': GoogleFonts.galada, + 'Galdeano': GoogleFonts.galdeano, + 'Galindo': GoogleFonts.galindo, + 'Gamja Flower': GoogleFonts.gamjaFlower, + 'Gayathri': GoogleFonts.gayathri, + 'Gelasio': GoogleFonts.gelasio, + 'Gentium Basic': GoogleFonts.gentiumBasic, + 'Gentium Book Basic': GoogleFonts.gentiumBookBasic, + 'Geo': GoogleFonts.geo, + 'Geostar': GoogleFonts.geostar, + 'Geostar Fill': GoogleFonts.geostarFill, + 'Germania One': GoogleFonts.germaniaOne, + 'Gidugu': GoogleFonts.gidugu, + 'Gilda Display': GoogleFonts.gildaDisplay, + 'Girassol': GoogleFonts.girassol, + 'Give You Glory': GoogleFonts.giveYouGlory, + 'Glass Antiqua': GoogleFonts.glassAntiqua, + 'Glegoo': GoogleFonts.glegoo, + 'Gloria Hallelujah': GoogleFonts.gloriaHallelujah, + 'Goblin One': GoogleFonts.goblinOne, + 'Gochi Hand': GoogleFonts.gochiHand, + 'Goldman': GoogleFonts.goldman, + 'Gorditas': GoogleFonts.gorditas, + 'Gothic A1': GoogleFonts.gothicA1, + 'Gotu': GoogleFonts.gotu, + 'Goudy Bookletter 1911': GoogleFonts.goudyBookletter1911, + 'Graduate': GoogleFonts.graduate, + 'Grand Hotel': GoogleFonts.grandHotel, + 'Grandstander': GoogleFonts.grandstander, + 'Gravitas One': GoogleFonts.gravitasOne, + 'Great Vibes': GoogleFonts.greatVibes, + 'Grenze': GoogleFonts.grenze, + 'Grenze Gotisch': GoogleFonts.grenzeGotisch, + 'Griffy': GoogleFonts.griffy, + 'Gruppo': GoogleFonts.gruppo, + 'Gudea': GoogleFonts.gudea, + 'Gugi': GoogleFonts.gugi, + 'Gupter': GoogleFonts.gupter, + 'Gurajada': GoogleFonts.gurajada, + 'Habibi': GoogleFonts.habibi, + 'Hachi Maru Pop': GoogleFonts.hachiMaruPop, + 'Halant': GoogleFonts.halant, + 'Hammersmith One': GoogleFonts.hammersmithOne, + 'Hanalei': GoogleFonts.hanalei, + 'Hanalei Fill': GoogleFonts.hanaleiFill, + 'Handlee': GoogleFonts.handlee, + 'Happy Monkey': GoogleFonts.happyMonkey, + 'Harmattan': GoogleFonts.harmattan, + 'Headland One': GoogleFonts.headlandOne, + 'Heebo': GoogleFonts.heebo, + 'Henny Penny': GoogleFonts.hennyPenny, + 'Hepta Slab': GoogleFonts.heptaSlab, + 'Herr Von Muellerhoff': GoogleFonts.herrVonMuellerhoff, + 'Hi Melody': GoogleFonts.hiMelody, + 'Hind': GoogleFonts.hind, + 'Hind Guntur': GoogleFonts.hindGuntur, + 'Hind Madurai': GoogleFonts.hindMadurai, + 'Hind Siliguri': GoogleFonts.hindSiliguri, + 'Hind Vadodara': GoogleFonts.hindVadodara, + 'Holtwood One SC': GoogleFonts.holtwoodOneSc, + 'Homemade Apple': GoogleFonts.homemadeApple, + 'Homenaje': GoogleFonts.homenaje, + 'IBM Plex Mono': GoogleFonts.ibmPlexMono, + 'IBM Plex Sans': GoogleFonts.ibmPlexSans, + 'IBM Plex Sans Condensed': GoogleFonts.ibmPlexSansCondensed, + 'IBM Plex Serif': GoogleFonts.ibmPlexSerif, + 'IM Fell DW Pica': GoogleFonts.imFellDwPica, + 'IM Fell DW Pica SC': GoogleFonts.imFellDwPicaSc, + 'IM Fell Double Pica': GoogleFonts.imFellDoublePica, + 'IM Fell Double Pica SC': GoogleFonts.imFellDoublePicaSc, + 'IM Fell English': GoogleFonts.imFellEnglish, + 'IM Fell English SC': GoogleFonts.imFellEnglishSc, + 'IM Fell French Canon': GoogleFonts.imFellFrenchCanon, + 'IM Fell French Canon SC': GoogleFonts.imFellFrenchCanonSc, + 'IM Fell Great Primer': GoogleFonts.imFellGreatPrimer, + 'IM Fell Great Primer SC': GoogleFonts.imFellGreatPrimerSc, + 'Ibarra Real Nova': GoogleFonts.ibarraRealNova, + 'Iceberg': GoogleFonts.iceberg, + 'Iceland': GoogleFonts.iceland, + 'Imprima': GoogleFonts.imprima, + 'Inconsolata': GoogleFonts.inconsolata, + 'Inder': GoogleFonts.inder, + 'Indie Flower': GoogleFonts.indieFlower, + 'Inika': GoogleFonts.inika, + 'Inknut Antiqua': GoogleFonts.inknutAntiqua, + 'Inria Sans': GoogleFonts.inriaSans, + 'Inria Serif': GoogleFonts.inriaSerif, + 'Inter': GoogleFonts.inter, + 'Irish Grover': GoogleFonts.irishGrover, + 'Istok Web': GoogleFonts.istokWeb, + 'Italiana': GoogleFonts.italiana, + 'Italianno': GoogleFonts.italianno, + 'Itim': GoogleFonts.itim, + 'Jacques Francois': GoogleFonts.jacquesFrancois, + 'Jacques Francois Shadow': GoogleFonts.jacquesFrancoisShadow, + 'Jaldi': GoogleFonts.jaldi, + 'JetBrains Mono': GoogleFonts.jetBrainsMono, + 'Jim Nightshade': GoogleFonts.jimNightshade, + 'Jockey One': GoogleFonts.jockeyOne, + 'Jolly Lodger': GoogleFonts.jollyLodger, + 'Jomhuria': GoogleFonts.jomhuria, + 'Jomolhari': GoogleFonts.jomolhari, + 'Josefin Sans': GoogleFonts.josefinSans, + 'Josefin Slab': GoogleFonts.josefinSlab, + 'Jost': GoogleFonts.jost, + 'Joti One': GoogleFonts.jotiOne, + 'Jua': GoogleFonts.jua, + 'Judson': GoogleFonts.judson, + 'Julee': GoogleFonts.julee, + 'Julius Sans One': GoogleFonts.juliusSansOne, + 'Junge': GoogleFonts.junge, + 'Jura': GoogleFonts.jura, + 'Just Another Hand': GoogleFonts.justAnotherHand, + 'Just Me Again Down Here': GoogleFonts.justMeAgainDownHere, + 'K2D': GoogleFonts.k2d, + 'Kadwa': GoogleFonts.kadwa, + 'Kalam': GoogleFonts.kalam, + 'Kameron': GoogleFonts.kameron, + 'Kanit': GoogleFonts.kanit, + 'Kantumruy': GoogleFonts.kantumruy, + 'Karla': GoogleFonts.karla, + 'Karma': GoogleFonts.karma, + 'Katibeh': GoogleFonts.katibeh, + 'Kaushan Script': GoogleFonts.kaushanScript, + 'Kavivanar': GoogleFonts.kavivanar, + 'Kavoon': GoogleFonts.kavoon, + 'Kdam Thmor': GoogleFonts.kdamThmor, + 'Keania One': GoogleFonts.keaniaOne, + 'Kelly Slab': GoogleFonts.kellySlab, + 'Kenia': GoogleFonts.kenia, + 'Khand': GoogleFonts.khand, + 'Khula': GoogleFonts.khula, + 'Kirang Haerang': GoogleFonts.kirangHaerang, + 'Kite One': GoogleFonts.kiteOne, + 'Knewave': GoogleFonts.knewave, + 'KoHo': GoogleFonts.koHo, + 'Kodchasan': GoogleFonts.kodchasan, + 'Kosugi': GoogleFonts.kosugi, + 'Kosugi Maru': GoogleFonts.kosugiMaru, + 'Kotta One': GoogleFonts.kottaOne, + 'Kranky': GoogleFonts.kranky, + 'Kreon': GoogleFonts.kreon, + 'Kristi': GoogleFonts.kristi, + 'Krona One': GoogleFonts.kronaOne, + 'Krub': GoogleFonts.krub, + 'Kufam': GoogleFonts.kufam, + 'Kulim Park': GoogleFonts.kulimPark, + 'Kumar One': GoogleFonts.kumarOne, + 'Kumar One Outline': GoogleFonts.kumarOneOutline, + 'Kumbh Sans': GoogleFonts.kumbhSans, + 'Kurale': GoogleFonts.kurale, + 'La Belle Aurore': GoogleFonts.laBelleAurore, + 'Lacquer': GoogleFonts.lacquer, + 'Laila': GoogleFonts.laila, + 'Lakki Reddy': GoogleFonts.lakkiReddy, + 'Lalezar': GoogleFonts.lalezar, + 'Lancelot': GoogleFonts.lancelot, + 'Langar': GoogleFonts.langar, + 'Lateef': GoogleFonts.lateef, + 'Lato': GoogleFonts.lato, + 'League Script': GoogleFonts.leagueScript, + 'Leckerli One': GoogleFonts.leckerliOne, + 'Ledger': GoogleFonts.ledger, + 'Lekton': GoogleFonts.lekton, + 'Lemon': GoogleFonts.lemon, + 'Lemonada': GoogleFonts.lemonada, + 'Lexend Deca': GoogleFonts.lexendDeca, + 'Lexend Exa': GoogleFonts.lexendExa, + 'Lexend Giga': GoogleFonts.lexendGiga, + 'Lexend Mega': GoogleFonts.lexendMega, + 'Lexend Peta': GoogleFonts.lexendPeta, + 'Lexend Tera': GoogleFonts.lexendTera, + 'Lexend Zetta': GoogleFonts.lexendZetta, + 'Libre Barcode 128': GoogleFonts.libreBarcode128, + 'Libre Barcode 128 Text': GoogleFonts.libreBarcode128Text, + 'Libre Barcode 39': GoogleFonts.libreBarcode39, + 'Libre Barcode 39 Extended': GoogleFonts.libreBarcode39Extended, + 'Libre Barcode 39 Extended Text': + GoogleFonts.libreBarcode39ExtendedText, + 'Libre Barcode 39 Text': GoogleFonts.libreBarcode39Text, + 'Libre Baskerville': GoogleFonts.libreBaskerville, + 'Libre Caslon Display': GoogleFonts.libreCaslonDisplay, + 'Libre Caslon Text': GoogleFonts.libreCaslonText, + 'Libre Franklin': GoogleFonts.libreFranklin, + 'Life Savers': GoogleFonts.lifeSavers, + 'Lilita One': GoogleFonts.lilitaOne, + 'Lily Script One': GoogleFonts.lilyScriptOne, + 'Limelight': GoogleFonts.limelight, + 'Linden Hill': GoogleFonts.lindenHill, + 'Literata': GoogleFonts.literata, + 'Liu Jian Mao Cao': GoogleFonts.liuJianMaoCao, + 'Livvic': GoogleFonts.livvic, + 'Lobster': GoogleFonts.lobster, + 'Lobster Two': GoogleFonts.lobsterTwo, + 'Londrina Outline': GoogleFonts.londrinaOutline, + 'Londrina Shadow': GoogleFonts.londrinaShadow, + 'Londrina Sketch': GoogleFonts.londrinaSketch, + 'Londrina Solid': GoogleFonts.londrinaSolid, + 'Long Cang': GoogleFonts.longCang, + 'Lora': GoogleFonts.lora, + 'Love Ya Like A Sister': GoogleFonts.loveYaLikeASister, + 'Loved by the King': GoogleFonts.lovedByTheKing, + 'Lovers Quarrel': GoogleFonts.loversQuarrel, + 'Luckiest Guy': GoogleFonts.luckiestGuy, + 'Lusitana': GoogleFonts.lusitana, + 'Lustria': GoogleFonts.lustria, + 'M PLUS 1p': GoogleFonts.mPlus1p, + 'M PLUS Rounded 1c': GoogleFonts.mPlusRounded1c, + 'Ma Shan Zheng': GoogleFonts.maShanZheng, + 'Macondo': GoogleFonts.macondo, + 'Macondo Swash Caps': GoogleFonts.macondoSwashCaps, + 'Mada': GoogleFonts.mada, + 'Magra': GoogleFonts.magra, + 'Maiden Orange': GoogleFonts.maidenOrange, + 'Maitree': GoogleFonts.maitree, + 'Major Mono Display': GoogleFonts.majorMonoDisplay, + 'Mako': GoogleFonts.mako, + 'Mali': GoogleFonts.mali, + 'Mallanna': GoogleFonts.mallanna, + 'Mandali': GoogleFonts.mandali, + 'Manjari': GoogleFonts.manjari, + 'Manrope': GoogleFonts.manrope, + 'Mansalva': GoogleFonts.mansalva, + 'Manuale': GoogleFonts.manuale, + 'Marcellus': GoogleFonts.marcellus, + 'Marcellus SC': GoogleFonts.marcellusSc, + 'Marck Script': GoogleFonts.marckScript, + 'Margarine': GoogleFonts.margarine, + 'Markazi Text': GoogleFonts.markaziText, + 'Marko One': GoogleFonts.markoOne, + 'Marmelad': GoogleFonts.marmelad, + 'Martel': GoogleFonts.martel, + 'Martel Sans': GoogleFonts.martelSans, + 'Marvel': GoogleFonts.marvel, + 'Mate': GoogleFonts.mate, + 'Mate SC': GoogleFonts.mateSc, + 'Maven Pro': GoogleFonts.mavenPro, + 'McLaren': GoogleFonts.mcLaren, + 'Meddon': GoogleFonts.meddon, + 'MedievalSharp': GoogleFonts.medievalSharp, + 'Medula One': GoogleFonts.medulaOne, + 'Meera Inimai': GoogleFonts.meeraInimai, + 'Megrim': GoogleFonts.megrim, + 'Meie Script': GoogleFonts.meieScript, + 'Merienda': GoogleFonts.merienda, + 'Merienda One': GoogleFonts.meriendaOne, + 'Merriweather': GoogleFonts.merriweather, + 'Merriweather Sans': GoogleFonts.merriweatherSans, + 'Metal Mania': GoogleFonts.metalMania, + 'Metamorphous': GoogleFonts.metamorphous, + 'Metrophobic': GoogleFonts.metrophobic, + 'Michroma': GoogleFonts.michroma, + 'Milonga': GoogleFonts.milonga, + 'Miltonian': GoogleFonts.miltonian, + 'Miltonian Tattoo': GoogleFonts.miltonianTattoo, + 'Mina': GoogleFonts.mina, + 'Miniver': GoogleFonts.miniver, + 'Miriam Libre': GoogleFonts.miriamLibre, + 'Mirza': GoogleFonts.mirza, + 'Miss Fajardose': GoogleFonts.missFajardose, + 'Mitr': GoogleFonts.mitr, + 'Modak': GoogleFonts.modak, + 'Modern Antiqua': GoogleFonts.modernAntiqua, + 'Mogra': GoogleFonts.mogra, + 'Molengo': GoogleFonts.molengo, + 'Molle': GoogleFonts.molle, + 'Monda': GoogleFonts.monda, + 'Monofett': GoogleFonts.monofett, + 'Monoton': GoogleFonts.monoton, + 'Monsieur La Doulaise': GoogleFonts.monsieurLaDoulaise, + 'Montaga': GoogleFonts.montaga, + 'Montez': GoogleFonts.montez, + 'Montserrat': GoogleFonts.montserrat, + 'Montserrat Alternates': GoogleFonts.montserratAlternates, + 'Montserrat Subrayada': GoogleFonts.montserratSubrayada, + 'Mountains of Christmas': GoogleFonts.mountainsOfChristmas, + 'Mouse Memoirs': GoogleFonts.mouseMemoirs, + 'Mr Bedfort': GoogleFonts.mrBedfort, + 'Mr Dafoe': GoogleFonts.mrDafoe, + 'Mr De Haviland': GoogleFonts.mrDeHaviland, + 'Mrs Saint Delafield': GoogleFonts.mrsSaintDelafield, + 'Mrs Sheppards': GoogleFonts.mrsSheppards, + 'Mukta': GoogleFonts.mukta, + 'Mukta Mahee': GoogleFonts.muktaMahee, + 'Mukta Malar': GoogleFonts.muktaMalar, + 'Mukta Vaani': GoogleFonts.muktaVaani, + 'Mulish': GoogleFonts.mulish, + 'MuseoModerno': GoogleFonts.museoModerno, + 'Mystery Quest': GoogleFonts.mysteryQuest, + 'NTR': GoogleFonts.ntr, + 'Nanum Brush Script': GoogleFonts.nanumBrushScript, + 'Nanum Gothic': GoogleFonts.nanumGothic, + 'Nanum Gothic Coding': GoogleFonts.nanumGothicCoding, + 'Nanum Myeongjo': GoogleFonts.nanumMyeongjo, + 'Nanum Pen Script': GoogleFonts.nanumPenScript, + 'Nerko One': GoogleFonts.nerkoOne, + 'Neucha': GoogleFonts.neucha, + 'Neuton': GoogleFonts.neuton, + 'New Rocker': GoogleFonts.newRocker, + 'News Cycle': GoogleFonts.newsCycle, + 'Niconne': GoogleFonts.niconne, + 'Niramit': GoogleFonts.niramit, + 'Nixie One': GoogleFonts.nixieOne, + 'Nobile': GoogleFonts.nobile, + 'Norican': GoogleFonts.norican, + 'Nosifer': GoogleFonts.nosifer, + 'Notable': GoogleFonts.notable, + 'Nothing You Could Do': GoogleFonts.nothingYouCouldDo, + 'Noticia Text': GoogleFonts.noticiaText, + 'Noto Color Emoji Compat': GoogleFonts.notoColorEmojiCompat, + 'Noto Sans': GoogleFonts.notoSans, + 'Noto Serif': GoogleFonts.notoSerif, + 'Nova Cut': GoogleFonts.novaCut, + 'Nova Flat': GoogleFonts.novaFlat, + 'Nova Mono': GoogleFonts.novaMono, + 'Nova Oval': GoogleFonts.novaOval, + 'Nova Round': GoogleFonts.novaRound, + 'Nova Script': GoogleFonts.novaScript, + 'Nova Slim': GoogleFonts.novaSlim, + 'Nova Square': GoogleFonts.novaSquare, + 'Numans': GoogleFonts.numans, + 'Nunito': GoogleFonts.nunito, + 'Nunito Sans': GoogleFonts.nunitoSans, + 'Odibee Sans': GoogleFonts.odibeeSans, + 'Odor Mean Chey': GoogleFonts.odorMeanChey, + 'Offside': GoogleFonts.offside, + 'Old Standard TT': GoogleFonts.oldStandardTt, + 'Oldenburg': GoogleFonts.oldenburg, + 'Oleo Script': GoogleFonts.oleoScript, + 'Oleo Script Swash Caps': GoogleFonts.oleoScriptSwashCaps, + 'Open Sans': GoogleFonts.openSans, + 'Open Sans Condensed': GoogleFonts.openSansCondensed, + 'Oranienbaum': GoogleFonts.oranienbaum, + 'Orbitron': GoogleFonts.orbitron, + 'Oregano': GoogleFonts.oregano, + 'Orienta': GoogleFonts.orienta, + 'Original Surfer': GoogleFonts.originalSurfer, + 'Oswald': GoogleFonts.oswald, + 'Over the Rainbow': GoogleFonts.overTheRainbow, + 'Overlock': GoogleFonts.overlock, + 'Overlock SC': GoogleFonts.overlockSc, + 'Overpass': GoogleFonts.overpass, + 'Overpass Mono': GoogleFonts.overpassMono, + 'Ovo': GoogleFonts.ovo, + 'Oxanium': GoogleFonts.oxanium, + 'Oxygen': GoogleFonts.oxygen, + 'Oxygen Mono': GoogleFonts.oxygenMono, + 'PT Mono': GoogleFonts.ptMono, + 'PT Sans': GoogleFonts.ptSans, + 'PT Sans Caption': GoogleFonts.ptSansCaption, + 'PT Sans Narrow': GoogleFonts.ptSansNarrow, + 'PT Serif': GoogleFonts.ptSerif, + 'PT Serif Caption': GoogleFonts.ptSerifCaption, + 'Pacifico': GoogleFonts.pacifico, + 'Padauk': GoogleFonts.padauk, + 'Palanquin': GoogleFonts.palanquin, + 'Palanquin Dark': GoogleFonts.palanquinDark, + 'Pangolin': GoogleFonts.pangolin, + 'Paprika': GoogleFonts.paprika, + 'Parisienne': GoogleFonts.parisienne, + 'Passero One': GoogleFonts.passeroOne, + 'Passion One': GoogleFonts.passionOne, + 'Pathway Gothic One': GoogleFonts.pathwayGothicOne, + 'Patrick Hand': GoogleFonts.patrickHand, + 'Patrick Hand SC': GoogleFonts.patrickHandSc, + 'Pattaya': GoogleFonts.pattaya, + 'Patua One': GoogleFonts.patuaOne, + 'Pavanam': GoogleFonts.pavanam, + 'Paytone One': GoogleFonts.paytoneOne, + 'Peddana': GoogleFonts.peddana, + 'Peralta': GoogleFonts.peralta, + 'Permanent Marker': GoogleFonts.permanentMarker, + 'Petit Formal Script': GoogleFonts.petitFormalScript, + 'Petrona': GoogleFonts.petrona, + 'Philosopher': GoogleFonts.philosopher, + 'Piazzolla': GoogleFonts.piazzolla, + 'Piedra': GoogleFonts.piedra, + 'Pinyon Script': GoogleFonts.pinyonScript, + 'Pirata One': GoogleFonts.pirataOne, + 'Plaster': GoogleFonts.plaster, + 'Play': GoogleFonts.play, + 'Playball': GoogleFonts.playball, + 'Playfair Display': GoogleFonts.playfairDisplay, + 'Playfair Display SC': GoogleFonts.playfairDisplaySc, + 'Podkova': GoogleFonts.podkova, + 'Poiret One': GoogleFonts.poiretOne, + 'Poller One': GoogleFonts.pollerOne, + 'Poly': GoogleFonts.poly, + 'Pompiere': GoogleFonts.pompiere, + 'Pontano Sans': GoogleFonts.pontanoSans, + 'Poor Story': GoogleFonts.poorStory, + 'Poppins': GoogleFonts.poppins, + 'Port Lligat Sans': GoogleFonts.portLligatSans, + 'Port Lligat Slab': GoogleFonts.portLligatSlab, + 'Potta One': GoogleFonts.pottaOne, + 'Pragati Narrow': GoogleFonts.pragatiNarrow, + 'Prata': GoogleFonts.prata, + 'Press Start 2P': GoogleFonts.pressStart2p, + 'Pridi': GoogleFonts.pridi, + 'Princess Sofia': GoogleFonts.princessSofia, + 'Prociono': GoogleFonts.prociono, + 'Prompt': GoogleFonts.prompt, + 'Prosto One': GoogleFonts.prostoOne, + 'Proza Libre': GoogleFonts.prozaLibre, + 'Public Sans': GoogleFonts.publicSans, + 'Puritan': GoogleFonts.puritan, + 'Purple Purse': GoogleFonts.purplePurse, + 'Quando': GoogleFonts.quando, + 'Quantico': GoogleFonts.quantico, + 'Quattrocento': GoogleFonts.quattrocento, + 'Quattrocento Sans': GoogleFonts.quattrocentoSans, + 'Questrial': GoogleFonts.questrial, + 'Quicksand': GoogleFonts.quicksand, + 'Quintessential': GoogleFonts.quintessential, + 'Qwigley': GoogleFonts.qwigley, + 'Racing Sans One': GoogleFonts.racingSansOne, + 'Radley': GoogleFonts.radley, + 'Rajdhani': GoogleFonts.rajdhani, + 'Rakkas': GoogleFonts.rakkas, + 'Raleway': GoogleFonts.raleway, + 'Raleway Dots': GoogleFonts.ralewayDots, + 'Ramabhadra': GoogleFonts.ramabhadra, + 'Ramaraja': GoogleFonts.ramaraja, + 'Rambla': GoogleFonts.rambla, + 'Rammetto One': GoogleFonts.rammettoOne, + 'Ranchers': GoogleFonts.ranchers, + 'Rancho': GoogleFonts.rancho, + 'Ranga': GoogleFonts.ranga, + 'Rasa': GoogleFonts.rasa, + 'Rationale': GoogleFonts.rationale, + 'Ravi Prakash': GoogleFonts.raviPrakash, + 'Recursive': GoogleFonts.recursive, + 'Red Hat Display': GoogleFonts.redHatDisplay, + 'Red Hat Text': GoogleFonts.redHatText, + 'Red Rose': GoogleFonts.redRose, + 'Redressed': GoogleFonts.redressed, + 'Reem Kufi': GoogleFonts.reemKufi, + 'Reenie Beanie': GoogleFonts.reenieBeanie, + 'Revalia': GoogleFonts.revalia, + 'Rhodium Libre': GoogleFonts.rhodiumLibre, + 'Ribeye': GoogleFonts.ribeye, + 'Ribeye Marrow': GoogleFonts.ribeyeMarrow, + 'Righteous': GoogleFonts.righteous, + 'Risque': GoogleFonts.risque, + 'Roboto': GoogleFonts.roboto, + 'Roboto Condensed': GoogleFonts.robotoCondensed, + 'Roboto Mono': GoogleFonts.robotoMono, + 'Roboto Slab': GoogleFonts.robotoSlab, + 'Rochester': GoogleFonts.rochester, + 'Rock Salt': GoogleFonts.rockSalt, + 'Rokkitt': GoogleFonts.rokkitt, + 'Romanesco': GoogleFonts.romanesco, + 'Ropa Sans': GoogleFonts.ropaSans, + 'Rosario': GoogleFonts.rosario, + 'Rosarivo': GoogleFonts.rosarivo, + 'Rouge Script': GoogleFonts.rougeScript, + 'Rowdies': GoogleFonts.rowdies, + 'Rozha One': GoogleFonts.rozhaOne, + 'Rubik': GoogleFonts.rubik, + 'Rubik Mono One': GoogleFonts.rubikMonoOne, + 'Ruda': GoogleFonts.ruda, + 'Rufina': GoogleFonts.rufina, + 'Ruge Boogie': GoogleFonts.rugeBoogie, + 'Ruluko': GoogleFonts.ruluko, + 'Rum Raisin': GoogleFonts.rumRaisin, + 'Ruslan Display': GoogleFonts.ruslanDisplay, + 'Russo One': GoogleFonts.russoOne, + 'Ruthie': GoogleFonts.ruthie, + 'Rye': GoogleFonts.rye, + 'Sacramento': GoogleFonts.sacramento, + 'Sahitya': GoogleFonts.sahitya, + 'Sail': GoogleFonts.sail, + 'Saira': GoogleFonts.saira, + 'Saira Condensed': GoogleFonts.sairaCondensed, + 'Saira Extra Condensed': GoogleFonts.sairaExtraCondensed, + 'Saira Semi Condensed': GoogleFonts.sairaSemiCondensed, + 'Saira Stencil One': GoogleFonts.sairaStencilOne, + 'Salsa': GoogleFonts.salsa, + 'Sanchez': GoogleFonts.sanchez, + 'Sancreek': GoogleFonts.sancreek, + 'Sansita': GoogleFonts.sansita, + 'Sansita Swashed': GoogleFonts.sansitaSwashed, + 'Sarabun': GoogleFonts.sarabun, + 'Sarala': GoogleFonts.sarala, + 'Sarina': GoogleFonts.sarina, + 'Sarpanch': GoogleFonts.sarpanch, + 'Satisfy': GoogleFonts.satisfy, + 'Sawarabi Gothic': GoogleFonts.sawarabiGothic, + 'Sawarabi Mincho': GoogleFonts.sawarabiMincho, + 'Scada': GoogleFonts.scada, + 'Scheherazade': GoogleFonts.scheherazade, + 'Schoolbell': GoogleFonts.schoolbell, + 'Scope One': GoogleFonts.scopeOne, + 'Seaweed Script': GoogleFonts.seaweedScript, + 'Secular One': GoogleFonts.secularOne, + 'Sedgwick Ave': GoogleFonts.sedgwickAve, + 'Sedgwick Ave Display': GoogleFonts.sedgwickAveDisplay, + 'Sen': GoogleFonts.sen, + 'Sevillana': GoogleFonts.sevillana, + 'Seymour One': GoogleFonts.seymourOne, + 'Shadows Into Light': GoogleFonts.shadowsIntoLight, + 'Shadows Into Light Two': GoogleFonts.shadowsIntoLightTwo, + 'Shanti': GoogleFonts.shanti, + 'Share': GoogleFonts.share, + 'Share Tech': GoogleFonts.shareTech, + 'Share Tech Mono': GoogleFonts.shareTechMono, + 'Shojumaru': GoogleFonts.shojumaru, + 'Short Stack': GoogleFonts.shortStack, + 'Shrikhand': GoogleFonts.shrikhand, + 'Sigmar One': GoogleFonts.sigmarOne, + 'Signika': GoogleFonts.signika, + 'Signika Negative': GoogleFonts.signikaNegative, + 'Simonetta': GoogleFonts.simonetta, + 'Single Day': GoogleFonts.singleDay, + 'Sintony': GoogleFonts.sintony, + 'Sirin Stencil': GoogleFonts.sirinStencil, + 'Six Caps': GoogleFonts.sixCaps, + 'Skranji': GoogleFonts.skranji, + 'Slabo 13px': GoogleFonts.slabo13px, + 'Slabo 27px': GoogleFonts.slabo27px, + 'Slackey': GoogleFonts.slackey, + 'Smokum': GoogleFonts.smokum, + 'Smythe': GoogleFonts.smythe, + 'Sniglet': GoogleFonts.sniglet, + 'Snippet': GoogleFonts.snippet, + 'Snowburst One': GoogleFonts.snowburstOne, + 'Sofadi One': GoogleFonts.sofadiOne, + 'Sofia': GoogleFonts.sofia, + 'Solway': GoogleFonts.solway, + 'Song Myung': GoogleFonts.songMyung, + 'Sonsie One': GoogleFonts.sonsieOne, + 'Sora': GoogleFonts.sora, + 'Sorts Mill Goudy': GoogleFonts.sortsMillGoudy, + 'Source Code Pro': GoogleFonts.sourceCodePro, + 'Source Sans Pro': GoogleFonts.sourceSansPro, + 'Source Serif Pro': GoogleFonts.sourceSerifPro, + 'Space Grotesk': GoogleFonts.spaceGrotesk, + 'Space Mono': GoogleFonts.spaceMono, + 'Spartan': GoogleFonts.spartan, + 'Special Elite': GoogleFonts.specialElite, + 'Spectral': GoogleFonts.spectral, + 'Spectral SC': GoogleFonts.spectralSc, + 'Spicy Rice': GoogleFonts.spicyRice, + 'Spinnaker': GoogleFonts.spinnaker, + 'Spirax': GoogleFonts.spirax, + 'Squada One': GoogleFonts.squadaOne, + 'Sree Krushnadevaraya': GoogleFonts.sreeKrushnadevaraya, + 'Sriracha': GoogleFonts.sriracha, + 'Srisakdi': GoogleFonts.srisakdi, + 'Staatliches': GoogleFonts.staatliches, + 'Stalemate': GoogleFonts.stalemate, + 'Stalinist One': GoogleFonts.stalinistOne, + 'Stardos Stencil': GoogleFonts.stardosStencil, + 'Stint Ultra Condensed': GoogleFonts.stintUltraCondensed, + 'Stint Ultra Expanded': GoogleFonts.stintUltraExpanded, + 'Stoke': GoogleFonts.stoke, + 'Strait': GoogleFonts.strait, + 'Stylish': GoogleFonts.stylish, + 'Sue Ellen Francisco': GoogleFonts.sueEllenFrancisco, + 'Suez One': GoogleFonts.suezOne, + 'Sulphur Point': GoogleFonts.sulphurPoint, + 'Sumana': GoogleFonts.sumana, + 'Sunflower': GoogleFonts.sunflower, + 'Sunshiney': GoogleFonts.sunshiney, + 'Supermercado One': GoogleFonts.supermercadoOne, + 'Sura': GoogleFonts.sura, + 'Suranna': GoogleFonts.suranna, + 'Suravaram': GoogleFonts.suravaram, + 'Swanky and Moo Moo': GoogleFonts.swankyAndMooMoo, + 'Syncopate': GoogleFonts.syncopate, + 'Syne': GoogleFonts.syne, + 'Syne Mono': GoogleFonts.syneMono, + 'Syne Tactile': GoogleFonts.syneTactile, + 'Tajawal': GoogleFonts.tajawal, + 'Tangerine': GoogleFonts.tangerine, + 'Tauri': GoogleFonts.tauri, + 'Taviraj': GoogleFonts.taviraj, + 'Teko': GoogleFonts.teko, + 'Telex': GoogleFonts.telex, + 'Tenali Ramakrishna': GoogleFonts.tenaliRamakrishna, + 'Tenor Sans': GoogleFonts.tenorSans, + 'Text Me One': GoogleFonts.textMeOne, + 'Thasadith': GoogleFonts.thasadith, + 'The Girl Next Door': GoogleFonts.theGirlNextDoor, + 'Tienne': GoogleFonts.tienne, + 'Tillana': GoogleFonts.tillana, + 'Timmana': GoogleFonts.timmana, + 'Tinos': GoogleFonts.tinos, + 'Titan One': GoogleFonts.titanOne, + 'Titillium Web': GoogleFonts.titilliumWeb, + 'Tomorrow': GoogleFonts.tomorrow, + 'Trade Winds': GoogleFonts.tradeWinds, + 'Trirong': GoogleFonts.trirong, + 'Trispace': GoogleFonts.trispace, + 'Trocchi': GoogleFonts.trocchi, + 'Trochut': GoogleFonts.trochut, + 'Trykker': GoogleFonts.trykker, + 'Tulpen One': GoogleFonts.tulpenOne, + 'Turret Road': GoogleFonts.turretRoad, + 'Ubuntu': GoogleFonts.ubuntu, + 'Ubuntu Condensed': GoogleFonts.ubuntuCondensed, + 'Ubuntu Mono': GoogleFonts.ubuntuMono, + 'Ultra': GoogleFonts.ultra, + 'Uncial Antiqua': GoogleFonts.uncialAntiqua, + 'Underdog': GoogleFonts.underdog, + 'Unica One': GoogleFonts.unicaOne, + 'UnifrakturCook': GoogleFonts.unifrakturCook, + 'UnifrakturMaguntia': GoogleFonts.unifrakturMaguntia, + 'Unkempt': GoogleFonts.unkempt, + 'Unlock': GoogleFonts.unlock, + 'Unna': GoogleFonts.unna, + 'VT323': GoogleFonts.vt323, + 'Vampiro One': GoogleFonts.vampiroOne, + 'Varela': GoogleFonts.varela, + 'Varela Round': GoogleFonts.varelaRound, + 'Varta': GoogleFonts.varta, + 'Vast Shadow': GoogleFonts.vastShadow, + 'Vesper Libre': GoogleFonts.vesperLibre, + 'Viaoda Libre': GoogleFonts.viaodaLibre, + 'Vibes': GoogleFonts.vibes, + 'Vibur': GoogleFonts.vibur, + 'Vidaloka': GoogleFonts.vidaloka, + 'Viga': GoogleFonts.viga, + 'Voces': GoogleFonts.voces, + 'Volkhov': GoogleFonts.volkhov, + 'Vollkorn': GoogleFonts.vollkorn, + 'Vollkorn SC': GoogleFonts.vollkornSc, + 'Voltaire': GoogleFonts.voltaire, + 'Waiting for the Sunrise': GoogleFonts.waitingForTheSunrise, + 'Wallpoet': GoogleFonts.wallpoet, + 'Walter Turncoat': GoogleFonts.walterTurncoat, + 'Warnes': GoogleFonts.warnes, + 'Wellfleet': GoogleFonts.wellfleet, + 'Wendy One': GoogleFonts.wendyOne, + 'Wire One': GoogleFonts.wireOne, + 'Work Sans': GoogleFonts.workSans, + 'Xanh Mono': GoogleFonts.xanhMono, + 'Yanone Kaffeesatz': GoogleFonts.yanoneKaffeesatz, + 'Yantramanav': GoogleFonts.yantramanav, + 'Yatra One': GoogleFonts.yatraOne, + 'Yellowtail': GoogleFonts.yellowtail, + 'Yeon Sung': GoogleFonts.yeonSung, + 'Yeseva One': GoogleFonts.yesevaOne, + 'Yesteryear': GoogleFonts.yesteryear, + 'Yrsa': GoogleFonts.yrsa, + 'Yusei Magic': GoogleFonts.yuseiMagic, + 'ZCOOL KuaiLe': GoogleFonts.zcoolKuaiLe, + 'ZCOOL QingKe HuangYou': GoogleFonts.zcoolQingKeHuangYou, + 'ZCOOL XiaoWei': GoogleFonts.zcoolXiaoWei, + 'Zeyada': GoogleFonts.zeyada, + 'Zhi Mang Xing': GoogleFonts.zhiMangXing, + 'Zilla Slab': GoogleFonts.zillaSlab, + 'Zilla Slab Highlight': GoogleFonts.zillaSlabHighlight, + }; + + /// Get a map of all available fonts and their associated text themes. + /// + /// Returns a map where the key is the name of the font family and the value + /// is the corresponding [GoogleFonts] `TextTheme` method. + static Map _asMapOfTextThemes() => + const { + 'ABeeZee': GoogleFonts.aBeeZeeTextTheme, + 'Abel': GoogleFonts.abelTextTheme, + 'Abhaya Libre': GoogleFonts.abhayaLibreTextTheme, + 'Abril Fatface': GoogleFonts.abrilFatfaceTextTheme, + 'Aclonica': GoogleFonts.aclonicaTextTheme, + 'Acme': GoogleFonts.acmeTextTheme, + 'Actor': GoogleFonts.actorTextTheme, + 'Adamina': GoogleFonts.adaminaTextTheme, + 'Advent Pro': GoogleFonts.adventProTextTheme, + 'Aguafina Script': GoogleFonts.aguafinaScriptTextTheme, + 'Akronim': GoogleFonts.akronimTextTheme, + 'Aladin': GoogleFonts.aladinTextTheme, + 'Alata': GoogleFonts.alataTextTheme, + 'Alatsi': GoogleFonts.alatsiTextTheme, + 'Aldrich': GoogleFonts.aldrichTextTheme, + 'Alef': GoogleFonts.alefTextTheme, + 'Alegreya': GoogleFonts.alegreyaTextTheme, + 'Alegreya SC': GoogleFonts.alegreyaScTextTheme, + 'Alegreya Sans': GoogleFonts.alegreyaSansTextTheme, + 'Alegreya Sans SC': GoogleFonts.alegreyaSansScTextTheme, + 'Aleo': GoogleFonts.aleoTextTheme, + 'Alex Brush': GoogleFonts.alexBrushTextTheme, + 'Alfa Slab One': GoogleFonts.alfaSlabOneTextTheme, + 'Alice': GoogleFonts.aliceTextTheme, + 'Alike': GoogleFonts.alikeTextTheme, + 'Alike Angular': GoogleFonts.alikeAngularTextTheme, + 'Allan': GoogleFonts.allanTextTheme, + 'Allerta': GoogleFonts.allertaTextTheme, + 'Allerta Stencil': GoogleFonts.allertaStencilTextTheme, + 'Allura': GoogleFonts.alluraTextTheme, + 'Almarai': GoogleFonts.almaraiTextTheme, + 'Almendra': GoogleFonts.almendraTextTheme, + 'Almendra Display': GoogleFonts.almendraDisplayTextTheme, + 'Almendra SC': GoogleFonts.almendraScTextTheme, + 'Amarante': GoogleFonts.amaranteTextTheme, + 'Amaranth': GoogleFonts.amaranthTextTheme, + 'Amatic SC': GoogleFonts.amaticScTextTheme, + 'Amatica SC': GoogleFonts.amaticaScTextTheme, + 'Amethysta': GoogleFonts.amethystaTextTheme, + 'Amiko': GoogleFonts.amikoTextTheme, + 'Amiri': GoogleFonts.amiriTextTheme, + 'Amita': GoogleFonts.amitaTextTheme, + 'Anaheim': GoogleFonts.anaheimTextTheme, + 'Andada': GoogleFonts.andadaTextTheme, + 'Andika': GoogleFonts.andikaTextTheme, + 'Andika New Basic': GoogleFonts.andikaNewBasicTextTheme, + 'Annie Use Your Telescope': GoogleFonts.annieUseYourTelescopeTextTheme, + 'Anonymous Pro': GoogleFonts.anonymousProTextTheme, + 'Antic': GoogleFonts.anticTextTheme, + 'Antic Didone': GoogleFonts.anticDidoneTextTheme, + 'Antic Slab': GoogleFonts.anticSlabTextTheme, + 'Anton': GoogleFonts.antonTextTheme, + 'Arapey': GoogleFonts.arapeyTextTheme, + 'Arbutus': GoogleFonts.arbutusTextTheme, + 'Arbutus Slab': GoogleFonts.arbutusSlabTextTheme, + 'Architects Daughter': GoogleFonts.architectsDaughterTextTheme, + 'Archivo': GoogleFonts.archivoTextTheme, + 'Archivo Black': GoogleFonts.archivoBlackTextTheme, + 'Archivo Narrow': GoogleFonts.archivoNarrowTextTheme, + 'Aref Ruqaa': GoogleFonts.arefRuqaaTextTheme, + 'Arima Madurai': GoogleFonts.arimaMaduraiTextTheme, + 'Arimo': GoogleFonts.arimoTextTheme, + 'Arizonia': GoogleFonts.arizoniaTextTheme, + 'Armata': GoogleFonts.armataTextTheme, + 'Arsenal': GoogleFonts.arsenalTextTheme, + 'Artifika': GoogleFonts.artifikaTextTheme, + 'Arvo': GoogleFonts.arvoTextTheme, + 'Arya': GoogleFonts.aryaTextTheme, + 'Asap': GoogleFonts.asapTextTheme, + 'Asar': GoogleFonts.asarTextTheme, + 'Asset': GoogleFonts.assetTextTheme, + 'Assistant': GoogleFonts.assistantTextTheme, + 'Astloch': GoogleFonts.astlochTextTheme, + 'Asul': GoogleFonts.asulTextTheme, + 'Athiti': GoogleFonts.athitiTextTheme, + 'Atma': GoogleFonts.atmaTextTheme, + 'Atomic Age': GoogleFonts.atomicAgeTextTheme, + 'Aubrey': GoogleFonts.aubreyTextTheme, + 'Audiowide': GoogleFonts.audiowideTextTheme, + 'Autour One': GoogleFonts.autourOneTextTheme, + 'Average': GoogleFonts.averageTextTheme, + 'Average Sans': GoogleFonts.averageSansTextTheme, + 'Averia Gruesa Libre': GoogleFonts.averiaGruesaLibreTextTheme, + 'Averia Libre': GoogleFonts.averiaLibreTextTheme, + 'Averia Sans Libre': GoogleFonts.averiaSansLibreTextTheme, + 'Averia Serif Libre': GoogleFonts.averiaSerifLibreTextTheme, + 'B612': GoogleFonts.b612TextTheme, + 'B612 Mono': GoogleFonts.b612MonoTextTheme, + 'Bad Script': GoogleFonts.badScriptTextTheme, + 'Bahiana': GoogleFonts.bahianaTextTheme, + 'Bahianita': GoogleFonts.bahianitaTextTheme, + 'Bai Jamjuree': GoogleFonts.baiJamjureeTextTheme, + 'Baloo': GoogleFonts.balooTextTheme, + 'Baloo Bhai': GoogleFonts.balooBhaiTextTheme, + 'Baloo Bhaijaan': GoogleFonts.balooBhaijaanTextTheme, + 'Baloo Bhaina': GoogleFonts.balooBhainaTextTheme, + 'Baloo Chettan': GoogleFonts.balooChettanTextTheme, + 'Baloo Da': GoogleFonts.balooDaTextTheme, + 'Baloo Paaji': GoogleFonts.balooPaajiTextTheme, + 'Baloo Tamma': GoogleFonts.balooTammaTextTheme, + 'Baloo Tammudu': GoogleFonts.balooTammuduTextTheme, + 'Baloo Thambi': GoogleFonts.balooThambiTextTheme, + 'Balsamiq Sans': GoogleFonts.balsamiqSansTextTheme, + 'Balthazar': GoogleFonts.balthazarTextTheme, + 'Bangers': GoogleFonts.bangersTextTheme, + 'Barlow': GoogleFonts.barlowTextTheme, + 'Barlow Condensed': GoogleFonts.barlowCondensedTextTheme, + 'Barlow Semi Condensed': GoogleFonts.barlowSemiCondensedTextTheme, + 'Barriecito': GoogleFonts.barriecitoTextTheme, + 'Barrio': GoogleFonts.barrioTextTheme, + 'Basic': GoogleFonts.basicTextTheme, + 'Baskervville': GoogleFonts.baskervvilleTextTheme, + 'Baumans': GoogleFonts.baumansTextTheme, + 'Be Vietnam': GoogleFonts.beVietnamTextTheme, + 'Bebas Neue': GoogleFonts.bebasNeueTextTheme, + 'Belgrano': GoogleFonts.belgranoTextTheme, + 'Bellefair': GoogleFonts.bellefairTextTheme, + 'Belleza': GoogleFonts.bellezaTextTheme, + 'Bellota': GoogleFonts.bellotaTextTheme, + 'Bellota Text': GoogleFonts.bellotaTextTextTheme, + 'BenchNine': GoogleFonts.benchNineTextTheme, + 'Bentham': GoogleFonts.benthamTextTheme, + 'Berkshire Swash': GoogleFonts.berkshireSwashTextTheme, + 'Beth Ellen': GoogleFonts.bethEllenTextTheme, + 'Bevan': GoogleFonts.bevanTextTheme, + 'Big Shoulders Display': GoogleFonts.bigShouldersDisplayTextTheme, + 'Big Shoulders Inline Display': + GoogleFonts.bigShouldersInlineDisplayTextTheme, + 'Big Shoulders Inline Text': + GoogleFonts.bigShouldersInlineTextTextTheme, + 'Big Shoulders Stencil Display': + GoogleFonts.bigShouldersStencilDisplayTextTheme, + 'Big Shoulders Stencil Text': + GoogleFonts.bigShouldersStencilTextTextTheme, + 'Big Shoulders Text': GoogleFonts.bigShouldersTextTextTheme, + 'Bigelow Rules': GoogleFonts.bigelowRulesTextTheme, + 'Bigshot One': GoogleFonts.bigshotOneTextTheme, + 'Bilbo': GoogleFonts.bilboTextTheme, + 'Bilbo Swash Caps': GoogleFonts.bilboSwashCapsTextTheme, + 'BioRhyme': GoogleFonts.bioRhymeTextTheme, + 'BioRhyme Expanded': GoogleFonts.bioRhymeExpandedTextTheme, + 'Biryani': GoogleFonts.biryaniTextTheme, + 'Bitter': GoogleFonts.bitterTextTheme, + 'Black And White Picture': GoogleFonts.blackAndWhitePictureTextTheme, + 'Black Han Sans': GoogleFonts.blackHanSansTextTheme, + 'Black Ops One': GoogleFonts.blackOpsOneTextTheme, + 'Blinker': GoogleFonts.blinkerTextTheme, + 'Bonbon': GoogleFonts.bonbonTextTheme, + 'Boogaloo': GoogleFonts.boogalooTextTheme, + 'Bowlby One': GoogleFonts.bowlbyOneTextTheme, + 'Bowlby One SC': GoogleFonts.bowlbyOneScTextTheme, + 'Brawler': GoogleFonts.brawlerTextTheme, + 'Bree Serif': GoogleFonts.breeSerifTextTheme, + 'Bubblegum Sans': GoogleFonts.bubblegumSansTextTheme, + 'Bubbler One': GoogleFonts.bubblerOneTextTheme, + 'Buda': GoogleFonts.budaTextTheme, + 'Buenard': GoogleFonts.buenardTextTheme, + 'Bungee': GoogleFonts.bungeeTextTheme, + 'Bungee Hairline': GoogleFonts.bungeeHairlineTextTheme, + 'Bungee Inline': GoogleFonts.bungeeInlineTextTheme, + 'Bungee Outline': GoogleFonts.bungeeOutlineTextTheme, + 'Bungee Shade': GoogleFonts.bungeeShadeTextTheme, + 'Butcherman': GoogleFonts.butchermanTextTheme, + 'Butterfly Kids': GoogleFonts.butterflyKidsTextTheme, + 'Cabin': GoogleFonts.cabinTextTheme, + 'Cabin Condensed': GoogleFonts.cabinCondensedTextTheme, + 'Cabin Sketch': GoogleFonts.cabinSketchTextTheme, + 'Caesar Dressing': GoogleFonts.caesarDressingTextTheme, + 'Cagliostro': GoogleFonts.cagliostroTextTheme, + 'Cairo': GoogleFonts.cairoTextTheme, + 'Caladea': GoogleFonts.caladeaTextTheme, + 'Calistoga': GoogleFonts.calistogaTextTheme, + 'Calligraffitti': GoogleFonts.calligraffittiTextTheme, + 'Cambay': GoogleFonts.cambayTextTheme, + 'Cambo': GoogleFonts.camboTextTheme, + 'Candal': GoogleFonts.candalTextTheme, + 'Cantarell': GoogleFonts.cantarellTextTheme, + 'Cantata One': GoogleFonts.cantataOneTextTheme, + 'Cantora One': GoogleFonts.cantoraOneTextTheme, + 'Capriola': GoogleFonts.capriolaTextTheme, + 'Cardo': GoogleFonts.cardoTextTheme, + 'Carme': GoogleFonts.carmeTextTheme, + 'Carrois Gothic': GoogleFonts.carroisGothicTextTheme, + 'Carrois Gothic SC': GoogleFonts.carroisGothicScTextTheme, + 'Carter One': GoogleFonts.carterOneTextTheme, + 'Castoro': GoogleFonts.castoroTextTheme, + 'Catamaran': GoogleFonts.catamaranTextTheme, + 'Caudex': GoogleFonts.caudexTextTheme, + 'Caveat': GoogleFonts.caveatTextTheme, + 'Caveat Brush': GoogleFonts.caveatBrushTextTheme, + 'Cedarville Cursive': GoogleFonts.cedarvilleCursiveTextTheme, + 'Ceviche One': GoogleFonts.cevicheOneTextTheme, + 'Chakra Petch': GoogleFonts.chakraPetchTextTheme, + 'Changa': GoogleFonts.changaTextTheme, + 'Changa One': GoogleFonts.changaOneTextTheme, + 'Chango': GoogleFonts.changoTextTheme, + 'Charm': GoogleFonts.charmTextTheme, + 'Charmonman': GoogleFonts.charmonmanTextTheme, + 'Chathura': GoogleFonts.chathuraTextTheme, + 'Chau Philomene One': GoogleFonts.chauPhilomeneOneTextTheme, + 'Chela One': GoogleFonts.chelaOneTextTheme, + 'Chelsea Market': GoogleFonts.chelseaMarketTextTheme, + 'Cherry Cream Soda': GoogleFonts.cherryCreamSodaTextTheme, + 'Cherry Swash': GoogleFonts.cherrySwashTextTheme, + 'Chewy': GoogleFonts.chewyTextTheme, + 'Chicle': GoogleFonts.chicleTextTheme, + 'Chilanka': GoogleFonts.chilankaTextTheme, + 'Chivo': GoogleFonts.chivoTextTheme, + 'Chonburi': GoogleFonts.chonburiTextTheme, + 'Cinzel': GoogleFonts.cinzelTextTheme, + 'Cinzel Decorative': GoogleFonts.cinzelDecorativeTextTheme, + 'Clicker Script': GoogleFonts.clickerScriptTextTheme, + 'Coda': GoogleFonts.codaTextTheme, + 'Coda Caption': GoogleFonts.codaCaptionTextTheme, + 'Codystar': GoogleFonts.codystarTextTheme, + 'Coiny': GoogleFonts.coinyTextTheme, + 'Combo': GoogleFonts.comboTextTheme, + 'Comfortaa': GoogleFonts.comfortaaTextTheme, + 'Comic Neue': GoogleFonts.comicNeueTextTheme, + 'Coming Soon': GoogleFonts.comingSoonTextTheme, + 'Commissioner': GoogleFonts.commissionerTextTheme, + 'Concert One': GoogleFonts.concertOneTextTheme, + 'Condiment': GoogleFonts.condimentTextTheme, + 'Contrail One': GoogleFonts.contrailOneTextTheme, + 'Convergence': GoogleFonts.convergenceTextTheme, + 'Cookie': GoogleFonts.cookieTextTheme, + 'Copse': GoogleFonts.copseTextTheme, + 'Corben': GoogleFonts.corbenTextTheme, + 'Cormorant': GoogleFonts.cormorantTextTheme, + 'Cormorant Garamond': GoogleFonts.cormorantGaramondTextTheme, + 'Cormorant Infant': GoogleFonts.cormorantInfantTextTheme, + 'Cormorant SC': GoogleFonts.cormorantScTextTheme, + 'Cormorant Unicase': GoogleFonts.cormorantUnicaseTextTheme, + 'Cormorant Upright': GoogleFonts.cormorantUprightTextTheme, + 'Courgette': GoogleFonts.courgetteTextTheme, + 'Courier Prime': GoogleFonts.courierPrimeTextTheme, + 'Cousine': GoogleFonts.cousineTextTheme, + 'Coustard': GoogleFonts.coustardTextTheme, + 'Covered By Your Grace': GoogleFonts.coveredByYourGraceTextTheme, + 'Crafty Girls': GoogleFonts.craftyGirlsTextTheme, + 'Creepster': GoogleFonts.creepsterTextTheme, + 'Crete Round': GoogleFonts.creteRoundTextTheme, + 'Crimson Pro': GoogleFonts.crimsonProTextTheme, + 'Crimson Text': GoogleFonts.crimsonTextTextTheme, + 'Croissant One': GoogleFonts.croissantOneTextTheme, + 'Crushed': GoogleFonts.crushedTextTheme, + 'Cuprum': GoogleFonts.cuprumTextTheme, + 'Cute Font': GoogleFonts.cuteFontTextTheme, + 'Cutive': GoogleFonts.cutiveTextTheme, + 'Cutive Mono': GoogleFonts.cutiveMonoTextTheme, + 'DM Mono': GoogleFonts.dmMonoTextTheme, + 'DM Sans': GoogleFonts.dmSansTextTheme, + 'DM Serif Display': GoogleFonts.dmSerifDisplayTextTheme, + 'DM Serif Text': GoogleFonts.dmSerifTextTextTheme, + 'Damion': GoogleFonts.damionTextTheme, + 'Dancing Script': GoogleFonts.dancingScriptTextTheme, + 'Darker Grotesque': GoogleFonts.darkerGrotesqueTextTheme, + 'David Libre': GoogleFonts.davidLibreTextTheme, + 'Dawning of a New Day': GoogleFonts.dawningOfANewDayTextTheme, + 'Days One': GoogleFonts.daysOneTextTheme, + 'Dekko': GoogleFonts.dekkoTextTheme, + 'Delius': GoogleFonts.deliusTextTheme, + 'Delius Swash Caps': GoogleFonts.deliusSwashCapsTextTheme, + 'Delius Unicase': GoogleFonts.deliusUnicaseTextTheme, + 'Della Respira': GoogleFonts.dellaRespiraTextTheme, + 'Denk One': GoogleFonts.denkOneTextTheme, + 'Devonshire': GoogleFonts.devonshireTextTheme, + 'Dhurjati': GoogleFonts.dhurjatiTextTheme, + 'Didact Gothic': GoogleFonts.didactGothicTextTheme, + 'Diplomata': GoogleFonts.diplomataTextTheme, + 'Diplomata SC': GoogleFonts.diplomataScTextTheme, + 'Do Hyeon': GoogleFonts.doHyeonTextTheme, + 'Dokdo': GoogleFonts.dokdoTextTheme, + 'Domine': GoogleFonts.domineTextTheme, + 'Donegal One': GoogleFonts.donegalOneTextTheme, + 'Doppio One': GoogleFonts.doppioOneTextTheme, + 'Dorsa': GoogleFonts.dorsaTextTheme, + 'Dosis': GoogleFonts.dosisTextTheme, + 'Dr Sugiyama': GoogleFonts.drSugiyamaTextTheme, + 'Droid Sans': GoogleFonts.droidSansTextTheme, + 'Droid Sans Mono': GoogleFonts.droidSansMonoTextTheme, + 'Droid Serif': GoogleFonts.droidSerifTextTheme, + 'Duru Sans': GoogleFonts.duruSansTextTheme, + 'Dynalight': GoogleFonts.dynalightTextTheme, + 'EB Garamond': GoogleFonts.ebGaramondTextTheme, + 'Eagle Lake': GoogleFonts.eagleLakeTextTheme, + 'East Sea Dokdo': GoogleFonts.eastSeaDokdoTextTheme, + 'Eater': GoogleFonts.eaterTextTheme, + 'Economica': GoogleFonts.economicaTextTheme, + 'Eczar': GoogleFonts.eczarTextTheme, + 'El Messiri': GoogleFonts.elMessiriTextTheme, + 'Electrolize': GoogleFonts.electrolizeTextTheme, + 'Elsie': GoogleFonts.elsieTextTheme, + 'Elsie Swash Caps': GoogleFonts.elsieSwashCapsTextTheme, + 'Emblema One': GoogleFonts.emblemaOneTextTheme, + 'Emilys Candy': GoogleFonts.emilysCandyTextTheme, + 'Encode Sans': GoogleFonts.encodeSansTextTheme, + 'Encode Sans Condensed': GoogleFonts.encodeSansCondensedTextTheme, + 'Encode Sans Expanded': GoogleFonts.encodeSansExpandedTextTheme, + 'Encode Sans Semi Condensed': + GoogleFonts.encodeSansSemiCondensedTextTheme, + 'Encode Sans Semi Expanded': + GoogleFonts.encodeSansSemiExpandedTextTheme, + 'Engagement': GoogleFonts.engagementTextTheme, + 'Englebert': GoogleFonts.englebertTextTheme, + 'Enriqueta': GoogleFonts.enriquetaTextTheme, + 'Epilogue': GoogleFonts.epilogueTextTheme, + 'Erica One': GoogleFonts.ericaOneTextTheme, + 'Esteban': GoogleFonts.estebanTextTheme, + 'Euphoria Script': GoogleFonts.euphoriaScriptTextTheme, + 'Ewert': GoogleFonts.ewertTextTheme, + 'Exo': GoogleFonts.exoTextTheme, + 'Exo 2': GoogleFonts.exo2TextTheme, + 'Expletus Sans': GoogleFonts.expletusSansTextTheme, + 'Fahkwang': GoogleFonts.fahkwangTextTheme, + 'Fanwood Text': GoogleFonts.fanwoodTextTextTheme, + 'Farro': GoogleFonts.farroTextTheme, + 'Farsan': GoogleFonts.farsanTextTheme, + 'Fascinate': GoogleFonts.fascinateTextTheme, + 'Fascinate Inline': GoogleFonts.fascinateInlineTextTheme, + 'Faster One': GoogleFonts.fasterOneTextTheme, + 'Fauna One': GoogleFonts.faunaOneTextTheme, + 'Faustina': GoogleFonts.faustinaTextTheme, + 'Federant': GoogleFonts.federantTextTheme, + 'Federo': GoogleFonts.federoTextTheme, + 'Felipa': GoogleFonts.felipaTextTheme, + 'Fenix': GoogleFonts.fenixTextTheme, + 'Finger Paint': GoogleFonts.fingerPaintTextTheme, + 'Fira Code': GoogleFonts.firaCodeTextTheme, + 'Fira Mono': GoogleFonts.firaMonoTextTheme, + 'Fira Sans': GoogleFonts.firaSansTextTheme, + 'Fira Sans Condensed': GoogleFonts.firaSansCondensedTextTheme, + 'Fira Sans Extra Condensed': + GoogleFonts.firaSansExtraCondensedTextTheme, + 'Fjalla One': GoogleFonts.fjallaOneTextTheme, + 'Fjord One': GoogleFonts.fjordOneTextTheme, + 'Flamenco': GoogleFonts.flamencoTextTheme, + 'Flavors': GoogleFonts.flavorsTextTheme, + 'Fondamento': GoogleFonts.fondamentoTextTheme, + 'Fontdiner Swanky': GoogleFonts.fontdinerSwankyTextTheme, + 'Forum': GoogleFonts.forumTextTheme, + 'Francois One': GoogleFonts.francoisOneTextTheme, + 'Frank Ruhl Libre': GoogleFonts.frankRuhlLibreTextTheme, + 'Fraunces': GoogleFonts.frauncesTextTheme, + 'Freckle Face': GoogleFonts.freckleFaceTextTheme, + 'Fredericka the Great': GoogleFonts.frederickaTheGreatTextTheme, + 'Fredoka One': GoogleFonts.fredokaOneTextTheme, + 'Fresca': GoogleFonts.frescaTextTheme, + 'Frijole': GoogleFonts.frijoleTextTheme, + 'Fruktur': GoogleFonts.frukturTextTheme, + 'Fugaz One': GoogleFonts.fugazOneTextTheme, + 'GFS Didot': GoogleFonts.gfsDidotTextTheme, + 'GFS Neohellenic': GoogleFonts.gfsNeohellenicTextTheme, + 'Gabriela': GoogleFonts.gabrielaTextTheme, + 'Gaegu': GoogleFonts.gaeguTextTheme, + 'Gafata': GoogleFonts.gafataTextTheme, + 'Galada': GoogleFonts.galadaTextTheme, + 'Galdeano': GoogleFonts.galdeanoTextTheme, + 'Galindo': GoogleFonts.galindoTextTheme, + 'Gamja Flower': GoogleFonts.gamjaFlowerTextTheme, + 'Gayathri': GoogleFonts.gayathriTextTheme, + 'Gelasio': GoogleFonts.gelasioTextTheme, + 'Gentium Basic': GoogleFonts.gentiumBasicTextTheme, + 'Gentium Book Basic': GoogleFonts.gentiumBookBasicTextTheme, + 'Geo': GoogleFonts.geoTextTheme, + 'Geostar': GoogleFonts.geostarTextTheme, + 'Geostar Fill': GoogleFonts.geostarFillTextTheme, + 'Germania One': GoogleFonts.germaniaOneTextTheme, + 'Gidugu': GoogleFonts.giduguTextTheme, + 'Gilda Display': GoogleFonts.gildaDisplayTextTheme, + 'Girassol': GoogleFonts.girassolTextTheme, + 'Give You Glory': GoogleFonts.giveYouGloryTextTheme, + 'Glass Antiqua': GoogleFonts.glassAntiquaTextTheme, + 'Glegoo': GoogleFonts.glegooTextTheme, + 'Gloria Hallelujah': GoogleFonts.gloriaHallelujahTextTheme, + 'Goblin One': GoogleFonts.goblinOneTextTheme, + 'Gochi Hand': GoogleFonts.gochiHandTextTheme, + 'Goldman': GoogleFonts.goldmanTextTheme, + 'Gorditas': GoogleFonts.gorditasTextTheme, + 'Gothic A1': GoogleFonts.gothicA1TextTheme, + 'Gotu': GoogleFonts.gotuTextTheme, + 'Goudy Bookletter 1911': GoogleFonts.goudyBookletter1911TextTheme, + 'Graduate': GoogleFonts.graduateTextTheme, + 'Grand Hotel': GoogleFonts.grandHotelTextTheme, + 'Grandstander': GoogleFonts.grandstanderTextTheme, + 'Gravitas One': GoogleFonts.gravitasOneTextTheme, + 'Great Vibes': GoogleFonts.greatVibesTextTheme, + 'Grenze': GoogleFonts.grenzeTextTheme, + 'Grenze Gotisch': GoogleFonts.grenzeGotischTextTheme, + 'Griffy': GoogleFonts.griffyTextTheme, + 'Gruppo': GoogleFonts.gruppoTextTheme, + 'Gudea': GoogleFonts.gudeaTextTheme, + 'Gugi': GoogleFonts.gugiTextTheme, + 'Gupter': GoogleFonts.gupterTextTheme, + 'Gurajada': GoogleFonts.gurajadaTextTheme, + 'Habibi': GoogleFonts.habibiTextTheme, + 'Hachi Maru Pop': GoogleFonts.hachiMaruPopTextTheme, + 'Halant': GoogleFonts.halantTextTheme, + 'Hammersmith One': GoogleFonts.hammersmithOneTextTheme, + 'Hanalei': GoogleFonts.hanaleiTextTheme, + 'Hanalei Fill': GoogleFonts.hanaleiFillTextTheme, + 'Handlee': GoogleFonts.handleeTextTheme, + 'Happy Monkey': GoogleFonts.happyMonkeyTextTheme, + 'Harmattan': GoogleFonts.harmattanTextTheme, + 'Headland One': GoogleFonts.headlandOneTextTheme, + 'Heebo': GoogleFonts.heeboTextTheme, + 'Henny Penny': GoogleFonts.hennyPennyTextTheme, + 'Hepta Slab': GoogleFonts.heptaSlabTextTheme, + 'Herr Von Muellerhoff': GoogleFonts.herrVonMuellerhoffTextTheme, + 'Hi Melody': GoogleFonts.hiMelodyTextTheme, + 'Hind': GoogleFonts.hindTextTheme, + 'Hind Guntur': GoogleFonts.hindGunturTextTheme, + 'Hind Madurai': GoogleFonts.hindMaduraiTextTheme, + 'Hind Siliguri': GoogleFonts.hindSiliguriTextTheme, + 'Hind Vadodara': GoogleFonts.hindVadodaraTextTheme, + 'Holtwood One SC': GoogleFonts.holtwoodOneScTextTheme, + 'Homemade Apple': GoogleFonts.homemadeAppleTextTheme, + 'Homenaje': GoogleFonts.homenajeTextTheme, + 'IBM Plex Mono': GoogleFonts.ibmPlexMonoTextTheme, + 'IBM Plex Sans': GoogleFonts.ibmPlexSansTextTheme, + 'IBM Plex Sans Condensed': GoogleFonts.ibmPlexSansCondensedTextTheme, + 'IBM Plex Serif': GoogleFonts.ibmPlexSerifTextTheme, + 'IM Fell DW Pica': GoogleFonts.imFellDwPicaTextTheme, + 'IM Fell DW Pica SC': GoogleFonts.imFellDwPicaScTextTheme, + 'IM Fell Double Pica': GoogleFonts.imFellDoublePicaTextTheme, + 'IM Fell Double Pica SC': GoogleFonts.imFellDoublePicaScTextTheme, + 'IM Fell English': GoogleFonts.imFellEnglishTextTheme, + 'IM Fell English SC': GoogleFonts.imFellEnglishScTextTheme, + 'IM Fell French Canon': GoogleFonts.imFellFrenchCanonTextTheme, + 'IM Fell French Canon SC': GoogleFonts.imFellFrenchCanonScTextTheme, + 'IM Fell Great Primer': GoogleFonts.imFellGreatPrimerTextTheme, + 'IM Fell Great Primer SC': GoogleFonts.imFellGreatPrimerScTextTheme, + 'Ibarra Real Nova': GoogleFonts.ibarraRealNovaTextTheme, + 'Iceberg': GoogleFonts.icebergTextTheme, + 'Iceland': GoogleFonts.icelandTextTheme, + 'Imprima': GoogleFonts.imprimaTextTheme, + 'Inconsolata': GoogleFonts.inconsolataTextTheme, + 'Inder': GoogleFonts.inderTextTheme, + 'Indie Flower': GoogleFonts.indieFlowerTextTheme, + 'Inika': GoogleFonts.inikaTextTheme, + 'Inknut Antiqua': GoogleFonts.inknutAntiquaTextTheme, + 'Inria Sans': GoogleFonts.inriaSansTextTheme, + 'Inria Serif': GoogleFonts.inriaSerifTextTheme, + 'Inter': GoogleFonts.interTextTheme, + 'Irish Grover': GoogleFonts.irishGroverTextTheme, + 'Istok Web': GoogleFonts.istokWebTextTheme, + 'Italiana': GoogleFonts.italianaTextTheme, + 'Italianno': GoogleFonts.italiannoTextTheme, + 'Itim': GoogleFonts.itimTextTheme, + 'Jacques Francois': GoogleFonts.jacquesFrancoisTextTheme, + 'Jacques Francois Shadow': GoogleFonts.jacquesFrancoisShadowTextTheme, + 'Jaldi': GoogleFonts.jaldiTextTheme, + 'JetBrains Mono': GoogleFonts.jetBrainsMonoTextTheme, + 'Jim Nightshade': GoogleFonts.jimNightshadeTextTheme, + 'Jockey One': GoogleFonts.jockeyOneTextTheme, + 'Jolly Lodger': GoogleFonts.jollyLodgerTextTheme, + 'Jomhuria': GoogleFonts.jomhuriaTextTheme, + 'Jomolhari': GoogleFonts.jomolhariTextTheme, + 'Josefin Sans': GoogleFonts.josefinSansTextTheme, + 'Josefin Slab': GoogleFonts.josefinSlabTextTheme, + 'Jost': GoogleFonts.jostTextTheme, + 'Joti One': GoogleFonts.jotiOneTextTheme, + 'Jua': GoogleFonts.juaTextTheme, + 'Judson': GoogleFonts.judsonTextTheme, + 'Julee': GoogleFonts.juleeTextTheme, + 'Julius Sans One': GoogleFonts.juliusSansOneTextTheme, + 'Junge': GoogleFonts.jungeTextTheme, + 'Jura': GoogleFonts.juraTextTheme, + 'Just Another Hand': GoogleFonts.justAnotherHandTextTheme, + 'Just Me Again Down Here': GoogleFonts.justMeAgainDownHereTextTheme, + 'K2D': GoogleFonts.k2dTextTheme, + 'Kadwa': GoogleFonts.kadwaTextTheme, + 'Kalam': GoogleFonts.kalamTextTheme, + 'Kameron': GoogleFonts.kameronTextTheme, + 'Kanit': GoogleFonts.kanitTextTheme, + 'Kantumruy': GoogleFonts.kantumruyTextTheme, + 'Karla': GoogleFonts.karlaTextTheme, + 'Karma': GoogleFonts.karmaTextTheme, + 'Katibeh': GoogleFonts.katibehTextTheme, + 'Kaushan Script': GoogleFonts.kaushanScriptTextTheme, + 'Kavivanar': GoogleFonts.kavivanarTextTheme, + 'Kavoon': GoogleFonts.kavoonTextTheme, + 'Kdam Thmor': GoogleFonts.kdamThmorTextTheme, + 'Keania One': GoogleFonts.keaniaOneTextTheme, + 'Kelly Slab': GoogleFonts.kellySlabTextTheme, + 'Kenia': GoogleFonts.keniaTextTheme, + 'Khand': GoogleFonts.khandTextTheme, + 'Khula': GoogleFonts.khulaTextTheme, + 'Kirang Haerang': GoogleFonts.kirangHaerangTextTheme, + 'Kite One': GoogleFonts.kiteOneTextTheme, + 'Knewave': GoogleFonts.knewaveTextTheme, + 'KoHo': GoogleFonts.koHoTextTheme, + 'Kodchasan': GoogleFonts.kodchasanTextTheme, + 'Kosugi': GoogleFonts.kosugiTextTheme, + 'Kosugi Maru': GoogleFonts.kosugiMaruTextTheme, + 'Kotta One': GoogleFonts.kottaOneTextTheme, + 'Kranky': GoogleFonts.krankyTextTheme, + 'Kreon': GoogleFonts.kreonTextTheme, + 'Kristi': GoogleFonts.kristiTextTheme, + 'Krona One': GoogleFonts.kronaOneTextTheme, + 'Krub': GoogleFonts.krubTextTheme, + 'Kufam': GoogleFonts.kufamTextTheme, + 'Kulim Park': GoogleFonts.kulimParkTextTheme, + 'Kumar One': GoogleFonts.kumarOneTextTheme, + 'Kumar One Outline': GoogleFonts.kumarOneOutlineTextTheme, + 'Kumbh Sans': GoogleFonts.kumbhSansTextTheme, + 'Kurale': GoogleFonts.kuraleTextTheme, + 'La Belle Aurore': GoogleFonts.laBelleAuroreTextTheme, + 'Lacquer': GoogleFonts.lacquerTextTheme, + 'Laila': GoogleFonts.lailaTextTheme, + 'Lakki Reddy': GoogleFonts.lakkiReddyTextTheme, + 'Lalezar': GoogleFonts.lalezarTextTheme, + 'Lancelot': GoogleFonts.lancelotTextTheme, + 'Langar': GoogleFonts.langarTextTheme, + 'Lateef': GoogleFonts.lateefTextTheme, + 'Lato': GoogleFonts.latoTextTheme, + 'League Script': GoogleFonts.leagueScriptTextTheme, + 'Leckerli One': GoogleFonts.leckerliOneTextTheme, + 'Ledger': GoogleFonts.ledgerTextTheme, + 'Lekton': GoogleFonts.lektonTextTheme, + 'Lemon': GoogleFonts.lemonTextTheme, + 'Lemonada': GoogleFonts.lemonadaTextTheme, + 'Lexend Deca': GoogleFonts.lexendDecaTextTheme, + 'Lexend Exa': GoogleFonts.lexendExaTextTheme, + 'Lexend Giga': GoogleFonts.lexendGigaTextTheme, + 'Lexend Mega': GoogleFonts.lexendMegaTextTheme, + 'Lexend Peta': GoogleFonts.lexendPetaTextTheme, + 'Lexend Tera': GoogleFonts.lexendTeraTextTheme, + 'Lexend Zetta': GoogleFonts.lexendZettaTextTheme, + 'Libre Barcode 128': GoogleFonts.libreBarcode128TextTheme, + 'Libre Barcode 128 Text': GoogleFonts.libreBarcode128TextTextTheme, + 'Libre Barcode 39': GoogleFonts.libreBarcode39TextTheme, + 'Libre Barcode 39 Extended': + GoogleFonts.libreBarcode39ExtendedTextTheme, + 'Libre Barcode 39 Extended Text': + GoogleFonts.libreBarcode39ExtendedTextTextTheme, + 'Libre Barcode 39 Text': GoogleFonts.libreBarcode39TextTextTheme, + 'Libre Baskerville': GoogleFonts.libreBaskervilleTextTheme, + 'Libre Caslon Display': GoogleFonts.libreCaslonDisplayTextTheme, + 'Libre Caslon Text': GoogleFonts.libreCaslonTextTextTheme, + 'Libre Franklin': GoogleFonts.libreFranklinTextTheme, + 'Life Savers': GoogleFonts.lifeSaversTextTheme, + 'Lilita One': GoogleFonts.lilitaOneTextTheme, + 'Lily Script One': GoogleFonts.lilyScriptOneTextTheme, + 'Limelight': GoogleFonts.limelightTextTheme, + 'Linden Hill': GoogleFonts.lindenHillTextTheme, + 'Literata': GoogleFonts.literataTextTheme, + 'Liu Jian Mao Cao': GoogleFonts.liuJianMaoCaoTextTheme, + 'Livvic': GoogleFonts.livvicTextTheme, + 'Lobster': GoogleFonts.lobsterTextTheme, + 'Lobster Two': GoogleFonts.lobsterTwoTextTheme, + 'Londrina Outline': GoogleFonts.londrinaOutlineTextTheme, + 'Londrina Shadow': GoogleFonts.londrinaShadowTextTheme, + 'Londrina Sketch': GoogleFonts.londrinaSketchTextTheme, + 'Londrina Solid': GoogleFonts.londrinaSolidTextTheme, + 'Long Cang': GoogleFonts.longCangTextTheme, + 'Lora': GoogleFonts.loraTextTheme, + 'Love Ya Like A Sister': GoogleFonts.loveYaLikeASisterTextTheme, + 'Loved by the King': GoogleFonts.lovedByTheKingTextTheme, + 'Lovers Quarrel': GoogleFonts.loversQuarrelTextTheme, + 'Luckiest Guy': GoogleFonts.luckiestGuyTextTheme, + 'Lusitana': GoogleFonts.lusitanaTextTheme, + 'Lustria': GoogleFonts.lustriaTextTheme, + 'M PLUS 1p': GoogleFonts.mPlus1pTextTheme, + 'M PLUS Rounded 1c': GoogleFonts.mPlusRounded1cTextTheme, + 'Ma Shan Zheng': GoogleFonts.maShanZhengTextTheme, + 'Macondo': GoogleFonts.macondoTextTheme, + 'Macondo Swash Caps': GoogleFonts.macondoSwashCapsTextTheme, + 'Mada': GoogleFonts.madaTextTheme, + 'Magra': GoogleFonts.magraTextTheme, + 'Maiden Orange': GoogleFonts.maidenOrangeTextTheme, + 'Maitree': GoogleFonts.maitreeTextTheme, + 'Major Mono Display': GoogleFonts.majorMonoDisplayTextTheme, + 'Mako': GoogleFonts.makoTextTheme, + 'Mali': GoogleFonts.maliTextTheme, + 'Mallanna': GoogleFonts.mallannaTextTheme, + 'Mandali': GoogleFonts.mandaliTextTheme, + 'Manjari': GoogleFonts.manjariTextTheme, + 'Manrope': GoogleFonts.manropeTextTheme, + 'Mansalva': GoogleFonts.mansalvaTextTheme, + 'Manuale': GoogleFonts.manualeTextTheme, + 'Marcellus': GoogleFonts.marcellusTextTheme, + 'Marcellus SC': GoogleFonts.marcellusScTextTheme, + 'Marck Script': GoogleFonts.marckScriptTextTheme, + 'Margarine': GoogleFonts.margarineTextTheme, + 'Markazi Text': GoogleFonts.markaziTextTextTheme, + 'Marko One': GoogleFonts.markoOneTextTheme, + 'Marmelad': GoogleFonts.marmeladTextTheme, + 'Martel': GoogleFonts.martelTextTheme, + 'Martel Sans': GoogleFonts.martelSansTextTheme, + 'Marvel': GoogleFonts.marvelTextTheme, + 'Mate': GoogleFonts.mateTextTheme, + 'Mate SC': GoogleFonts.mateScTextTheme, + 'Maven Pro': GoogleFonts.mavenProTextTheme, + 'McLaren': GoogleFonts.mcLarenTextTheme, + 'Meddon': GoogleFonts.meddonTextTheme, + 'MedievalSharp': GoogleFonts.medievalSharpTextTheme, + 'Medula One': GoogleFonts.medulaOneTextTheme, + 'Meera Inimai': GoogleFonts.meeraInimaiTextTheme, + 'Megrim': GoogleFonts.megrimTextTheme, + 'Meie Script': GoogleFonts.meieScriptTextTheme, + 'Merienda': GoogleFonts.meriendaTextTheme, + 'Merienda One': GoogleFonts.meriendaOneTextTheme, + 'Merriweather': GoogleFonts.merriweatherTextTheme, + 'Merriweather Sans': GoogleFonts.merriweatherSansTextTheme, + 'Metal Mania': GoogleFonts.metalManiaTextTheme, + 'Metamorphous': GoogleFonts.metamorphousTextTheme, + 'Metrophobic': GoogleFonts.metrophobicTextTheme, + 'Michroma': GoogleFonts.michromaTextTheme, + 'Milonga': GoogleFonts.milongaTextTheme, + 'Miltonian': GoogleFonts.miltonianTextTheme, + 'Miltonian Tattoo': GoogleFonts.miltonianTattooTextTheme, + 'Mina': GoogleFonts.minaTextTheme, + 'Miniver': GoogleFonts.miniverTextTheme, + 'Miriam Libre': GoogleFonts.miriamLibreTextTheme, + 'Mirza': GoogleFonts.mirzaTextTheme, + 'Miss Fajardose': GoogleFonts.missFajardoseTextTheme, + 'Mitr': GoogleFonts.mitrTextTheme, + 'Modak': GoogleFonts.modakTextTheme, + 'Modern Antiqua': GoogleFonts.modernAntiquaTextTheme, + 'Mogra': GoogleFonts.mograTextTheme, + 'Molengo': GoogleFonts.molengoTextTheme, + 'Molle': GoogleFonts.molleTextTheme, + 'Monda': GoogleFonts.mondaTextTheme, + 'Monofett': GoogleFonts.monofettTextTheme, + 'Monoton': GoogleFonts.monotonTextTheme, + 'Monsieur La Doulaise': GoogleFonts.monsieurLaDoulaiseTextTheme, + 'Montaga': GoogleFonts.montagaTextTheme, + 'Montez': GoogleFonts.montezTextTheme, + 'Montserrat': GoogleFonts.montserratTextTheme, + 'Montserrat Alternates': GoogleFonts.montserratAlternatesTextTheme, + 'Montserrat Subrayada': GoogleFonts.montserratSubrayadaTextTheme, + 'Mountains of Christmas': GoogleFonts.mountainsOfChristmasTextTheme, + 'Mouse Memoirs': GoogleFonts.mouseMemoirsTextTheme, + 'Mr Bedfort': GoogleFonts.mrBedfortTextTheme, + 'Mr Dafoe': GoogleFonts.mrDafoeTextTheme, + 'Mr De Haviland': GoogleFonts.mrDeHavilandTextTheme, + 'Mrs Saint Delafield': GoogleFonts.mrsSaintDelafieldTextTheme, + 'Mrs Sheppards': GoogleFonts.mrsSheppardsTextTheme, + 'Mukta': GoogleFonts.muktaTextTheme, + 'Mukta Mahee': GoogleFonts.muktaMaheeTextTheme, + 'Mukta Malar': GoogleFonts.muktaMalarTextTheme, + 'Mukta Vaani': GoogleFonts.muktaVaaniTextTheme, + 'Mulish': GoogleFonts.mulishTextTheme, + 'MuseoModerno': GoogleFonts.museoModernoTextTheme, + 'Mystery Quest': GoogleFonts.mysteryQuestTextTheme, + 'NTR': GoogleFonts.ntrTextTheme, + 'Nanum Brush Script': GoogleFonts.nanumBrushScriptTextTheme, + 'Nanum Gothic': GoogleFonts.nanumGothicTextTheme, + 'Nanum Gothic Coding': GoogleFonts.nanumGothicCodingTextTheme, + 'Nanum Myeongjo': GoogleFonts.nanumMyeongjoTextTheme, + 'Nanum Pen Script': GoogleFonts.nanumPenScriptTextTheme, + 'Nerko One': GoogleFonts.nerkoOneTextTheme, + 'Neucha': GoogleFonts.neuchaTextTheme, + 'Neuton': GoogleFonts.neutonTextTheme, + 'New Rocker': GoogleFonts.newRockerTextTheme, + 'News Cycle': GoogleFonts.newsCycleTextTheme, + 'Niconne': GoogleFonts.niconneTextTheme, + 'Niramit': GoogleFonts.niramitTextTheme, + 'Nixie One': GoogleFonts.nixieOneTextTheme, + 'Nobile': GoogleFonts.nobileTextTheme, + 'Norican': GoogleFonts.noricanTextTheme, + 'Nosifer': GoogleFonts.nosiferTextTheme, + 'Notable': GoogleFonts.notableTextTheme, + 'Nothing You Could Do': GoogleFonts.nothingYouCouldDoTextTheme, + 'Noticia Text': GoogleFonts.noticiaTextTextTheme, + 'Noto Color Emoji Compat': GoogleFonts.notoColorEmojiCompatTextTheme, + 'Noto Sans': GoogleFonts.notoSansTextTheme, + 'Noto Serif': GoogleFonts.notoSerifTextTheme, + 'Nova Cut': GoogleFonts.novaCutTextTheme, + 'Nova Flat': GoogleFonts.novaFlatTextTheme, + 'Nova Mono': GoogleFonts.novaMonoTextTheme, + 'Nova Oval': GoogleFonts.novaOvalTextTheme, + 'Nova Round': GoogleFonts.novaRoundTextTheme, + 'Nova Script': GoogleFonts.novaScriptTextTheme, + 'Nova Slim': GoogleFonts.novaSlimTextTheme, + 'Nova Square': GoogleFonts.novaSquareTextTheme, + 'Numans': GoogleFonts.numansTextTheme, + 'Nunito': GoogleFonts.nunitoTextTheme, + 'Nunito Sans': GoogleFonts.nunitoSansTextTheme, + 'Odibee Sans': GoogleFonts.odibeeSansTextTheme, + 'Odor Mean Chey': GoogleFonts.odorMeanCheyTextTheme, + 'Offside': GoogleFonts.offsideTextTheme, + 'Old Standard TT': GoogleFonts.oldStandardTtTextTheme, + 'Oldenburg': GoogleFonts.oldenburgTextTheme, + 'Oleo Script': GoogleFonts.oleoScriptTextTheme, + 'Oleo Script Swash Caps': GoogleFonts.oleoScriptSwashCapsTextTheme, + 'Open Sans': GoogleFonts.openSansTextTheme, + 'Open Sans Condensed': GoogleFonts.openSansCondensedTextTheme, + 'Oranienbaum': GoogleFonts.oranienbaumTextTheme, + 'Orbitron': GoogleFonts.orbitronTextTheme, + 'Oregano': GoogleFonts.oreganoTextTheme, + 'Orienta': GoogleFonts.orientaTextTheme, + 'Original Surfer': GoogleFonts.originalSurferTextTheme, + 'Oswald': GoogleFonts.oswaldTextTheme, + 'Over the Rainbow': GoogleFonts.overTheRainbowTextTheme, + 'Overlock': GoogleFonts.overlockTextTheme, + 'Overlock SC': GoogleFonts.overlockScTextTheme, + 'Overpass': GoogleFonts.overpassTextTheme, + 'Overpass Mono': GoogleFonts.overpassMonoTextTheme, + 'Ovo': GoogleFonts.ovoTextTheme, + 'Oxanium': GoogleFonts.oxaniumTextTheme, + 'Oxygen': GoogleFonts.oxygenTextTheme, + 'Oxygen Mono': GoogleFonts.oxygenMonoTextTheme, + 'PT Mono': GoogleFonts.ptMonoTextTheme, + 'PT Sans': GoogleFonts.ptSansTextTheme, + 'PT Sans Caption': GoogleFonts.ptSansCaptionTextTheme, + 'PT Sans Narrow': GoogleFonts.ptSansNarrowTextTheme, + 'PT Serif': GoogleFonts.ptSerifTextTheme, + 'PT Serif Caption': GoogleFonts.ptSerifCaptionTextTheme, + 'Pacifico': GoogleFonts.pacificoTextTheme, + 'Padauk': GoogleFonts.padaukTextTheme, + 'Palanquin': GoogleFonts.palanquinTextTheme, + 'Palanquin Dark': GoogleFonts.palanquinDarkTextTheme, + 'Pangolin': GoogleFonts.pangolinTextTheme, + 'Paprika': GoogleFonts.paprikaTextTheme, + 'Parisienne': GoogleFonts.parisienneTextTheme, + 'Passero One': GoogleFonts.passeroOneTextTheme, + 'Passion One': GoogleFonts.passionOneTextTheme, + 'Pathway Gothic One': GoogleFonts.pathwayGothicOneTextTheme, + 'Patrick Hand': GoogleFonts.patrickHandTextTheme, + 'Patrick Hand SC': GoogleFonts.patrickHandScTextTheme, + 'Pattaya': GoogleFonts.pattayaTextTheme, + 'Patua One': GoogleFonts.patuaOneTextTheme, + 'Pavanam': GoogleFonts.pavanamTextTheme, + 'Paytone One': GoogleFonts.paytoneOneTextTheme, + 'Peddana': GoogleFonts.peddanaTextTheme, + 'Peralta': GoogleFonts.peraltaTextTheme, + 'Permanent Marker': GoogleFonts.permanentMarkerTextTheme, + 'Petit Formal Script': GoogleFonts.petitFormalScriptTextTheme, + 'Petrona': GoogleFonts.petronaTextTheme, + 'Philosopher': GoogleFonts.philosopherTextTheme, + 'Piazzolla': GoogleFonts.piazzollaTextTheme, + 'Piedra': GoogleFonts.piedraTextTheme, + 'Pinyon Script': GoogleFonts.pinyonScriptTextTheme, + 'Pirata One': GoogleFonts.pirataOneTextTheme, + 'Plaster': GoogleFonts.plasterTextTheme, + 'Play': GoogleFonts.playTextTheme, + 'Playball': GoogleFonts.playballTextTheme, + 'Playfair Display': GoogleFonts.playfairDisplayTextTheme, + 'Playfair Display SC': GoogleFonts.playfairDisplayScTextTheme, + 'Podkova': GoogleFonts.podkovaTextTheme, + 'Poiret One': GoogleFonts.poiretOneTextTheme, + 'Poller One': GoogleFonts.pollerOneTextTheme, + 'Poly': GoogleFonts.polyTextTheme, + 'Pompiere': GoogleFonts.pompiereTextTheme, + 'Pontano Sans': GoogleFonts.pontanoSansTextTheme, + 'Poor Story': GoogleFonts.poorStoryTextTheme, + 'Poppins': GoogleFonts.poppinsTextTheme, + 'Port Lligat Sans': GoogleFonts.portLligatSansTextTheme, + 'Port Lligat Slab': GoogleFonts.portLligatSlabTextTheme, + 'Potta One': GoogleFonts.pottaOneTextTheme, + 'Pragati Narrow': GoogleFonts.pragatiNarrowTextTheme, + 'Prata': GoogleFonts.prataTextTheme, + 'Press Start 2P': GoogleFonts.pressStart2pTextTheme, + 'Pridi': GoogleFonts.pridiTextTheme, + 'Princess Sofia': GoogleFonts.princessSofiaTextTheme, + 'Prociono': GoogleFonts.procionoTextTheme, + 'Prompt': GoogleFonts.promptTextTheme, + 'Prosto One': GoogleFonts.prostoOneTextTheme, + 'Proza Libre': GoogleFonts.prozaLibreTextTheme, + 'Public Sans': GoogleFonts.publicSansTextTheme, + 'Puritan': GoogleFonts.puritanTextTheme, + 'Purple Purse': GoogleFonts.purplePurseTextTheme, + 'Quando': GoogleFonts.quandoTextTheme, + 'Quantico': GoogleFonts.quanticoTextTheme, + 'Quattrocento': GoogleFonts.quattrocentoTextTheme, + 'Quattrocento Sans': GoogleFonts.quattrocentoSansTextTheme, + 'Questrial': GoogleFonts.questrialTextTheme, + 'Quicksand': GoogleFonts.quicksandTextTheme, + 'Quintessential': GoogleFonts.quintessentialTextTheme, + 'Qwigley': GoogleFonts.qwigleyTextTheme, + 'Racing Sans One': GoogleFonts.racingSansOneTextTheme, + 'Radley': GoogleFonts.radleyTextTheme, + 'Rajdhani': GoogleFonts.rajdhaniTextTheme, + 'Rakkas': GoogleFonts.rakkasTextTheme, + 'Raleway': GoogleFonts.ralewayTextTheme, + 'Raleway Dots': GoogleFonts.ralewayDotsTextTheme, + 'Ramabhadra': GoogleFonts.ramabhadraTextTheme, + 'Ramaraja': GoogleFonts.ramarajaTextTheme, + 'Rambla': GoogleFonts.ramblaTextTheme, + 'Rammetto One': GoogleFonts.rammettoOneTextTheme, + 'Ranchers': GoogleFonts.ranchersTextTheme, + 'Rancho': GoogleFonts.ranchoTextTheme, + 'Ranga': GoogleFonts.rangaTextTheme, + 'Rasa': GoogleFonts.rasaTextTheme, + 'Rationale': GoogleFonts.rationaleTextTheme, + 'Ravi Prakash': GoogleFonts.raviPrakashTextTheme, + 'Recursive': GoogleFonts.recursiveTextTheme, + 'Red Hat Display': GoogleFonts.redHatDisplayTextTheme, + 'Red Hat Text': GoogleFonts.redHatTextTextTheme, + 'Red Rose': GoogleFonts.redRoseTextTheme, + 'Redressed': GoogleFonts.redressedTextTheme, + 'Reem Kufi': GoogleFonts.reemKufiTextTheme, + 'Reenie Beanie': GoogleFonts.reenieBeanieTextTheme, + 'Revalia': GoogleFonts.revaliaTextTheme, + 'Rhodium Libre': GoogleFonts.rhodiumLibreTextTheme, + 'Ribeye': GoogleFonts.ribeyeTextTheme, + 'Ribeye Marrow': GoogleFonts.ribeyeMarrowTextTheme, + 'Righteous': GoogleFonts.righteousTextTheme, + 'Risque': GoogleFonts.risqueTextTheme, + 'Roboto': GoogleFonts.robotoTextTheme, + 'Roboto Condensed': GoogleFonts.robotoCondensedTextTheme, + 'Roboto Mono': GoogleFonts.robotoMonoTextTheme, + 'Roboto Slab': GoogleFonts.robotoSlabTextTheme, + 'Rochester': GoogleFonts.rochesterTextTheme, + 'Rock Salt': GoogleFonts.rockSaltTextTheme, + 'Rokkitt': GoogleFonts.rokkittTextTheme, + 'Romanesco': GoogleFonts.romanescoTextTheme, + 'Ropa Sans': GoogleFonts.ropaSansTextTheme, + 'Rosario': GoogleFonts.rosarioTextTheme, + 'Rosarivo': GoogleFonts.rosarivoTextTheme, + 'Rouge Script': GoogleFonts.rougeScriptTextTheme, + 'Rowdies': GoogleFonts.rowdiesTextTheme, + 'Rozha One': GoogleFonts.rozhaOneTextTheme, + 'Rubik': GoogleFonts.rubikTextTheme, + 'Rubik Mono One': GoogleFonts.rubikMonoOneTextTheme, + 'Ruda': GoogleFonts.rudaTextTheme, + 'Rufina': GoogleFonts.rufinaTextTheme, + 'Ruge Boogie': GoogleFonts.rugeBoogieTextTheme, + 'Ruluko': GoogleFonts.rulukoTextTheme, + 'Rum Raisin': GoogleFonts.rumRaisinTextTheme, + 'Ruslan Display': GoogleFonts.ruslanDisplayTextTheme, + 'Russo One': GoogleFonts.russoOneTextTheme, + 'Ruthie': GoogleFonts.ruthieTextTheme, + 'Rye': GoogleFonts.ryeTextTheme, + 'Sacramento': GoogleFonts.sacramentoTextTheme, + 'Sahitya': GoogleFonts.sahityaTextTheme, + 'Sail': GoogleFonts.sailTextTheme, + 'Saira': GoogleFonts.sairaTextTheme, + 'Saira Condensed': GoogleFonts.sairaCondensedTextTheme, + 'Saira Extra Condensed': GoogleFonts.sairaExtraCondensedTextTheme, + 'Saira Semi Condensed': GoogleFonts.sairaSemiCondensedTextTheme, + 'Saira Stencil One': GoogleFonts.sairaStencilOneTextTheme, + 'Salsa': GoogleFonts.salsaTextTheme, + 'Sanchez': GoogleFonts.sanchezTextTheme, + 'Sancreek': GoogleFonts.sancreekTextTheme, + 'Sansita': GoogleFonts.sansitaTextTheme, + 'Sansita Swashed': GoogleFonts.sansitaSwashedTextTheme, + 'Sarabun': GoogleFonts.sarabunTextTheme, + 'Sarala': GoogleFonts.saralaTextTheme, + 'Sarina': GoogleFonts.sarinaTextTheme, + 'Sarpanch': GoogleFonts.sarpanchTextTheme, + 'Satisfy': GoogleFonts.satisfyTextTheme, + 'Sawarabi Gothic': GoogleFonts.sawarabiGothicTextTheme, + 'Sawarabi Mincho': GoogleFonts.sawarabiMinchoTextTheme, + 'Scada': GoogleFonts.scadaTextTheme, + 'Scheherazade': GoogleFonts.scheherazadeTextTheme, + 'Schoolbell': GoogleFonts.schoolbellTextTheme, + 'Scope One': GoogleFonts.scopeOneTextTheme, + 'Seaweed Script': GoogleFonts.seaweedScriptTextTheme, + 'Secular One': GoogleFonts.secularOneTextTheme, + 'Sedgwick Ave': GoogleFonts.sedgwickAveTextTheme, + 'Sedgwick Ave Display': GoogleFonts.sedgwickAveDisplayTextTheme, + 'Sen': GoogleFonts.senTextTheme, + 'Sevillana': GoogleFonts.sevillanaTextTheme, + 'Seymour One': GoogleFonts.seymourOneTextTheme, + 'Shadows Into Light': GoogleFonts.shadowsIntoLightTextTheme, + 'Shadows Into Light Two': GoogleFonts.shadowsIntoLightTwoTextTheme, + 'Shanti': GoogleFonts.shantiTextTheme, + 'Share': GoogleFonts.shareTextTheme, + 'Share Tech': GoogleFonts.shareTechTextTheme, + 'Share Tech Mono': GoogleFonts.shareTechMonoTextTheme, + 'Shojumaru': GoogleFonts.shojumaruTextTheme, + 'Short Stack': GoogleFonts.shortStackTextTheme, + 'Shrikhand': GoogleFonts.shrikhandTextTheme, + 'Sigmar One': GoogleFonts.sigmarOneTextTheme, + 'Signika': GoogleFonts.signikaTextTheme, + 'Signika Negative': GoogleFonts.signikaNegativeTextTheme, + 'Simonetta': GoogleFonts.simonettaTextTheme, + 'Single Day': GoogleFonts.singleDayTextTheme, + 'Sintony': GoogleFonts.sintonyTextTheme, + 'Sirin Stencil': GoogleFonts.sirinStencilTextTheme, + 'Six Caps': GoogleFonts.sixCapsTextTheme, + 'Skranji': GoogleFonts.skranjiTextTheme, + 'Slabo 13px': GoogleFonts.slabo13pxTextTheme, + 'Slabo 27px': GoogleFonts.slabo27pxTextTheme, + 'Slackey': GoogleFonts.slackeyTextTheme, + 'Smokum': GoogleFonts.smokumTextTheme, + 'Smythe': GoogleFonts.smytheTextTheme, + 'Sniglet': GoogleFonts.snigletTextTheme, + 'Snippet': GoogleFonts.snippetTextTheme, + 'Snowburst One': GoogleFonts.snowburstOneTextTheme, + 'Sofadi One': GoogleFonts.sofadiOneTextTheme, + 'Sofia': GoogleFonts.sofiaTextTheme, + 'Solway': GoogleFonts.solwayTextTheme, + 'Song Myung': GoogleFonts.songMyungTextTheme, + 'Sonsie One': GoogleFonts.sonsieOneTextTheme, + 'Sora': GoogleFonts.soraTextTheme, + 'Sorts Mill Goudy': GoogleFonts.sortsMillGoudyTextTheme, + 'Source Code Pro': GoogleFonts.sourceCodeProTextTheme, + 'Source Sans Pro': GoogleFonts.sourceSansProTextTheme, + 'Source Serif Pro': GoogleFonts.sourceSerifProTextTheme, + 'Space Grotesk': GoogleFonts.spaceGroteskTextTheme, + 'Space Mono': GoogleFonts.spaceMonoTextTheme, + 'Spartan': GoogleFonts.spartanTextTheme, + 'Special Elite': GoogleFonts.specialEliteTextTheme, + 'Spectral': GoogleFonts.spectralTextTheme, + 'Spectral SC': GoogleFonts.spectralScTextTheme, + 'Spicy Rice': GoogleFonts.spicyRiceTextTheme, + 'Spinnaker': GoogleFonts.spinnakerTextTheme, + 'Spirax': GoogleFonts.spiraxTextTheme, + 'Squada One': GoogleFonts.squadaOneTextTheme, + 'Sree Krushnadevaraya': GoogleFonts.sreeKrushnadevarayaTextTheme, + 'Sriracha': GoogleFonts.srirachaTextTheme, + 'Srisakdi': GoogleFonts.srisakdiTextTheme, + 'Staatliches': GoogleFonts.staatlichesTextTheme, + 'Stalemate': GoogleFonts.stalemateTextTheme, + 'Stalinist One': GoogleFonts.stalinistOneTextTheme, + 'Stardos Stencil': GoogleFonts.stardosStencilTextTheme, + 'Stint Ultra Condensed': GoogleFonts.stintUltraCondensedTextTheme, + 'Stint Ultra Expanded': GoogleFonts.stintUltraExpandedTextTheme, + 'Stoke': GoogleFonts.stokeTextTheme, + 'Strait': GoogleFonts.straitTextTheme, + 'Stylish': GoogleFonts.stylishTextTheme, + 'Sue Ellen Francisco': GoogleFonts.sueEllenFranciscoTextTheme, + 'Suez One': GoogleFonts.suezOneTextTheme, + 'Sulphur Point': GoogleFonts.sulphurPointTextTheme, + 'Sumana': GoogleFonts.sumanaTextTheme, + 'Sunflower': GoogleFonts.sunflowerTextTheme, + 'Sunshiney': GoogleFonts.sunshineyTextTheme, + 'Supermercado One': GoogleFonts.supermercadoOneTextTheme, + 'Sura': GoogleFonts.suraTextTheme, + 'Suranna': GoogleFonts.surannaTextTheme, + 'Suravaram': GoogleFonts.suravaramTextTheme, + 'Swanky and Moo Moo': GoogleFonts.swankyAndMooMooTextTheme, + 'Syncopate': GoogleFonts.syncopateTextTheme, + 'Syne': GoogleFonts.syneTextTheme, + 'Syne Mono': GoogleFonts.syneMonoTextTheme, + 'Syne Tactile': GoogleFonts.syneTactileTextTheme, + 'Tajawal': GoogleFonts.tajawalTextTheme, + 'Tangerine': GoogleFonts.tangerineTextTheme, + 'Tauri': GoogleFonts.tauriTextTheme, + 'Taviraj': GoogleFonts.tavirajTextTheme, + 'Teko': GoogleFonts.tekoTextTheme, + 'Telex': GoogleFonts.telexTextTheme, + 'Tenali Ramakrishna': GoogleFonts.tenaliRamakrishnaTextTheme, + 'Tenor Sans': GoogleFonts.tenorSansTextTheme, + 'Text Me One': GoogleFonts.textMeOneTextTheme, + 'Thasadith': GoogleFonts.thasadithTextTheme, + 'The Girl Next Door': GoogleFonts.theGirlNextDoorTextTheme, + 'Tienne': GoogleFonts.tienneTextTheme, + 'Tillana': GoogleFonts.tillanaTextTheme, + 'Timmana': GoogleFonts.timmanaTextTheme, + 'Tinos': GoogleFonts.tinosTextTheme, + 'Titan One': GoogleFonts.titanOneTextTheme, + 'Titillium Web': GoogleFonts.titilliumWebTextTheme, + 'Tomorrow': GoogleFonts.tomorrowTextTheme, + 'Trade Winds': GoogleFonts.tradeWindsTextTheme, + 'Trirong': GoogleFonts.trirongTextTheme, + 'Trispace': GoogleFonts.trispaceTextTheme, + 'Trocchi': GoogleFonts.trocchiTextTheme, + 'Trochut': GoogleFonts.trochutTextTheme, + 'Trykker': GoogleFonts.trykkerTextTheme, + 'Tulpen One': GoogleFonts.tulpenOneTextTheme, + 'Turret Road': GoogleFonts.turretRoadTextTheme, + 'Ubuntu': GoogleFonts.ubuntuTextTheme, + 'Ubuntu Condensed': GoogleFonts.ubuntuCondensedTextTheme, + 'Ubuntu Mono': GoogleFonts.ubuntuMonoTextTheme, + 'Ultra': GoogleFonts.ultraTextTheme, + 'Uncial Antiqua': GoogleFonts.uncialAntiquaTextTheme, + 'Underdog': GoogleFonts.underdogTextTheme, + 'Unica One': GoogleFonts.unicaOneTextTheme, + 'UnifrakturCook': GoogleFonts.unifrakturCookTextTheme, + 'UnifrakturMaguntia': GoogleFonts.unifrakturMaguntiaTextTheme, + 'Unkempt': GoogleFonts.unkemptTextTheme, + 'Unlock': GoogleFonts.unlockTextTheme, + 'Unna': GoogleFonts.unnaTextTheme, + 'VT323': GoogleFonts.vt323TextTheme, + 'Vampiro One': GoogleFonts.vampiroOneTextTheme, + 'Varela': GoogleFonts.varelaTextTheme, + 'Varela Round': GoogleFonts.varelaRoundTextTheme, + 'Varta': GoogleFonts.vartaTextTheme, + 'Vast Shadow': GoogleFonts.vastShadowTextTheme, + 'Vesper Libre': GoogleFonts.vesperLibreTextTheme, + 'Viaoda Libre': GoogleFonts.viaodaLibreTextTheme, + 'Vibes': GoogleFonts.vibesTextTheme, + 'Vibur': GoogleFonts.viburTextTheme, + 'Vidaloka': GoogleFonts.vidalokaTextTheme, + 'Viga': GoogleFonts.vigaTextTheme, + 'Voces': GoogleFonts.vocesTextTheme, + 'Volkhov': GoogleFonts.volkhovTextTheme, + 'Vollkorn': GoogleFonts.vollkornTextTheme, + 'Vollkorn SC': GoogleFonts.vollkornScTextTheme, + 'Voltaire': GoogleFonts.voltaireTextTheme, + 'Waiting for the Sunrise': GoogleFonts.waitingForTheSunriseTextTheme, + 'Wallpoet': GoogleFonts.wallpoetTextTheme, + 'Walter Turncoat': GoogleFonts.walterTurncoatTextTheme, + 'Warnes': GoogleFonts.warnesTextTheme, + 'Wellfleet': GoogleFonts.wellfleetTextTheme, + 'Wendy One': GoogleFonts.wendyOneTextTheme, + 'Wire One': GoogleFonts.wireOneTextTheme, + 'Work Sans': GoogleFonts.workSansTextTheme, + 'Xanh Mono': GoogleFonts.xanhMonoTextTheme, + 'Yanone Kaffeesatz': GoogleFonts.yanoneKaffeesatzTextTheme, + 'Yantramanav': GoogleFonts.yantramanavTextTheme, + 'Yatra One': GoogleFonts.yatraOneTextTheme, + 'Yellowtail': GoogleFonts.yellowtailTextTheme, + 'Yeon Sung': GoogleFonts.yeonSungTextTheme, + 'Yeseva One': GoogleFonts.yesevaOneTextTheme, + 'Yesteryear': GoogleFonts.yesteryearTextTheme, + 'Yrsa': GoogleFonts.yrsaTextTheme, + 'Yusei Magic': GoogleFonts.yuseiMagicTextTheme, + 'ZCOOL KuaiLe': GoogleFonts.zcoolKuaiLeTextTheme, + 'ZCOOL QingKe HuangYou': GoogleFonts.zcoolQingKeHuangYouTextTheme, + 'ZCOOL XiaoWei': GoogleFonts.zcoolXiaoWeiTextTheme, + 'Zeyada': GoogleFonts.zeyadaTextTheme, + 'Zhi Mang Xing': GoogleFonts.zhiMangXingTextTheme, + 'Zilla Slab': GoogleFonts.zillaSlabTextTheme, + 'Zilla Slab Highlight': GoogleFonts.zillaSlabHighlightTextTheme, + }; + + /// Retrieve a font by family name. + /// + /// Applies the given font family from Google Fonts to the given [textStyle] + /// and returns the resulting [TextStyle]. + /// + /// Note: [fontFamily] is case-sensitive. + /// + /// Parameter [fontFamily] must not be `null`. Throws if no font by name + /// [fontFamily] exists. + static TextStyle getFont( + String fontFamily, { + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = GoogleFonts.asMap(); + if (!fonts.containsKey(fontFamily)) { + throw Exception("No font family by name '$fontFamily' was found."); + } + return fonts[fontFamily]!( + textStyle: textStyle, + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + ); + } + + /// Retrieve a text theme by its font family name. + /// + /// Applies the given font family from Google Fonts to the given [textTheme] + /// and returns the resulting [textTheme]. + /// + /// Note: [fontFamily] is case-sensitive. + /// + /// Parameter [fontFamily] must not be `null`. Throws if no font by name + /// [fontFamily] exists. + static TextTheme getTextTheme(String fontFamily, [TextTheme? textTheme]) { + final fonts = _asMapOfTextThemes(); + if (!fonts.containsKey(fontFamily)) { + throw Exception("No font family by name '$fontFamily' was found."); + } + return fonts[fontFamily]!(textTheme); + } + + /// Applies the ABeeZee font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/ABeeZee + static TextStyle aBeeZee({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2ff99dd1bd594806e1b9f7423a75f1c1dfbbbcddb2698b3ab91f5709b1b90caf', + 29632, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8654a417521bf7fa4ffd1a7f7b62648648c5415ff0f7e0d53474e4436d049b7a', + 30984, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ABeeZee', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the ABeeZee font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/ABeeZee + static TextTheme aBeeZeeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.aBeeZee(textStyle: textTheme.headline1), + headline2: GoogleFonts.aBeeZee(textStyle: textTheme.headline2), + headline3: GoogleFonts.aBeeZee(textStyle: textTheme.headline3), + headline4: GoogleFonts.aBeeZee(textStyle: textTheme.headline4), + headline5: GoogleFonts.aBeeZee(textStyle: textTheme.headline5), + headline6: GoogleFonts.aBeeZee(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.aBeeZee(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.aBeeZee(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.aBeeZee(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.aBeeZee(textStyle: textTheme.bodyText2), + caption: GoogleFonts.aBeeZee(textStyle: textTheme.caption), + button: GoogleFonts.aBeeZee(textStyle: textTheme.button), + overline: GoogleFonts.aBeeZee(textStyle: textTheme.overline), + ); + } + + /// Applies the Abel font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Abel + static TextStyle abel({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '37a44f872ce09b8a93244abfaf3741aa8e4da7cbf64de118635a7cf1c7bc1d5e', + 34924, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Abel', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Abel font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Abel + static TextTheme abelTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.abel(textStyle: textTheme.headline1), + headline2: GoogleFonts.abel(textStyle: textTheme.headline2), + headline3: GoogleFonts.abel(textStyle: textTheme.headline3), + headline4: GoogleFonts.abel(textStyle: textTheme.headline4), + headline5: GoogleFonts.abel(textStyle: textTheme.headline5), + headline6: GoogleFonts.abel(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.abel(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.abel(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.abel(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.abel(textStyle: textTheme.bodyText2), + caption: GoogleFonts.abel(textStyle: textTheme.caption), + button: GoogleFonts.abel(textStyle: textTheme.button), + overline: GoogleFonts.abel(textStyle: textTheme.overline), + ); + } + + /// Applies the Abhaya Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Abhaya+Libre + static TextStyle abhayaLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f8e1a260e8a56f8cdb2e2401be9e3a6903026becbf134336b9c8f6b2e2490cd5', + 282252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ff52a780878fd838b81f8c96e548f49d7bbd4f92cb0a3dc68eb3f852ca3f3fd4', + 282512, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e3be63e1c52229673f453da3c6abd79dc0011d02fd57da38489880434556aa77', + 281648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1c7bdb109ab0e98ef91a41ec55825dcb97c2ea2e9274c67dde899104f5b59878', + 281252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9457be94f81fc73b59af3e850d0dcb91790d60078cbdc252da50881c615173aa', + 280484, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AbhayaLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Abhaya Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Abhaya+Libre + static TextTheme abhayaLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.abhayaLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.abhayaLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.abhayaLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.abhayaLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.abhayaLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.abhayaLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.abhayaLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.abhayaLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.abhayaLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.abhayaLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.abhayaLibre(textStyle: textTheme.caption), + button: GoogleFonts.abhayaLibre(textStyle: textTheme.button), + overline: GoogleFonts.abhayaLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Abril Fatface font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Abril+Fatface + static TextStyle abrilFatface({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2baf7b134013a2183457312f0d26115640d0171829d024dfb1466616a3ac789a', + 67316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AbrilFatface', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Abril Fatface font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Abril+Fatface + static TextTheme abrilFatfaceTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.abrilFatface(textStyle: textTheme.headline1), + headline2: GoogleFonts.abrilFatface(textStyle: textTheme.headline2), + headline3: GoogleFonts.abrilFatface(textStyle: textTheme.headline3), + headline4: GoogleFonts.abrilFatface(textStyle: textTheme.headline4), + headline5: GoogleFonts.abrilFatface(textStyle: textTheme.headline5), + headline6: GoogleFonts.abrilFatface(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.abrilFatface(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.abrilFatface(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.abrilFatface(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.abrilFatface(textStyle: textTheme.bodyText2), + caption: GoogleFonts.abrilFatface(textStyle: textTheme.caption), + button: GoogleFonts.abrilFatface(textStyle: textTheme.button), + overline: GoogleFonts.abrilFatface(textStyle: textTheme.overline), + ); + } + + /// Applies the Aclonica font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aclonica + static TextStyle aclonica({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e26afc4582406a86fc1e1b81aad6e16a03f9276419fa76e91b98f9e42d868cc8', + 68136, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Aclonica', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Aclonica font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aclonica + static TextTheme aclonicaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.aclonica(textStyle: textTheme.headline1), + headline2: GoogleFonts.aclonica(textStyle: textTheme.headline2), + headline3: GoogleFonts.aclonica(textStyle: textTheme.headline3), + headline4: GoogleFonts.aclonica(textStyle: textTheme.headline4), + headline5: GoogleFonts.aclonica(textStyle: textTheme.headline5), + headline6: GoogleFonts.aclonica(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.aclonica(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.aclonica(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.aclonica(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.aclonica(textStyle: textTheme.bodyText2), + caption: GoogleFonts.aclonica(textStyle: textTheme.caption), + button: GoogleFonts.aclonica(textStyle: textTheme.button), + overline: GoogleFonts.aclonica(textStyle: textTheme.overline), + ); + } + + /// Applies the Acme font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Acme + static TextStyle acme({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f7d0b4054bd37012deca722e47899589c1d35302b51b2fd21ea83e7f3410bccd', + 23028, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Acme', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Acme font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Acme + static TextTheme acmeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.acme(textStyle: textTheme.headline1), + headline2: GoogleFonts.acme(textStyle: textTheme.headline2), + headline3: GoogleFonts.acme(textStyle: textTheme.headline3), + headline4: GoogleFonts.acme(textStyle: textTheme.headline4), + headline5: GoogleFonts.acme(textStyle: textTheme.headline5), + headline6: GoogleFonts.acme(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.acme(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.acme(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.acme(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.acme(textStyle: textTheme.bodyText2), + caption: GoogleFonts.acme(textStyle: textTheme.caption), + button: GoogleFonts.acme(textStyle: textTheme.button), + overline: GoogleFonts.acme(textStyle: textTheme.overline), + ); + } + + /// Applies the Actor font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Actor + static TextStyle actor({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '417b785d001974cb097e1f84b068ed6f47fa9c5317bf90801a55709954b59350', + 42356, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Actor', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Actor font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Actor + static TextTheme actorTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.actor(textStyle: textTheme.headline1), + headline2: GoogleFonts.actor(textStyle: textTheme.headline2), + headline3: GoogleFonts.actor(textStyle: textTheme.headline3), + headline4: GoogleFonts.actor(textStyle: textTheme.headline4), + headline5: GoogleFonts.actor(textStyle: textTheme.headline5), + headline6: GoogleFonts.actor(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.actor(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.actor(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.actor(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.actor(textStyle: textTheme.bodyText2), + caption: GoogleFonts.actor(textStyle: textTheme.caption), + button: GoogleFonts.actor(textStyle: textTheme.button), + overline: GoogleFonts.actor(textStyle: textTheme.overline), + ); + } + + /// Applies the Adamina font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Adamina + static TextStyle adamina({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c241502ff8869d44e310b4e1782d5ca6f53b2d1844593bb0a360e12af0ddfcb1', + 76672, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Adamina', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Adamina font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Adamina + static TextTheme adaminaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.adamina(textStyle: textTheme.headline1), + headline2: GoogleFonts.adamina(textStyle: textTheme.headline2), + headline3: GoogleFonts.adamina(textStyle: textTheme.headline3), + headline4: GoogleFonts.adamina(textStyle: textTheme.headline4), + headline5: GoogleFonts.adamina(textStyle: textTheme.headline5), + headline6: GoogleFonts.adamina(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.adamina(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.adamina(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.adamina(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.adamina(textStyle: textTheme.bodyText2), + caption: GoogleFonts.adamina(textStyle: textTheme.caption), + button: GoogleFonts.adamina(textStyle: textTheme.button), + overline: GoogleFonts.adamina(textStyle: textTheme.overline), + ); + } + + /// Applies the Advent Pro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Advent+Pro + static TextStyle adventPro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4041ce69b488624d0653057137ff69ead9c9496be2059ede6a5056fd48780850', + 46400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '20f54f798dd883fc2fab8294006f8201f1deed59b0abd0ad6c6864bb0062eb47', + 46424, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '23462d311ba53dbeac614ad5c99742d75264652538c2aaaea50fa3f9a37c1111', + 46356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c7084224aa15f7d31683e67bc3107aa12f725f4d20a10e9b65bbcec912162191', + 46836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '21feddd6602a8e2daf17501cb32c4b27a26b6a357f3652ad357008c8a90f1646', + 51004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '908b9b388605933b6e469878f17c52da7e2cd9cd6c4ec72a3e12aa5a9c3b9b79', + 50772, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '962b3ce8591b2ca225b23e65b3914233c576d21700e3f24c6b820230fe8424e0', + 55976, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AdventPro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Advent Pro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Advent+Pro + static TextTheme adventProTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.adventPro(textStyle: textTheme.headline1), + headline2: GoogleFonts.adventPro(textStyle: textTheme.headline2), + headline3: GoogleFonts.adventPro(textStyle: textTheme.headline3), + headline4: GoogleFonts.adventPro(textStyle: textTheme.headline4), + headline5: GoogleFonts.adventPro(textStyle: textTheme.headline5), + headline6: GoogleFonts.adventPro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.adventPro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.adventPro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.adventPro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.adventPro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.adventPro(textStyle: textTheme.caption), + button: GoogleFonts.adventPro(textStyle: textTheme.button), + overline: GoogleFonts.adventPro(textStyle: textTheme.overline), + ); + } + + /// Applies the Aguafina Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aguafina+Script + static TextStyle aguafinaScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '282b677fa945b70a3a5a57b8ffb8064638a07feb77edc68cf29591225bc7b5ce', + 47180, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AguafinaScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Aguafina Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aguafina+Script + static TextTheme aguafinaScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.aguafinaScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.aguafinaScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.aguafinaScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.aguafinaScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.aguafinaScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.aguafinaScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.aguafinaScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.aguafinaScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.aguafinaScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.aguafinaScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.aguafinaScript(textStyle: textTheme.caption), + button: GoogleFonts.aguafinaScript(textStyle: textTheme.button), + overline: GoogleFonts.aguafinaScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Akronim font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Akronim + static TextStyle akronim({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bb077a1601fc7353abf83d6f7e667b5c1ff47a853f2a90f466be1dd738f4e6a1', + 107340, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Akronim', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Akronim font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Akronim + static TextTheme akronimTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.akronim(textStyle: textTheme.headline1), + headline2: GoogleFonts.akronim(textStyle: textTheme.headline2), + headline3: GoogleFonts.akronim(textStyle: textTheme.headline3), + headline4: GoogleFonts.akronim(textStyle: textTheme.headline4), + headline5: GoogleFonts.akronim(textStyle: textTheme.headline5), + headline6: GoogleFonts.akronim(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.akronim(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.akronim(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.akronim(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.akronim(textStyle: textTheme.bodyText2), + caption: GoogleFonts.akronim(textStyle: textTheme.caption), + button: GoogleFonts.akronim(textStyle: textTheme.button), + overline: GoogleFonts.akronim(textStyle: textTheme.overline), + ); + } + + /// Applies the Aladin font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aladin + static TextStyle aladin({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '47e6aa68e0a6686d85005a8cd4e3c3055dc4828dc3b49d69fdf88f38491c8ae2', + 42112, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Aladin', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Aladin font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aladin + static TextTheme aladinTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.aladin(textStyle: textTheme.headline1), + headline2: GoogleFonts.aladin(textStyle: textTheme.headline2), + headline3: GoogleFonts.aladin(textStyle: textTheme.headline3), + headline4: GoogleFonts.aladin(textStyle: textTheme.headline4), + headline5: GoogleFonts.aladin(textStyle: textTheme.headline5), + headline6: GoogleFonts.aladin(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.aladin(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.aladin(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.aladin(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.aladin(textStyle: textTheme.bodyText2), + caption: GoogleFonts.aladin(textStyle: textTheme.caption), + button: GoogleFonts.aladin(textStyle: textTheme.button), + overline: GoogleFonts.aladin(textStyle: textTheme.overline), + ); + } + + /// Applies the Alata font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alata + static TextStyle alata({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0e69926cd849e08f0dfa58fa809a89d58262ec6a29e3dd4e2c59ea279301b12e', + 63264, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Alata', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alata font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alata + static TextTheme alataTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alata(textStyle: textTheme.headline1), + headline2: GoogleFonts.alata(textStyle: textTheme.headline2), + headline3: GoogleFonts.alata(textStyle: textTheme.headline3), + headline4: GoogleFonts.alata(textStyle: textTheme.headline4), + headline5: GoogleFonts.alata(textStyle: textTheme.headline5), + headline6: GoogleFonts.alata(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alata(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alata(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alata(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alata(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alata(textStyle: textTheme.caption), + button: GoogleFonts.alata(textStyle: textTheme.button), + overline: GoogleFonts.alata(textStyle: textTheme.overline), + ); + } + + /// Applies the Alatsi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alatsi + static TextStyle alatsi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7fa5a16b3bfdf1423bfccb98349fc2cee90ca48e42252467b9a36f5a3149622e', + 70056, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Alatsi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alatsi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alatsi + static TextTheme alatsiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alatsi(textStyle: textTheme.headline1), + headline2: GoogleFonts.alatsi(textStyle: textTheme.headline2), + headline3: GoogleFonts.alatsi(textStyle: textTheme.headline3), + headline4: GoogleFonts.alatsi(textStyle: textTheme.headline4), + headline5: GoogleFonts.alatsi(textStyle: textTheme.headline5), + headline6: GoogleFonts.alatsi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alatsi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alatsi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alatsi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alatsi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alatsi(textStyle: textTheme.caption), + button: GoogleFonts.alatsi(textStyle: textTheme.button), + overline: GoogleFonts.alatsi(textStyle: textTheme.overline), + ); + } + + /// Applies the Aldrich font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aldrich + static TextStyle aldrich({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e288c81eacbaee70be6e11a25f4fb3bdaffcc0ea0449f285c94fc558e64335f4', + 27932, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Aldrich', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Aldrich font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aldrich + static TextTheme aldrichTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.aldrich(textStyle: textTheme.headline1), + headline2: GoogleFonts.aldrich(textStyle: textTheme.headline2), + headline3: GoogleFonts.aldrich(textStyle: textTheme.headline3), + headline4: GoogleFonts.aldrich(textStyle: textTheme.headline4), + headline5: GoogleFonts.aldrich(textStyle: textTheme.headline5), + headline6: GoogleFonts.aldrich(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.aldrich(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.aldrich(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.aldrich(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.aldrich(textStyle: textTheme.bodyText2), + caption: GoogleFonts.aldrich(textStyle: textTheme.caption), + button: GoogleFonts.aldrich(textStyle: textTheme.button), + overline: GoogleFonts.aldrich(textStyle: textTheme.overline), + ); + } + + /// Applies the Alef font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alef + static TextStyle alef({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a50dedb5215d98f65036893675ded42762d4c7bdae624c71adb1ea584f5a1467', + 58300, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'acbe7d381fcdbd3bca38351290cba306a1dde6549d74fbdef431ee9fcb60030d', + 59936, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Alef', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alef font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alef + static TextTheme alefTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alef(textStyle: textTheme.headline1), + headline2: GoogleFonts.alef(textStyle: textTheme.headline2), + headline3: GoogleFonts.alef(textStyle: textTheme.headline3), + headline4: GoogleFonts.alef(textStyle: textTheme.headline4), + headline5: GoogleFonts.alef(textStyle: textTheme.headline5), + headline6: GoogleFonts.alef(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alef(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alef(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alef(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alef(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alef(textStyle: textTheme.caption), + button: GoogleFonts.alef(textStyle: textTheme.button), + overline: GoogleFonts.alef(textStyle: textTheme.overline), + ); + } + + /// Applies the Alegreya font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alegreya + static TextStyle alegreya({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '530d78cba23c5d8e261ae9447b431e1fa550f9dc6563540a0c400be3f7ee88ab', + 63708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'efba5f9b4495a2e911ec871cc4dfebb5dba60bc72d643c0dd346e8f90513f81a', + 61596, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c00ad52d215d793be827a98a0661e13bbd3276c96c6aa5e6c8d71c9487a3da03', + 67268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bd912b8f7b092f81fc94ee9f3b769e57ecbb1a2443bfce7d405d2ad0c48c04b4', + 65700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f2d4a4c114f8e7ad762e764046f117bf954b1ba7797bbe6b6d754decc9bdbf99', + 62328, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '01804c5bcb6aedbda393491d82c14328987c7fb66a6ef8c8313aed5d683d3dad', + 60620, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Alegreya', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alegreya font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alegreya + static TextTheme alegreyaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alegreya(textStyle: textTheme.headline1), + headline2: GoogleFonts.alegreya(textStyle: textTheme.headline2), + headline3: GoogleFonts.alegreya(textStyle: textTheme.headline3), + headline4: GoogleFonts.alegreya(textStyle: textTheme.headline4), + headline5: GoogleFonts.alegreya(textStyle: textTheme.headline5), + headline6: GoogleFonts.alegreya(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alegreya(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alegreya(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alegreya(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alegreya(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alegreya(textStyle: textTheme.caption), + button: GoogleFonts.alegreya(textStyle: textTheme.button), + overline: GoogleFonts.alegreya(textStyle: textTheme.overline), + ); + } + + /// Applies the Alegreya SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alegreya+SC + static TextStyle alegreyaSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7449fd0507a0808ae452506eb8fb2fb46b4abe72f8f5d982b25c963ba93bc094', + 72748, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6b36a9c6614f3cea8c2846f74b6823f8d3c5edd8a8b2319eccae142e3bb42738', + 73048, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '16e159f79c1929fa884f232e47d45cb0cc16a55a22b127359024868245f4a2d4', + 71836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6920f9042274d5d0b37753d233b86c7066a47d1cb94015d70ecbb9a76359faa7', + 72428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd591a36a0d78f0315b16c23983d84d6d8b4bbf8ea5b5879019cad423941d5990', + 70500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd312d023b86792b3a0f7cd9594498720cdb9feb7bec946d75a3f25f6580c19c7', + 71700, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AlegreyaSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alegreya SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alegreya+SC + static TextTheme alegreyaScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alegreyaSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.alegreyaSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.alegreyaSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.alegreyaSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.alegreyaSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.alegreyaSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alegreyaSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alegreyaSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alegreyaSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alegreyaSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alegreyaSc(textStyle: textTheme.caption), + button: GoogleFonts.alegreyaSc(textStyle: textTheme.button), + overline: GoogleFonts.alegreyaSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Alegreya Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alegreya+Sans + static TextStyle alegreyaSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4e4fc2370a575c44ada0a88565af306c9e5f6f863cd3e594f68fbecb64d6eb45', + 86800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dfad029fd95bc8e1e6f4aff5ca9a40f7ee01b7c42436068b1a609af1036de968', + 75952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f413bb7452d6c3127865026e765917685dde894f8130417ee32c5c22d3332a5a', + 88928, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '53c675ca8ca26437bfdef9475e6be6a31d8f390904f2a25dc7f71ecacf749525', + 76244, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5186af372dbc9306a0390c6a53c2b3ed7e398bf7e19390e4115779d9d4dcb9e0', + 90044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a1cf80b2ffea7f7a74c290c886e0853612aa20f2f2942a11b6221973a8b1125a', + 75740, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b54080b02a55195adec0aed32ecb384095ddfef221504059e15682a59709d9a5', + 90304, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '16b83ef0510db5d9b7adeb15a6bf505975df75012e3f04118c8384165bae4c4f', + 75644, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'baf6cfdcdaeaff8ae1997ba5a87f7c43b4823b8e094097eb354fdaeb531c610e', + 90308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c3ea4ab25245b87d94c68e797ee68e472bf893023027f57d0dfb6aef204e650d', + 75464, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2313ece3a1be01342c2f2b902904ce864b05c9ecf3a72e96580c84ed124b370c', + 90492, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '296f24dc4713815e4ea5f25a60e938c00c6d94678ba90f140c4c4dcd5d3dae42', + 75552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c1ae94a74aa4998c1ed777107095512b795dd19783a838e9eaffca2382405bf3', + 90324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '63fa7d406f209d33ac9020dc3209f61bda016b2e851b369e2475f6c77bd65111', + 75748, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AlegreyaSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alegreya Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alegreya+Sans + static TextTheme alegreyaSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alegreyaSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.alegreyaSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.alegreyaSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.alegreyaSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.alegreyaSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.alegreyaSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alegreyaSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alegreyaSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alegreyaSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alegreyaSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alegreyaSans(textStyle: textTheme.caption), + button: GoogleFonts.alegreyaSans(textStyle: textTheme.button), + overline: GoogleFonts.alegreyaSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Alegreya Sans SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alegreya+Sans+SC + static TextStyle alegreyaSansSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7f5b4f9e7531121c2163e92598f24222cdef538a04352553731f0c81f69c4227', + 77260, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1a8c6b334dbb0663e1b509d268363d557f9d231f702c2fb6ffe0727c0bb374b5', + 67308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0d94b7e8e30244280988269fbefbf776d08ff9ad0be6df4f620a6a5b7e0362f0', + 79488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ccd17db40859ba985ad048cea705168d600d36d89c00086787c0e0c4b3d82350', + 67492, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2487f405a054a83c784021b2c8e860860b9243fb34fc64b7a5fd2250d68bf4f9', + 80884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b427017865c854fea91f74c2c65b73010299f090c4ce77e0854fac9a1de8bc0a', + 67168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'edb603dab26042252c435e746201e0f2f353dd09865130082f25072fb0969e0b', + 81296, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'de77ecc3bedb1b421aebae8d44d23fc290cb7f252c8cd7eea6cc478ee69e13ec', + 67248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c46b10c450739d774b11b6e3d2f51e421d416b9a8174d249ad85973c5018894c', + 81476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '16e2233f43d03898a785024de868496150dfcba5754cec33d4e349b92c857453', + 67060, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '356b90a20e5818313f51f03a05985f5c63745944a01aa92b78804caa0b7a4268', + 81900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '85eb333661be027f374e08a28cc4b0c394fa0052fc64197c5a96409168532e87', + 67216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '41a1bac96732155ce8415a0155d80de58383ab4223de540ad68c383f51b3cb5e', + 81560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7100fdd6d991e596021a3bc2578fd4eb74fb5bd5d7dfc6c30dcde981e6a27281', + 67304, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AlegreyaSansSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alegreya Sans SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alegreya+Sans+SC + static TextTheme alegreyaSansScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alegreyaSansSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.alegreyaSansSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.alegreyaSansSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.alegreyaSansSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.alegreyaSansSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.alegreyaSansSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alegreyaSansSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alegreyaSansSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alegreyaSansSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alegreyaSansSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alegreyaSansSc(textStyle: textTheme.caption), + button: GoogleFonts.alegreyaSansSc(textStyle: textTheme.button), + overline: GoogleFonts.alegreyaSansSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Aleo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aleo + static TextStyle aleo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8844034f7614859b836238cb530853c190b011335edbfc9fd9dbb15669134bcb', + 35800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9d41d1b8e554c18ef31b39cd96576f58048ab1dacd1e03dd349c3f471917ab43', + 45124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4124c4a19546d618079ccad928418735907b0eff5c68a0faf16b8fd3ec1d5bc2', + 65892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7662bf685a6bddd2908c8392229aac54817f3666c9915cec596880a13eef66c9', + 68788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd20df7d3bc69a847115b4c7f6de4db4d8aa878a8ad3ccc70a83b9beb9d29826c', + 60744, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0277e97f9c04c3812b3987b151b56953251d09574f7f649b461074b2439a4026', + 64516, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Aleo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Aleo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aleo + static TextTheme aleoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.aleo(textStyle: textTheme.headline1), + headline2: GoogleFonts.aleo(textStyle: textTheme.headline2), + headline3: GoogleFonts.aleo(textStyle: textTheme.headline3), + headline4: GoogleFonts.aleo(textStyle: textTheme.headline4), + headline5: GoogleFonts.aleo(textStyle: textTheme.headline5), + headline6: GoogleFonts.aleo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.aleo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.aleo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.aleo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.aleo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.aleo(textStyle: textTheme.caption), + button: GoogleFonts.aleo(textStyle: textTheme.button), + overline: GoogleFonts.aleo(textStyle: textTheme.overline), + ); + } + + /// Applies the Alex Brush font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alex+Brush + static TextStyle alexBrush({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eb8044f112b9878ec59f0825d91a9f011fc4925ce2272737c02ce2be161c3efd', + 48660, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AlexBrush', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alex Brush font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alex+Brush + static TextTheme alexBrushTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alexBrush(textStyle: textTheme.headline1), + headline2: GoogleFonts.alexBrush(textStyle: textTheme.headline2), + headline3: GoogleFonts.alexBrush(textStyle: textTheme.headline3), + headline4: GoogleFonts.alexBrush(textStyle: textTheme.headline4), + headline5: GoogleFonts.alexBrush(textStyle: textTheme.headline5), + headline6: GoogleFonts.alexBrush(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alexBrush(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alexBrush(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alexBrush(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alexBrush(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alexBrush(textStyle: textTheme.caption), + button: GoogleFonts.alexBrush(textStyle: textTheme.button), + overline: GoogleFonts.alexBrush(textStyle: textTheme.overline), + ); + } + + /// Applies the Alfa Slab One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alfa+Slab+One + static TextStyle alfaSlabOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7da478a94cb0f5cdf81dc70a08204fc3d9b097463f65a9108151851580dd9151', + 64824, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AlfaSlabOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alfa Slab One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alfa+Slab+One + static TextTheme alfaSlabOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alfaSlabOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.alfaSlabOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.alfaSlabOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.alfaSlabOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.alfaSlabOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.alfaSlabOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alfaSlabOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alfaSlabOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alfaSlabOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alfaSlabOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alfaSlabOne(textStyle: textTheme.caption), + button: GoogleFonts.alfaSlabOne(textStyle: textTheme.button), + overline: GoogleFonts.alfaSlabOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Alice font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alice + static TextStyle alice({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b09d7119f6ceba6b3b798683927d8bd51757498f4af762dc4509d1c76aafc6a3', + 95148, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Alice', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alice font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alice + static TextTheme aliceTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alice(textStyle: textTheme.headline1), + headline2: GoogleFonts.alice(textStyle: textTheme.headline2), + headline3: GoogleFonts.alice(textStyle: textTheme.headline3), + headline4: GoogleFonts.alice(textStyle: textTheme.headline4), + headline5: GoogleFonts.alice(textStyle: textTheme.headline5), + headline6: GoogleFonts.alice(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alice(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alice(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alice(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alice(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alice(textStyle: textTheme.caption), + button: GoogleFonts.alice(textStyle: textTheme.button), + overline: GoogleFonts.alice(textStyle: textTheme.overline), + ); + } + + /// Applies the Alike font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alike + static TextStyle alike({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b9683edf916072397bd15b9b312ff78533f85b4ac5598b5867733fb5670ed534', + 64584, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Alike', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alike font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alike + static TextTheme alikeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alike(textStyle: textTheme.headline1), + headline2: GoogleFonts.alike(textStyle: textTheme.headline2), + headline3: GoogleFonts.alike(textStyle: textTheme.headline3), + headline4: GoogleFonts.alike(textStyle: textTheme.headline4), + headline5: GoogleFonts.alike(textStyle: textTheme.headline5), + headline6: GoogleFonts.alike(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alike(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alike(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alike(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alike(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alike(textStyle: textTheme.caption), + button: GoogleFonts.alike(textStyle: textTheme.button), + overline: GoogleFonts.alike(textStyle: textTheme.overline), + ); + } + + /// Applies the Alike Angular font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alike+Angular + static TextStyle alikeAngular({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0ae146a31a48840c579bbeefc31597a7c9b385c626ef8387ad461aeea8432452', + 97120, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AlikeAngular', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Alike Angular font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Alike+Angular + static TextTheme alikeAngularTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.alikeAngular(textStyle: textTheme.headline1), + headline2: GoogleFonts.alikeAngular(textStyle: textTheme.headline2), + headline3: GoogleFonts.alikeAngular(textStyle: textTheme.headline3), + headline4: GoogleFonts.alikeAngular(textStyle: textTheme.headline4), + headline5: GoogleFonts.alikeAngular(textStyle: textTheme.headline5), + headline6: GoogleFonts.alikeAngular(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.alikeAngular(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.alikeAngular(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.alikeAngular(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.alikeAngular(textStyle: textTheme.bodyText2), + caption: GoogleFonts.alikeAngular(textStyle: textTheme.caption), + button: GoogleFonts.alikeAngular(textStyle: textTheme.button), + overline: GoogleFonts.alikeAngular(textStyle: textTheme.overline), + ); + } + + /// Applies the Allan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Allan + static TextStyle allan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '83a268d06857cada4246725e7cc04eb4d7b87d19e6d4f44e745d33be739852fb', + 40992, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b309341937b6f2a1893638c71f9877c70c658e6461e5b18011f9ab7f2782adc9', + 95644, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Allan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Allan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Allan + static TextTheme allanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.allan(textStyle: textTheme.headline1), + headline2: GoogleFonts.allan(textStyle: textTheme.headline2), + headline3: GoogleFonts.allan(textStyle: textTheme.headline3), + headline4: GoogleFonts.allan(textStyle: textTheme.headline4), + headline5: GoogleFonts.allan(textStyle: textTheme.headline5), + headline6: GoogleFonts.allan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.allan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.allan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.allan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.allan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.allan(textStyle: textTheme.caption), + button: GoogleFonts.allan(textStyle: textTheme.button), + overline: GoogleFonts.allan(textStyle: textTheme.overline), + ); + } + + /// Applies the Allerta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Allerta + static TextStyle allerta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'df4ce73d43a2a1eb976d66944a0555b8ab45b8848b9e9be9355d0f68a9373270', + 18844, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Allerta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Allerta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Allerta + static TextTheme allertaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.allerta(textStyle: textTheme.headline1), + headline2: GoogleFonts.allerta(textStyle: textTheme.headline2), + headline3: GoogleFonts.allerta(textStyle: textTheme.headline3), + headline4: GoogleFonts.allerta(textStyle: textTheme.headline4), + headline5: GoogleFonts.allerta(textStyle: textTheme.headline5), + headline6: GoogleFonts.allerta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.allerta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.allerta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.allerta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.allerta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.allerta(textStyle: textTheme.caption), + button: GoogleFonts.allerta(textStyle: textTheme.button), + overline: GoogleFonts.allerta(textStyle: textTheme.overline), + ); + } + + /// Applies the Allerta Stencil font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Allerta+Stencil + static TextStyle allertaStencil({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd43b315a156fb147d0bcd2dad6a682e5a23d388f0d12365c29c2d46fbf1e2c96', + 19512, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AllertaStencil', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Allerta Stencil font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Allerta+Stencil + static TextTheme allertaStencilTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.allertaStencil(textStyle: textTheme.headline1), + headline2: GoogleFonts.allertaStencil(textStyle: textTheme.headline2), + headline3: GoogleFonts.allertaStencil(textStyle: textTheme.headline3), + headline4: GoogleFonts.allertaStencil(textStyle: textTheme.headline4), + headline5: GoogleFonts.allertaStencil(textStyle: textTheme.headline5), + headline6: GoogleFonts.allertaStencil(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.allertaStencil(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.allertaStencil(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.allertaStencil(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.allertaStencil(textStyle: textTheme.bodyText2), + caption: GoogleFonts.allertaStencil(textStyle: textTheme.caption), + button: GoogleFonts.allertaStencil(textStyle: textTheme.button), + overline: GoogleFonts.allertaStencil(textStyle: textTheme.overline), + ); + } + + /// Applies the Allura font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Allura + static TextStyle allura({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '32adf6de6bc3ee14bedf4674a1020492d2c2e4a939883aa672ff9a31777f63ed', + 88036, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Allura', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Allura font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Allura + static TextTheme alluraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.allura(textStyle: textTheme.headline1), + headline2: GoogleFonts.allura(textStyle: textTheme.headline2), + headline3: GoogleFonts.allura(textStyle: textTheme.headline3), + headline4: GoogleFonts.allura(textStyle: textTheme.headline4), + headline5: GoogleFonts.allura(textStyle: textTheme.headline5), + headline6: GoogleFonts.allura(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.allura(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.allura(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.allura(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.allura(textStyle: textTheme.bodyText2), + caption: GoogleFonts.allura(textStyle: textTheme.caption), + button: GoogleFonts.allura(textStyle: textTheme.button), + overline: GoogleFonts.allura(textStyle: textTheme.overline), + ); + } + + /// Applies the Almarai font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Almarai + static TextStyle almarai({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd65c40f0692b45d73302895b80e837f57f1b4e69a5d3255c3f186919eab23780', + 85828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1b22529a81e051312110ae38c450d9b4f5474030f2275dc4574f26c8fcf5318e', + 85912, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6cf3b7ecc9ac853f7071684fc5dfb22dd3a13f41901fee6aeb54cd9cc81d1126', + 85696, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '55d68f8e4adef1c44ed2dbc154537092c330112b9ac46a94338e58f08f02bcb6', + 86588, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Almarai', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Almarai font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Almarai + static TextTheme almaraiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.almarai(textStyle: textTheme.headline1), + headline2: GoogleFonts.almarai(textStyle: textTheme.headline2), + headline3: GoogleFonts.almarai(textStyle: textTheme.headline3), + headline4: GoogleFonts.almarai(textStyle: textTheme.headline4), + headline5: GoogleFonts.almarai(textStyle: textTheme.headline5), + headline6: GoogleFonts.almarai(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.almarai(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.almarai(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.almarai(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.almarai(textStyle: textTheme.bodyText2), + caption: GoogleFonts.almarai(textStyle: textTheme.caption), + button: GoogleFonts.almarai(textStyle: textTheme.button), + overline: GoogleFonts.almarai(textStyle: textTheme.overline), + ); + } + + /// Applies the Almendra font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Almendra + static TextStyle almendra({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '08fa6c15ee1bba267ec0f0f30bd11a5be545d922ebd057f450a702f87aa9aaa8', + 68696, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd40d53b865a76778b1362d4e74f6c6294fbde5ae31f24f0173d9401c3fabcddc', + 35276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b0792b18907bbbe9c24855a75a53fc8ac926ae12e181ec5bbc70fae19df05bfa', + 36684, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eb34d628f80f6ab95c12f0ef6dd4138d2182b94042d615028af5353e58b9f1ee', + 35448, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Almendra', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Almendra font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Almendra + static TextTheme almendraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.almendra(textStyle: textTheme.headline1), + headline2: GoogleFonts.almendra(textStyle: textTheme.headline2), + headline3: GoogleFonts.almendra(textStyle: textTheme.headline3), + headline4: GoogleFonts.almendra(textStyle: textTheme.headline4), + headline5: GoogleFonts.almendra(textStyle: textTheme.headline5), + headline6: GoogleFonts.almendra(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.almendra(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.almendra(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.almendra(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.almendra(textStyle: textTheme.bodyText2), + caption: GoogleFonts.almendra(textStyle: textTheme.caption), + button: GoogleFonts.almendra(textStyle: textTheme.button), + overline: GoogleFonts.almendra(textStyle: textTheme.overline), + ); + } + + /// Applies the Almendra Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Almendra+Display + static TextStyle almendraDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a8aa056bca4ab7efab868e9b7a435eea1109abde7b232725b1e1b41cf482191a', + 39284, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AlmendraDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Almendra Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Almendra+Display + static TextTheme almendraDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.almendraDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.almendraDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.almendraDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.almendraDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.almendraDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.almendraDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.almendraDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.almendraDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.almendraDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.almendraDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.almendraDisplay(textStyle: textTheme.caption), + button: GoogleFonts.almendraDisplay(textStyle: textTheme.button), + overline: GoogleFonts.almendraDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Almendra SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Almendra+SC + static TextStyle almendraSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '12f0d325f41e23a75aa0ddb706236e13487d31b43a77435817a684f239f324bd', + 36008, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AlmendraSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Almendra SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Almendra+SC + static TextTheme almendraScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.almendraSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.almendraSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.almendraSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.almendraSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.almendraSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.almendraSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.almendraSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.almendraSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.almendraSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.almendraSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.almendraSc(textStyle: textTheme.caption), + button: GoogleFonts.almendraSc(textStyle: textTheme.button), + overline: GoogleFonts.almendraSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Amarante font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amarante + static TextStyle amarante({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f11a52c1a0f3e94f81dde8d9c60832c688c1d9b01c5bb1098c3ea30daac8ad29', + 74348, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Amarante', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Amarante font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amarante + static TextTheme amaranteTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.amarante(textStyle: textTheme.headline1), + headline2: GoogleFonts.amarante(textStyle: textTheme.headline2), + headline3: GoogleFonts.amarante(textStyle: textTheme.headline3), + headline4: GoogleFonts.amarante(textStyle: textTheme.headline4), + headline5: GoogleFonts.amarante(textStyle: textTheme.headline5), + headline6: GoogleFonts.amarante(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.amarante(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.amarante(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.amarante(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.amarante(textStyle: textTheme.bodyText2), + caption: GoogleFonts.amarante(textStyle: textTheme.caption), + button: GoogleFonts.amarante(textStyle: textTheme.button), + overline: GoogleFonts.amarante(textStyle: textTheme.overline), + ); + } + + /// Applies the Amaranth font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amaranth + static TextStyle amaranth({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4b8c69a7d5f0b230b1b010da8da3ad4ccb84f4dff4a1247a14af83392c9ecf64', + 66272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '359639014bf096771cbebb373f2d347f8e1b44a2ef2b48556e1a21289dbc7eb5', + 74196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9b35625ebc301f471cd70df7575f4fc81597a8ab27dc321418707c40d8a99616', + 65892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '48c74968a6ddedd92d0c4d4e05959d24a1ae124fce3ab60c793c5a331dddee10', + 74616, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Amaranth', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Amaranth font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amaranth + static TextTheme amaranthTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.amaranth(textStyle: textTheme.headline1), + headline2: GoogleFonts.amaranth(textStyle: textTheme.headline2), + headline3: GoogleFonts.amaranth(textStyle: textTheme.headline3), + headline4: GoogleFonts.amaranth(textStyle: textTheme.headline4), + headline5: GoogleFonts.amaranth(textStyle: textTheme.headline5), + headline6: GoogleFonts.amaranth(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.amaranth(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.amaranth(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.amaranth(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.amaranth(textStyle: textTheme.bodyText2), + caption: GoogleFonts.amaranth(textStyle: textTheme.caption), + button: GoogleFonts.amaranth(textStyle: textTheme.button), + overline: GoogleFonts.amaranth(textStyle: textTheme.overline), + ); + } + + /// Applies the Amatic SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amatic+SC + static TextStyle amaticSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9da6405b57357f309f00592371cf54bb3c1d57b8e7d9fc40fff6f364d6ca80fe', + 104904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '81f4df2ecbc8d2fcae65290f5075ff98149f4f95ea00bb6bf3a0711e4e1afd75', + 99680, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AmaticSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Amatic SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amatic+SC + static TextTheme amaticScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.amaticSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.amaticSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.amaticSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.amaticSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.amaticSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.amaticSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.amaticSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.amaticSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.amaticSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.amaticSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.amaticSc(textStyle: textTheme.caption), + button: GoogleFonts.amaticSc(textStyle: textTheme.button), + overline: GoogleFonts.amaticSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Amatica SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amatica+SC + static TextStyle amaticaSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '39a7e41edc371bdb0e8356c4e9f69ea62594cfd412fbb1f5c45a32c0a5e75516', + 140932, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ead630d51d6f70a5e14a17fec1bffc04c9a13118b217101fd42eac20be2ae66', + 105524, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AmaticaSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Amatica SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amatica+SC + static TextTheme amaticaScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.amaticaSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.amaticaSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.amaticaSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.amaticaSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.amaticaSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.amaticaSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.amaticaSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.amaticaSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.amaticaSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.amaticaSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.amaticaSc(textStyle: textTheme.caption), + button: GoogleFonts.amaticaSc(textStyle: textTheme.button), + overline: GoogleFonts.amaticaSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Amethysta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amethysta + static TextStyle amethysta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e4d26711903ae08c3bd10750f3b713928bdd3ee56d00372e37bd8606a3fe2d7a', + 36864, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Amethysta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Amethysta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amethysta + static TextTheme amethystaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.amethysta(textStyle: textTheme.headline1), + headline2: GoogleFonts.amethysta(textStyle: textTheme.headline2), + headline3: GoogleFonts.amethysta(textStyle: textTheme.headline3), + headline4: GoogleFonts.amethysta(textStyle: textTheme.headline4), + headline5: GoogleFonts.amethysta(textStyle: textTheme.headline5), + headline6: GoogleFonts.amethysta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.amethysta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.amethysta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.amethysta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.amethysta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.amethysta(textStyle: textTheme.caption), + button: GoogleFonts.amethysta(textStyle: textTheme.button), + overline: GoogleFonts.amethysta(textStyle: textTheme.overline), + ); + } + + /// Applies the Amiko font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amiko + static TextStyle amiko({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c2e782cc6b503328a87e3b81b3ee6afa1acb6cd66bd04d9da2ba5d3ff4c43e3f', + 143076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd56799efb6c3d56b106cae38c558a3f2f9da3d0a90d0d1ea64449c693d3cadfc', + 142664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '037bbdff86b70266d62abc94be043671d3c04188f477dbb0ead70ee89df98ecb', + 142052, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Amiko', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Amiko font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amiko + static TextTheme amikoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.amiko(textStyle: textTheme.headline1), + headline2: GoogleFonts.amiko(textStyle: textTheme.headline2), + headline3: GoogleFonts.amiko(textStyle: textTheme.headline3), + headline4: GoogleFonts.amiko(textStyle: textTheme.headline4), + headline5: GoogleFonts.amiko(textStyle: textTheme.headline5), + headline6: GoogleFonts.amiko(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.amiko(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.amiko(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.amiko(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.amiko(textStyle: textTheme.bodyText2), + caption: GoogleFonts.amiko(textStyle: textTheme.caption), + button: GoogleFonts.amiko(textStyle: textTheme.button), + overline: GoogleFonts.amiko(textStyle: textTheme.overline), + ); + } + + /// Applies the Amiri font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amiri + static TextStyle amiri({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '15af380107efd8a082b372d1ba8027d5fd6d4720ccf7f7ce48345b845cfb83b6', + 370496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '03496500b8efdd151ca91912b003f23e04fcb45a8d39cee588e4ea47b61fc052', + 357340, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a1f6fcfa01fc6084132c66ff5b8da7b655fbf82dae7a9200c4471400281678bb', + 351752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9d9add54ab339fd5ca1f0b2fbda1117e04758800cefa39fa72d5f1e38b7a2e27', + 355324, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Amiri', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Amiri font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amiri + static TextTheme amiriTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.amiri(textStyle: textTheme.headline1), + headline2: GoogleFonts.amiri(textStyle: textTheme.headline2), + headline3: GoogleFonts.amiri(textStyle: textTheme.headline3), + headline4: GoogleFonts.amiri(textStyle: textTheme.headline4), + headline5: GoogleFonts.amiri(textStyle: textTheme.headline5), + headline6: GoogleFonts.amiri(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.amiri(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.amiri(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.amiri(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.amiri(textStyle: textTheme.bodyText2), + caption: GoogleFonts.amiri(textStyle: textTheme.caption), + button: GoogleFonts.amiri(textStyle: textTheme.button), + overline: GoogleFonts.amiri(textStyle: textTheme.overline), + ); + } + + /// Applies the Amita font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amita + static TextStyle amita({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f8ab328073e1c729f0b4f38521b47bb39c63db396da1602f6b08a2a8775249f4', + 141504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e421cec126c6014995b96189e28c3c8b119e3e21dbe1c3dea8585ec31afa0679', + 141464, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Amita', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Amita font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Amita + static TextTheme amitaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.amita(textStyle: textTheme.headline1), + headline2: GoogleFonts.amita(textStyle: textTheme.headline2), + headline3: GoogleFonts.amita(textStyle: textTheme.headline3), + headline4: GoogleFonts.amita(textStyle: textTheme.headline4), + headline5: GoogleFonts.amita(textStyle: textTheme.headline5), + headline6: GoogleFonts.amita(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.amita(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.amita(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.amita(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.amita(textStyle: textTheme.bodyText2), + caption: GoogleFonts.amita(textStyle: textTheme.caption), + button: GoogleFonts.amita(textStyle: textTheme.button), + overline: GoogleFonts.amita(textStyle: textTheme.overline), + ); + } + + /// Applies the Anaheim font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Anaheim + static TextStyle anaheim({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '738fa7ae0283744abbfcfd999eb71d255210a7ee0fa7e195a47482269b9e381e', + 27848, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Anaheim', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Anaheim font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Anaheim + static TextTheme anaheimTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.anaheim(textStyle: textTheme.headline1), + headline2: GoogleFonts.anaheim(textStyle: textTheme.headline2), + headline3: GoogleFonts.anaheim(textStyle: textTheme.headline3), + headline4: GoogleFonts.anaheim(textStyle: textTheme.headline4), + headline5: GoogleFonts.anaheim(textStyle: textTheme.headline5), + headline6: GoogleFonts.anaheim(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.anaheim(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.anaheim(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.anaheim(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.anaheim(textStyle: textTheme.bodyText2), + caption: GoogleFonts.anaheim(textStyle: textTheme.caption), + button: GoogleFonts.anaheim(textStyle: textTheme.button), + overline: GoogleFonts.anaheim(textStyle: textTheme.overline), + ); + } + + /// Applies the Andada font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Andada + static TextStyle andada({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7c3fda3cdd2dcc60f34129cdd9c0a2f139b2a4bec16bcff6b27521d87d222f1e', + 108572, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Andada', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Andada font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Andada + static TextTheme andadaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.andada(textStyle: textTheme.headline1), + headline2: GoogleFonts.andada(textStyle: textTheme.headline2), + headline3: GoogleFonts.andada(textStyle: textTheme.headline3), + headline4: GoogleFonts.andada(textStyle: textTheme.headline4), + headline5: GoogleFonts.andada(textStyle: textTheme.headline5), + headline6: GoogleFonts.andada(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.andada(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.andada(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.andada(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.andada(textStyle: textTheme.bodyText2), + caption: GoogleFonts.andada(textStyle: textTheme.caption), + button: GoogleFonts.andada(textStyle: textTheme.button), + overline: GoogleFonts.andada(textStyle: textTheme.overline), + ); + } + + /// Applies the Andika font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Andika + static TextStyle andika({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1c10763224ab91314d3fae862634f6bddf0aae60bd71668d68950102ca77b5d4', + 964524, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Andika', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Andika font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Andika + static TextTheme andikaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.andika(textStyle: textTheme.headline1), + headline2: GoogleFonts.andika(textStyle: textTheme.headline2), + headline3: GoogleFonts.andika(textStyle: textTheme.headline3), + headline4: GoogleFonts.andika(textStyle: textTheme.headline4), + headline5: GoogleFonts.andika(textStyle: textTheme.headline5), + headline6: GoogleFonts.andika(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.andika(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.andika(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.andika(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.andika(textStyle: textTheme.bodyText2), + caption: GoogleFonts.andika(textStyle: textTheme.caption), + button: GoogleFonts.andika(textStyle: textTheme.button), + overline: GoogleFonts.andika(textStyle: textTheme.overline), + ); + } + + /// Applies the Andika New Basic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Andika+New+Basic + static TextStyle andikaNewBasic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '48b18f488f9907c784ac7924a2d763257e1057f5ac3ee22c804ab0ba194253fb', + 71420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '65eed85f74c45790107ec98d6a3098e99d4f54a7580b53d536891a35385b16ba', + 75508, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '50bbb54d0ec04a720a330e87931ea2be85d5fc406fd2e171ce44ca67855f8a8d', + 72220, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a2a105533f2063ef7f4a489f1d438cf7af064f1c5ed1c3ebc6ba7c1d46c8db40', + 76148, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AndikaNewBasic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Andika New Basic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Andika+New+Basic + static TextTheme andikaNewBasicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.andikaNewBasic(textStyle: textTheme.headline1), + headline2: GoogleFonts.andikaNewBasic(textStyle: textTheme.headline2), + headline3: GoogleFonts.andikaNewBasic(textStyle: textTheme.headline3), + headline4: GoogleFonts.andikaNewBasic(textStyle: textTheme.headline4), + headline5: GoogleFonts.andikaNewBasic(textStyle: textTheme.headline5), + headline6: GoogleFonts.andikaNewBasic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.andikaNewBasic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.andikaNewBasic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.andikaNewBasic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.andikaNewBasic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.andikaNewBasic(textStyle: textTheme.caption), + button: GoogleFonts.andikaNewBasic(textStyle: textTheme.button), + overline: GoogleFonts.andikaNewBasic(textStyle: textTheme.overline), + ); + } + + /// Applies the Annie Use Your Telescope font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Annie+Use+Your+Telescope + static TextStyle annieUseYourTelescope({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '65c0cd06d1ec2528de45688966f2971cf95fed9f810f246e08b4efd9e717d850', + 50692, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AnnieUseYourTelescope', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Annie Use Your Telescope font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Annie+Use+Your+Telescope + static TextTheme annieUseYourTelescopeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.headline1), + headline2: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.headline2), + headline3: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.headline3), + headline4: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.headline4), + headline5: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.headline5), + headline6: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.bodyText2), + caption: GoogleFonts.annieUseYourTelescope(textStyle: textTheme.caption), + button: GoogleFonts.annieUseYourTelescope(textStyle: textTheme.button), + overline: + GoogleFonts.annieUseYourTelescope(textStyle: textTheme.overline), + ); + } + + /// Applies the Anonymous Pro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Anonymous+Pro + static TextStyle anonymousPro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ca7beef0b5eb5c9e72533cd45bc1e4f41c8272dc2335f22d3649e32a795995f', + 106796, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '71ce3ee6476a91f9e89e9f8010d9ea13314306b645af3e8d7b7add697e6f0d3e', + 108996, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd00937283f3b530bee6700e02cfabfbb96b833d42559d48fc5fdfcfde2ff5b39', + 106604, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '60f1f3cae99bbc1323cdcdf9af6a0127d5b4684ef675e6836fa3034a297dc16a', + 108760, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AnonymousPro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Anonymous Pro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Anonymous+Pro + static TextTheme anonymousProTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.anonymousPro(textStyle: textTheme.headline1), + headline2: GoogleFonts.anonymousPro(textStyle: textTheme.headline2), + headline3: GoogleFonts.anonymousPro(textStyle: textTheme.headline3), + headline4: GoogleFonts.anonymousPro(textStyle: textTheme.headline4), + headline5: GoogleFonts.anonymousPro(textStyle: textTheme.headline5), + headline6: GoogleFonts.anonymousPro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.anonymousPro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.anonymousPro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.anonymousPro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.anonymousPro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.anonymousPro(textStyle: textTheme.caption), + button: GoogleFonts.anonymousPro(textStyle: textTheme.button), + overline: GoogleFonts.anonymousPro(textStyle: textTheme.overline), + ); + } + + /// Applies the Antic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Antic + static TextStyle antic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6526fff8a94a5503810bc8805b716126e91295380d0e970f089e3e663a4440d5', + 39272, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Antic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Antic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Antic + static TextTheme anticTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.antic(textStyle: textTheme.headline1), + headline2: GoogleFonts.antic(textStyle: textTheme.headline2), + headline3: GoogleFonts.antic(textStyle: textTheme.headline3), + headline4: GoogleFonts.antic(textStyle: textTheme.headline4), + headline5: GoogleFonts.antic(textStyle: textTheme.headline5), + headline6: GoogleFonts.antic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.antic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.antic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.antic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.antic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.antic(textStyle: textTheme.caption), + button: GoogleFonts.antic(textStyle: textTheme.button), + overline: GoogleFonts.antic(textStyle: textTheme.overline), + ); + } + + /// Applies the Antic Didone font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Antic+Didone + static TextStyle anticDidone({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ed8ca32ea2c34cc27f4a10cdf51c0ddb35d0cd580df90b19e68d8096a145ec35', + 39640, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AnticDidone', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Antic Didone font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Antic+Didone + static TextTheme anticDidoneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.anticDidone(textStyle: textTheme.headline1), + headline2: GoogleFonts.anticDidone(textStyle: textTheme.headline2), + headline3: GoogleFonts.anticDidone(textStyle: textTheme.headline3), + headline4: GoogleFonts.anticDidone(textStyle: textTheme.headline4), + headline5: GoogleFonts.anticDidone(textStyle: textTheme.headline5), + headline6: GoogleFonts.anticDidone(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.anticDidone(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.anticDidone(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.anticDidone(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.anticDidone(textStyle: textTheme.bodyText2), + caption: GoogleFonts.anticDidone(textStyle: textTheme.caption), + button: GoogleFonts.anticDidone(textStyle: textTheme.button), + overline: GoogleFonts.anticDidone(textStyle: textTheme.overline), + ); + } + + /// Applies the Antic Slab font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Antic+Slab + static TextStyle anticSlab({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1348202760ad87d67e74d3a921ad2be20b563b2cd2a8d6e99d54da029c7f2aad', + 36924, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AnticSlab', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Antic Slab font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Antic+Slab + static TextTheme anticSlabTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.anticSlab(textStyle: textTheme.headline1), + headline2: GoogleFonts.anticSlab(textStyle: textTheme.headline2), + headline3: GoogleFonts.anticSlab(textStyle: textTheme.headline3), + headline4: GoogleFonts.anticSlab(textStyle: textTheme.headline4), + headline5: GoogleFonts.anticSlab(textStyle: textTheme.headline5), + headline6: GoogleFonts.anticSlab(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.anticSlab(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.anticSlab(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.anticSlab(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.anticSlab(textStyle: textTheme.bodyText2), + caption: GoogleFonts.anticSlab(textStyle: textTheme.caption), + button: GoogleFonts.anticSlab(textStyle: textTheme.button), + overline: GoogleFonts.anticSlab(textStyle: textTheme.overline), + ); + } + + /// Applies the Anton font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Anton + static TextStyle anton({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e0d29150a430129b0bfdaabaa46ba1e7967ccabc46440a5789bffe18b7dfcc2d', + 54896, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Anton', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Anton font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Anton + static TextTheme antonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.anton(textStyle: textTheme.headline1), + headline2: GoogleFonts.anton(textStyle: textTheme.headline2), + headline3: GoogleFonts.anton(textStyle: textTheme.headline3), + headline4: GoogleFonts.anton(textStyle: textTheme.headline4), + headline5: GoogleFonts.anton(textStyle: textTheme.headline5), + headline6: GoogleFonts.anton(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.anton(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.anton(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.anton(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.anton(textStyle: textTheme.bodyText2), + caption: GoogleFonts.anton(textStyle: textTheme.caption), + button: GoogleFonts.anton(textStyle: textTheme.button), + overline: GoogleFonts.anton(textStyle: textTheme.overline), + ); + } + + /// Applies the Arapey font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arapey + static TextStyle arapey({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8d4786e233fac8fe0069ba6efaa828eb2fffef7b1d21a92a6d4f250ae9710415', + 26716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '10f469eeecd1cca95a1881d5fbd920abff25911a343caf957f7b2a0e3d4de390', + 29520, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Arapey', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arapey font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arapey + static TextTheme arapeyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arapey(textStyle: textTheme.headline1), + headline2: GoogleFonts.arapey(textStyle: textTheme.headline2), + headline3: GoogleFonts.arapey(textStyle: textTheme.headline3), + headline4: GoogleFonts.arapey(textStyle: textTheme.headline4), + headline5: GoogleFonts.arapey(textStyle: textTheme.headline5), + headline6: GoogleFonts.arapey(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arapey(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arapey(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arapey(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arapey(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arapey(textStyle: textTheme.caption), + button: GoogleFonts.arapey(textStyle: textTheme.button), + overline: GoogleFonts.arapey(textStyle: textTheme.overline), + ); + } + + /// Applies the Arbutus font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arbutus + static TextStyle arbutus({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd1484fe1dd2948c05f4d1ab7f6acbbc88d4acea2e32880263ec8f991cba4905f', + 81792, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Arbutus', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arbutus font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arbutus + static TextTheme arbutusTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arbutus(textStyle: textTheme.headline1), + headline2: GoogleFonts.arbutus(textStyle: textTheme.headline2), + headline3: GoogleFonts.arbutus(textStyle: textTheme.headline3), + headline4: GoogleFonts.arbutus(textStyle: textTheme.headline4), + headline5: GoogleFonts.arbutus(textStyle: textTheme.headline5), + headline6: GoogleFonts.arbutus(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arbutus(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arbutus(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arbutus(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arbutus(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arbutus(textStyle: textTheme.caption), + button: GoogleFonts.arbutus(textStyle: textTheme.button), + overline: GoogleFonts.arbutus(textStyle: textTheme.overline), + ); + } + + /// Applies the Arbutus Slab font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arbutus+Slab + static TextStyle arbutusSlab({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7c7bbc09f84fc70a8541195a960de7d282eeaee64c5b146253bd79fd209893d', + 39812, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ArbutusSlab', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arbutus Slab font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arbutus+Slab + static TextTheme arbutusSlabTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arbutusSlab(textStyle: textTheme.headline1), + headline2: GoogleFonts.arbutusSlab(textStyle: textTheme.headline2), + headline3: GoogleFonts.arbutusSlab(textStyle: textTheme.headline3), + headline4: GoogleFonts.arbutusSlab(textStyle: textTheme.headline4), + headline5: GoogleFonts.arbutusSlab(textStyle: textTheme.headline5), + headline6: GoogleFonts.arbutusSlab(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arbutusSlab(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arbutusSlab(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arbutusSlab(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arbutusSlab(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arbutusSlab(textStyle: textTheme.caption), + button: GoogleFonts.arbutusSlab(textStyle: textTheme.button), + overline: GoogleFonts.arbutusSlab(textStyle: textTheme.overline), + ); + } + + /// Applies the Architects Daughter font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Architects+Daughter + static TextStyle architectsDaughter({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a4f5860f4b7aca9b95305b6c5a3b14e2f1c951eaddd28b5d1fffd374171ccdba', + 43356, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ArchitectsDaughter', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Architects Daughter font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Architects+Daughter + static TextTheme architectsDaughterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.architectsDaughter(textStyle: textTheme.headline1), + headline2: GoogleFonts.architectsDaughter(textStyle: textTheme.headline2), + headline3: GoogleFonts.architectsDaughter(textStyle: textTheme.headline3), + headline4: GoogleFonts.architectsDaughter(textStyle: textTheme.headline4), + headline5: GoogleFonts.architectsDaughter(textStyle: textTheme.headline5), + headline6: GoogleFonts.architectsDaughter(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.architectsDaughter(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.architectsDaughter(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.architectsDaughter(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.architectsDaughter(textStyle: textTheme.bodyText2), + caption: GoogleFonts.architectsDaughter(textStyle: textTheme.caption), + button: GoogleFonts.architectsDaughter(textStyle: textTheme.button), + overline: GoogleFonts.architectsDaughter(textStyle: textTheme.overline), + ); + } + + /// Applies the Archivo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Archivo + static TextStyle archivo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e3992a886b3891c9b073cf3e46b1c578cb31ab065cf9b5e07f6fc2a0200a495f', + 58160, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8af059c64838f116e4c8afda7a5c344815c3fe3c2111749d7281a046087dfb8a', + 60944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '455a61b80b447af7647cb7bbbef6de06c3c3031d0ecbb2619fa9cffa73871e76', + 59648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c266aeada4adba34caec3d404c7953743cf0327123506b66cde56cf556ad2ddf', + 62104, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7ad030ef4465b1be7229c5326d24955683bea533c9646e4ed2773cd30697d031', + 59960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '453878357ed380bea09e3661badd4636234be8794956428236bc3a166d84fc92', + 62300, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5c37a5634c5b7802983e322dcc187d5b4bc26e238dd61828a71f184592b9032f', + 59436, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '12b65a3c8f63eb390f4acb0a6ade0ac245782113ddc2e397c216c3605fc245f8', + 62036, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Archivo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Archivo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Archivo + static TextTheme archivoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.archivo(textStyle: textTheme.headline1), + headline2: GoogleFonts.archivo(textStyle: textTheme.headline2), + headline3: GoogleFonts.archivo(textStyle: textTheme.headline3), + headline4: GoogleFonts.archivo(textStyle: textTheme.headline4), + headline5: GoogleFonts.archivo(textStyle: textTheme.headline5), + headline6: GoogleFonts.archivo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.archivo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.archivo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.archivo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.archivo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.archivo(textStyle: textTheme.caption), + button: GoogleFonts.archivo(textStyle: textTheme.button), + overline: GoogleFonts.archivo(textStyle: textTheme.overline), + ); + } + + /// Applies the Archivo Black font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Archivo+Black + static TextStyle archivoBlack({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fdd008fdde6eaf026762810841b23a803c1fd8f7691df010d250df61e584703b', + 59204, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ArchivoBlack', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Archivo Black font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Archivo+Black + static TextTheme archivoBlackTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.archivoBlack(textStyle: textTheme.headline1), + headline2: GoogleFonts.archivoBlack(textStyle: textTheme.headline2), + headline3: GoogleFonts.archivoBlack(textStyle: textTheme.headline3), + headline4: GoogleFonts.archivoBlack(textStyle: textTheme.headline4), + headline5: GoogleFonts.archivoBlack(textStyle: textTheme.headline5), + headline6: GoogleFonts.archivoBlack(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.archivoBlack(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.archivoBlack(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.archivoBlack(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.archivoBlack(textStyle: textTheme.bodyText2), + caption: GoogleFonts.archivoBlack(textStyle: textTheme.caption), + button: GoogleFonts.archivoBlack(textStyle: textTheme.button), + overline: GoogleFonts.archivoBlack(textStyle: textTheme.overline), + ); + } + + /// Applies the Archivo Narrow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Archivo+Narrow + static TextStyle archivoNarrow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '95b4094186b9443c74e987b6a5ad660b55c7dc1e548d66cc53ead05a10bf096f', + 57132, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c5be034d89310f5e551f67507ef7bd0d5093e193d5e556598e1137cff7598ada', + 58796, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '898e57eec4db5685859996bc7c9a87707d53ceca97c917edb0497302b7145fd5', + 55924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ff034a0073d594043d35a5058bf44df331be4b22576c8a753b210bcc55789e50', + 59204, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ArchivoNarrow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Archivo Narrow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Archivo+Narrow + static TextTheme archivoNarrowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.archivoNarrow(textStyle: textTheme.headline1), + headline2: GoogleFonts.archivoNarrow(textStyle: textTheme.headline2), + headline3: GoogleFonts.archivoNarrow(textStyle: textTheme.headline3), + headline4: GoogleFonts.archivoNarrow(textStyle: textTheme.headline4), + headline5: GoogleFonts.archivoNarrow(textStyle: textTheme.headline5), + headline6: GoogleFonts.archivoNarrow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.archivoNarrow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.archivoNarrow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.archivoNarrow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.archivoNarrow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.archivoNarrow(textStyle: textTheme.caption), + button: GoogleFonts.archivoNarrow(textStyle: textTheme.button), + overline: GoogleFonts.archivoNarrow(textStyle: textTheme.overline), + ); + } + + /// Applies the Aref Ruqaa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aref+Ruqaa + static TextStyle arefRuqaa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '483d6ce42473c62a61b38dc4e30c6b1a5d9b02921ab5034c8eec4b8f0496127d', + 112872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ea198095e22fea5b0b08338b3b524a2ac489bd669154eab1927955f20124358', + 139992, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ArefRuqaa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Aref Ruqaa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aref+Ruqaa + static TextTheme arefRuqaaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arefRuqaa(textStyle: textTheme.headline1), + headline2: GoogleFonts.arefRuqaa(textStyle: textTheme.headline2), + headline3: GoogleFonts.arefRuqaa(textStyle: textTheme.headline3), + headline4: GoogleFonts.arefRuqaa(textStyle: textTheme.headline4), + headline5: GoogleFonts.arefRuqaa(textStyle: textTheme.headline5), + headline6: GoogleFonts.arefRuqaa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arefRuqaa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arefRuqaa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arefRuqaa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arefRuqaa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arefRuqaa(textStyle: textTheme.caption), + button: GoogleFonts.arefRuqaa(textStyle: textTheme.button), + overline: GoogleFonts.arefRuqaa(textStyle: textTheme.overline), + ); + } + + /// Applies the Arima Madurai font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arima+Madurai + static TextStyle arimaMadurai({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '20fe984789a290b9c540b82d788511cf37e7dcb0c94a3f808ed8a9980ce92262', + 92064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ea122a5616110be9d6b0719ff9a8e5d87a5bb067671e53f60e9e2f34151a054', + 92944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e9bb6dffdcb0e85ac571c284727a1ff484951f065ccff0e42668f232709bcfd0', + 93064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '72a8a5252b9293d6af843e90bdda0f995b86531cb25d7a2489b5b58e7c495575', + 93452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b608979162b4bce202e22f3cba5768ef3c5f96294c41e1d36229b02393a70cf7', + 93560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f9809fc1ba075315f2526aba738bb8c4bfb8af33451d402a57eae3edbdbe45b6', + 93480, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '030889c403dcab9b3a79394ed59d1d1da7d0dbafae26fc8c6d1b870d7732c997', + 93616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25561cbe875f9bad0c96c060f2a1f8108ba709366496e68ff510efdf5930429f', + 93604, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ArimaMadurai', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arima Madurai font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arima+Madurai + static TextTheme arimaMaduraiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arimaMadurai(textStyle: textTheme.headline1), + headline2: GoogleFonts.arimaMadurai(textStyle: textTheme.headline2), + headline3: GoogleFonts.arimaMadurai(textStyle: textTheme.headline3), + headline4: GoogleFonts.arimaMadurai(textStyle: textTheme.headline4), + headline5: GoogleFonts.arimaMadurai(textStyle: textTheme.headline5), + headline6: GoogleFonts.arimaMadurai(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arimaMadurai(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arimaMadurai(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arimaMadurai(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arimaMadurai(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arimaMadurai(textStyle: textTheme.caption), + button: GoogleFonts.arimaMadurai(textStyle: textTheme.button), + overline: GoogleFonts.arimaMadurai(textStyle: textTheme.overline), + ); + } + + /// Applies the Arimo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arimo + static TextStyle arimo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'df255da5c656bbf01f4aa3012b4d4ba16f7bd17664a4e1fc011146a4eb95d436', + 242708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eafe825bf96517b1ff3b8d8710254e225584de1489e4c3deaa6b1cb8549a027d', + 249396, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5a4f400fb6090e3938136ea6fd3ec2c02777fb674d13b9582f96d4515044df23', + 240652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e6b358f015564a1505c76b32db9b3f5c538a8f7d220dd04446697d286c820bf0', + 248528, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Arimo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arimo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arimo + static TextTheme arimoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arimo(textStyle: textTheme.headline1), + headline2: GoogleFonts.arimo(textStyle: textTheme.headline2), + headline3: GoogleFonts.arimo(textStyle: textTheme.headline3), + headline4: GoogleFonts.arimo(textStyle: textTheme.headline4), + headline5: GoogleFonts.arimo(textStyle: textTheme.headline5), + headline6: GoogleFonts.arimo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arimo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arimo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arimo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arimo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arimo(textStyle: textTheme.caption), + button: GoogleFonts.arimo(textStyle: textTheme.button), + overline: GoogleFonts.arimo(textStyle: textTheme.overline), + ); + } + + /// Applies the Arizonia font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arizonia + static TextStyle arizonia({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '603a1ae367969056ace1484bd5db4d882fabfa78008e6843d3ba07c08082c2c7', + 50688, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Arizonia', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arizonia font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arizonia + static TextTheme arizoniaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arizonia(textStyle: textTheme.headline1), + headline2: GoogleFonts.arizonia(textStyle: textTheme.headline2), + headline3: GoogleFonts.arizonia(textStyle: textTheme.headline3), + headline4: GoogleFonts.arizonia(textStyle: textTheme.headline4), + headline5: GoogleFonts.arizonia(textStyle: textTheme.headline5), + headline6: GoogleFonts.arizonia(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arizonia(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arizonia(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arizonia(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arizonia(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arizonia(textStyle: textTheme.caption), + button: GoogleFonts.arizonia(textStyle: textTheme.button), + overline: GoogleFonts.arizonia(textStyle: textTheme.overline), + ); + } + + /// Applies the Armata font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Armata + static TextStyle armata({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7631b4ae2fae472da8b9d0b46acfec928c9c550e82dbee1685e72f389ab890d9', + 54772, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Armata', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Armata font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Armata + static TextTheme armataTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.armata(textStyle: textTheme.headline1), + headline2: GoogleFonts.armata(textStyle: textTheme.headline2), + headline3: GoogleFonts.armata(textStyle: textTheme.headline3), + headline4: GoogleFonts.armata(textStyle: textTheme.headline4), + headline5: GoogleFonts.armata(textStyle: textTheme.headline5), + headline6: GoogleFonts.armata(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.armata(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.armata(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.armata(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.armata(textStyle: textTheme.bodyText2), + caption: GoogleFonts.armata(textStyle: textTheme.caption), + button: GoogleFonts.armata(textStyle: textTheme.button), + overline: GoogleFonts.armata(textStyle: textTheme.overline), + ); + } + + /// Applies the Arsenal font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arsenal + static TextStyle arsenal({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7b13a735c3c27289a74f4e934b380f078f89568b2633c5d8386e97a97d46158c', + 140064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f687cc6b9b17ac45aaf3391fbe649c2e1607804ce3ab85daddf9669f796d0a79', + 138944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0ac62eb1c6ee28d30c2dacea06acdbec9c72bcbfdca1f76a873b8a2c18ac8ae6', + 141180, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '41b9ba2384a037e4ec361896e5868107cfa8535ab8befda2d9666584884aca80', + 139236, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Arsenal', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arsenal font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arsenal + static TextTheme arsenalTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arsenal(textStyle: textTheme.headline1), + headline2: GoogleFonts.arsenal(textStyle: textTheme.headline2), + headline3: GoogleFonts.arsenal(textStyle: textTheme.headline3), + headline4: GoogleFonts.arsenal(textStyle: textTheme.headline4), + headline5: GoogleFonts.arsenal(textStyle: textTheme.headline5), + headline6: GoogleFonts.arsenal(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arsenal(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arsenal(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arsenal(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arsenal(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arsenal(textStyle: textTheme.caption), + button: GoogleFonts.arsenal(textStyle: textTheme.button), + overline: GoogleFonts.arsenal(textStyle: textTheme.overline), + ); + } + + /// Applies the Artifika font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Artifika + static TextStyle artifika({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a0d399a0a07f993bcb6bdd075a4e0f6ae155d222d230710b94d48933e8470dbf', + 100216, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Artifika', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Artifika font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Artifika + static TextTheme artifikaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.artifika(textStyle: textTheme.headline1), + headline2: GoogleFonts.artifika(textStyle: textTheme.headline2), + headline3: GoogleFonts.artifika(textStyle: textTheme.headline3), + headline4: GoogleFonts.artifika(textStyle: textTheme.headline4), + headline5: GoogleFonts.artifika(textStyle: textTheme.headline5), + headline6: GoogleFonts.artifika(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.artifika(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.artifika(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.artifika(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.artifika(textStyle: textTheme.bodyText2), + caption: GoogleFonts.artifika(textStyle: textTheme.caption), + button: GoogleFonts.artifika(textStyle: textTheme.button), + overline: GoogleFonts.artifika(textStyle: textTheme.overline), + ); + } + + /// Applies the Arvo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arvo + static TextStyle arvo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b816c4a4a7813e7daaa88e2f869b5c8acefbf8d52e00205c41d15dda95f1766c', + 22724, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5250cf6a9f89eba5cb07686924135f2bce7a6f8775a569fac7276b5c83b03db7', + 22704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1126bb2afe7e919632493ca620fc94e998910794a9fd47d82092f6edc26f4368', + 22608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '43a330e1b8afd2c95f4f6b1c9c67ef7dfab28ed90bfb6a4551efe8480a060222', + 23288, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Arvo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arvo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arvo + static TextTheme arvoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arvo(textStyle: textTheme.headline1), + headline2: GoogleFonts.arvo(textStyle: textTheme.headline2), + headline3: GoogleFonts.arvo(textStyle: textTheme.headline3), + headline4: GoogleFonts.arvo(textStyle: textTheme.headline4), + headline5: GoogleFonts.arvo(textStyle: textTheme.headline5), + headline6: GoogleFonts.arvo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arvo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arvo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arvo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arvo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arvo(textStyle: textTheme.caption), + button: GoogleFonts.arvo(textStyle: textTheme.button), + overline: GoogleFonts.arvo(textStyle: textTheme.overline), + ); + } + + /// Applies the Arya font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arya + static TextStyle arya({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '98cf640f609db3f8940fc4bc1566dda034961cb11d23f71a277f3ab268c8859a', + 120116, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6c168a53b559c7407d20692a42b94301046b15c4838d709b83992c32cab5732c', + 119776, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Arya', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Arya font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Arya + static TextTheme aryaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.arya(textStyle: textTheme.headline1), + headline2: GoogleFonts.arya(textStyle: textTheme.headline2), + headline3: GoogleFonts.arya(textStyle: textTheme.headline3), + headline4: GoogleFonts.arya(textStyle: textTheme.headline4), + headline5: GoogleFonts.arya(textStyle: textTheme.headline5), + headline6: GoogleFonts.arya(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.arya(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.arya(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.arya(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.arya(textStyle: textTheme.bodyText2), + caption: GoogleFonts.arya(textStyle: textTheme.caption), + button: GoogleFonts.arya(textStyle: textTheme.button), + overline: GoogleFonts.arya(textStyle: textTheme.overline), + ); + } + + /// Applies the Asap font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Asap + static TextStyle asap({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3424989c5e2512f04cbd78fd70665961847d7307eb5d795caadac8db451f74cc', + 67676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6286c24191501089796508556c20c3086610ae6aeb56d9aadceaaa0b7d825c51', + 69828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c7034a58c9a896f74c127472a7085dbd1d6bfb6fd2cafb4140dfde291f0bc399', + 67936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '13483b794adc9a08424049bbf8e6a03b399069e87c0c4d01777ae17c3328de81', + 69828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '835a74fedec5a1877e092c739d9f213a3e41860462c70437da2465b5f99ea073', + 67904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ce966470982f0031860428bc4a47e41d80471ac70ccc857fac1e948d6c964eb7', + 69648, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Asap', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Asap font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Asap + static TextTheme asapTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.asap(textStyle: textTheme.headline1), + headline2: GoogleFonts.asap(textStyle: textTheme.headline2), + headline3: GoogleFonts.asap(textStyle: textTheme.headline3), + headline4: GoogleFonts.asap(textStyle: textTheme.headline4), + headline5: GoogleFonts.asap(textStyle: textTheme.headline5), + headline6: GoogleFonts.asap(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.asap(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.asap(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.asap(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.asap(textStyle: textTheme.bodyText2), + caption: GoogleFonts.asap(textStyle: textTheme.caption), + button: GoogleFonts.asap(textStyle: textTheme.button), + overline: GoogleFonts.asap(textStyle: textTheme.overline), + ); + } + + /// Applies the Asar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Asar + static TextStyle asar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '52cdc31a962e99a625bf96be5b06ab8118290c27e17701c4938182d9e56109af', + 410900, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Asar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Asar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Asar + static TextTheme asarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.asar(textStyle: textTheme.headline1), + headline2: GoogleFonts.asar(textStyle: textTheme.headline2), + headline3: GoogleFonts.asar(textStyle: textTheme.headline3), + headline4: GoogleFonts.asar(textStyle: textTheme.headline4), + headline5: GoogleFonts.asar(textStyle: textTheme.headline5), + headline6: GoogleFonts.asar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.asar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.asar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.asar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.asar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.asar(textStyle: textTheme.caption), + button: GoogleFonts.asar(textStyle: textTheme.button), + overline: GoogleFonts.asar(textStyle: textTheme.overline), + ); + } + + /// Applies the Asset font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Asset + static TextStyle asset({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6423261d7b23d05ef705ee59a0151076feed8408f637b04693272b767ac6cfd5', + 52004, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Asset', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Asset font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Asset + static TextTheme assetTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.asset(textStyle: textTheme.headline1), + headline2: GoogleFonts.asset(textStyle: textTheme.headline2), + headline3: GoogleFonts.asset(textStyle: textTheme.headline3), + headline4: GoogleFonts.asset(textStyle: textTheme.headline4), + headline5: GoogleFonts.asset(textStyle: textTheme.headline5), + headline6: GoogleFonts.asset(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.asset(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.asset(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.asset(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.asset(textStyle: textTheme.bodyText2), + caption: GoogleFonts.asset(textStyle: textTheme.caption), + button: GoogleFonts.asset(textStyle: textTheme.button), + overline: GoogleFonts.asset(textStyle: textTheme.overline), + ); + } + + /// Applies the Assistant font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Assistant + static TextStyle assistant({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6f4c276bf1e4d52183015128074de4702a86fc31cce04f575a8ebef54a077c78', + 57240, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ad7ba792736448061fddf24806abe616e89d7a21a00d169ac4bf95db35ffe9cc', + 57400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1ffb8d00a2bd6ab725bb34dc8eaf61737481f6b285988332e4f6a4b60279dbde', + 57088, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1dc8095e8dddae977007770ce433f8ed1e374d0a83d7330ecea3b335109a4985', + 56812, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '81008b85f8a91125a8efe85a353982fe1b825def9ef33eed881b709a6debf250', + 56752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7370c1c3e5649abcfa6f44475eed601eb070ab934a708081b87627827d5463a', + 56872, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Assistant', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Assistant font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Assistant + static TextTheme assistantTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.assistant(textStyle: textTheme.headline1), + headline2: GoogleFonts.assistant(textStyle: textTheme.headline2), + headline3: GoogleFonts.assistant(textStyle: textTheme.headline3), + headline4: GoogleFonts.assistant(textStyle: textTheme.headline4), + headline5: GoogleFonts.assistant(textStyle: textTheme.headline5), + headline6: GoogleFonts.assistant(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.assistant(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.assistant(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.assistant(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.assistant(textStyle: textTheme.bodyText2), + caption: GoogleFonts.assistant(textStyle: textTheme.caption), + button: GoogleFonts.assistant(textStyle: textTheme.button), + overline: GoogleFonts.assistant(textStyle: textTheme.overline), + ); + } + + /// Applies the Astloch font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Astloch + static TextStyle astloch({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b51d807f9b0f818e44f8f40d4fbedacfff7df981efda85e7b722d62f6022a168', + 49860, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b86a5f0e90945d44c5b629fde8c5a667dd7882ab201ccb397f96f482fd7e98bc', + 51544, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Astloch', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Astloch font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Astloch + static TextTheme astlochTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.astloch(textStyle: textTheme.headline1), + headline2: GoogleFonts.astloch(textStyle: textTheme.headline2), + headline3: GoogleFonts.astloch(textStyle: textTheme.headline3), + headline4: GoogleFonts.astloch(textStyle: textTheme.headline4), + headline5: GoogleFonts.astloch(textStyle: textTheme.headline5), + headline6: GoogleFonts.astloch(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.astloch(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.astloch(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.astloch(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.astloch(textStyle: textTheme.bodyText2), + caption: GoogleFonts.astloch(textStyle: textTheme.caption), + button: GoogleFonts.astloch(textStyle: textTheme.button), + overline: GoogleFonts.astloch(textStyle: textTheme.overline), + ); + } + + /// Applies the Asul font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Asul + static TextStyle asul({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd38e526c102508df44df01ded7aefa955a61c999e42e91cbcb82103aa1269875', + 33468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1810c0e0a5199932d466db95d83fab54bd1b5f6fd5b91664ca7240078d2dd1f0', + 33500, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Asul', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Asul font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Asul + static TextTheme asulTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.asul(textStyle: textTheme.headline1), + headline2: GoogleFonts.asul(textStyle: textTheme.headline2), + headline3: GoogleFonts.asul(textStyle: textTheme.headline3), + headline4: GoogleFonts.asul(textStyle: textTheme.headline4), + headline5: GoogleFonts.asul(textStyle: textTheme.headline5), + headline6: GoogleFonts.asul(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.asul(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.asul(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.asul(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.asul(textStyle: textTheme.bodyText2), + caption: GoogleFonts.asul(textStyle: textTheme.caption), + button: GoogleFonts.asul(textStyle: textTheme.button), + overline: GoogleFonts.asul(textStyle: textTheme.overline), + ); + } + + /// Applies the Athiti font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Athiti + static TextStyle athiti({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4abe61baf7f8762b4dcb6b88b0610de73f42b112a793e28b92da163ee7e441d7', + 112524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f9c6df08ed329fa184304cf4bc64319e7812c62c2ae136dc89cb10a5d5c35018', + 111332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4559ae55fe1020c88dc144ae60afba5e282fcd3aa1c5107292df173d42135806', + 112320, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6e1f0a1706330d270d93ea13e88b35d9c6f4bf71d927e9468278c03b57986330', + 112508, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '398a37b4c34df12c6ede4a85f215d56eaa5a8b515ea5e0bdad2ef676c2ae858a', + 112080, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '63b6ab040d22bd64ce5d5400f352fac3ecefa83827b1862b8a216d5c729ea286', + 112932, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Athiti', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Athiti font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Athiti + static TextTheme athitiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.athiti(textStyle: textTheme.headline1), + headline2: GoogleFonts.athiti(textStyle: textTheme.headline2), + headline3: GoogleFonts.athiti(textStyle: textTheme.headline3), + headline4: GoogleFonts.athiti(textStyle: textTheme.headline4), + headline5: GoogleFonts.athiti(textStyle: textTheme.headline5), + headline6: GoogleFonts.athiti(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.athiti(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.athiti(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.athiti(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.athiti(textStyle: textTheme.bodyText2), + caption: GoogleFonts.athiti(textStyle: textTheme.caption), + button: GoogleFonts.athiti(textStyle: textTheme.button), + overline: GoogleFonts.athiti(textStyle: textTheme.overline), + ); + } + + /// Applies the Atma font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Atma + static TextStyle atma({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd691cbd1df6f6a53328f8d9d9514102c915be55e93a8c1f0cb0826a27a60e4f2', + 196364, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '702ceed58c58203ab0c8ad4bbbbda56c77b89a29496d748322180acbed120201', + 198056, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cc558572cee6afca8a8d34b8cb8a2397d749e0c22f9d9977f39eb0e84d636967', + 197528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b569b84d6ee492ead3f4c73af6244137b0e4c604c9e98cc57627162221d498bb', + 196596, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '127f716e96fc47aee7624acf9cebd859693a19f2fc1f7d832f33835e5bd3b834', + 193184, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Atma', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Atma font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Atma + static TextTheme atmaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.atma(textStyle: textTheme.headline1), + headline2: GoogleFonts.atma(textStyle: textTheme.headline2), + headline3: GoogleFonts.atma(textStyle: textTheme.headline3), + headline4: GoogleFonts.atma(textStyle: textTheme.headline4), + headline5: GoogleFonts.atma(textStyle: textTheme.headline5), + headline6: GoogleFonts.atma(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.atma(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.atma(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.atma(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.atma(textStyle: textTheme.bodyText2), + caption: GoogleFonts.atma(textStyle: textTheme.caption), + button: GoogleFonts.atma(textStyle: textTheme.button), + overline: GoogleFonts.atma(textStyle: textTheme.overline), + ); + } + + /// Applies the Atomic Age font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Atomic+Age + static TextStyle atomicAge({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6fc59a494c6184d973d9d5db8ec698d8acb6283fc807bd1a13c30000b83b832c', + 44272, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AtomicAge', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Atomic Age font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Atomic+Age + static TextTheme atomicAgeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.atomicAge(textStyle: textTheme.headline1), + headline2: GoogleFonts.atomicAge(textStyle: textTheme.headline2), + headline3: GoogleFonts.atomicAge(textStyle: textTheme.headline3), + headline4: GoogleFonts.atomicAge(textStyle: textTheme.headline4), + headline5: GoogleFonts.atomicAge(textStyle: textTheme.headline5), + headline6: GoogleFonts.atomicAge(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.atomicAge(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.atomicAge(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.atomicAge(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.atomicAge(textStyle: textTheme.bodyText2), + caption: GoogleFonts.atomicAge(textStyle: textTheme.caption), + button: GoogleFonts.atomicAge(textStyle: textTheme.button), + overline: GoogleFonts.atomicAge(textStyle: textTheme.overline), + ); + } + + /// Applies the Aubrey font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aubrey + static TextStyle aubrey({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1464a409557010421785a4857a333c92eb6c4a28c0dbeeb0b1f8441f5e68ab96', + 96976, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Aubrey', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Aubrey font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Aubrey + static TextTheme aubreyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.aubrey(textStyle: textTheme.headline1), + headline2: GoogleFonts.aubrey(textStyle: textTheme.headline2), + headline3: GoogleFonts.aubrey(textStyle: textTheme.headline3), + headline4: GoogleFonts.aubrey(textStyle: textTheme.headline4), + headline5: GoogleFonts.aubrey(textStyle: textTheme.headline5), + headline6: GoogleFonts.aubrey(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.aubrey(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.aubrey(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.aubrey(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.aubrey(textStyle: textTheme.bodyText2), + caption: GoogleFonts.aubrey(textStyle: textTheme.caption), + button: GoogleFonts.aubrey(textStyle: textTheme.button), + overline: GoogleFonts.aubrey(textStyle: textTheme.overline), + ); + } + + /// Applies the Audiowide font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Audiowide + static TextStyle audiowide({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2054b5910bd5457176b1479122e09690d5afe73d3749e5ef89a3686e6f724c29', + 70472, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Audiowide', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Audiowide font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Audiowide + static TextTheme audiowideTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.audiowide(textStyle: textTheme.headline1), + headline2: GoogleFonts.audiowide(textStyle: textTheme.headline2), + headline3: GoogleFonts.audiowide(textStyle: textTheme.headline3), + headline4: GoogleFonts.audiowide(textStyle: textTheme.headline4), + headline5: GoogleFonts.audiowide(textStyle: textTheme.headline5), + headline6: GoogleFonts.audiowide(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.audiowide(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.audiowide(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.audiowide(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.audiowide(textStyle: textTheme.bodyText2), + caption: GoogleFonts.audiowide(textStyle: textTheme.caption), + button: GoogleFonts.audiowide(textStyle: textTheme.button), + overline: GoogleFonts.audiowide(textStyle: textTheme.overline), + ); + } + + /// Applies the Autour One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Autour+One + static TextStyle autourOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ee63c9c20873c21ac935c1493e94bb24b9dc9782f63d01761b54dfedf4b3972c', + 59552, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AutourOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Autour One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Autour+One + static TextTheme autourOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.autourOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.autourOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.autourOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.autourOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.autourOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.autourOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.autourOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.autourOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.autourOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.autourOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.autourOne(textStyle: textTheme.caption), + button: GoogleFonts.autourOne(textStyle: textTheme.button), + overline: GoogleFonts.autourOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Average font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Average + static TextStyle average({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ce0697844aa3a978d483dfa380fbebd5bff8e7e6dc0897bf6c2c009fb9ae4ab2', + 37788, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Average', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Average font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Average + static TextTheme averageTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.average(textStyle: textTheme.headline1), + headline2: GoogleFonts.average(textStyle: textTheme.headline2), + headline3: GoogleFonts.average(textStyle: textTheme.headline3), + headline4: GoogleFonts.average(textStyle: textTheme.headline4), + headline5: GoogleFonts.average(textStyle: textTheme.headline5), + headline6: GoogleFonts.average(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.average(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.average(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.average(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.average(textStyle: textTheme.bodyText2), + caption: GoogleFonts.average(textStyle: textTheme.caption), + button: GoogleFonts.average(textStyle: textTheme.button), + overline: GoogleFonts.average(textStyle: textTheme.overline), + ); + } + + /// Applies the Average Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Average+Sans + static TextStyle averageSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'defa6f6e46057de37a3b075c74765ba7cd6a46e0ac756e83f454dfb8b1afa95c', + 43964, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AverageSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Average Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Average+Sans + static TextTheme averageSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.averageSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.averageSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.averageSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.averageSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.averageSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.averageSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.averageSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.averageSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.averageSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.averageSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.averageSans(textStyle: textTheme.caption), + button: GoogleFonts.averageSans(textStyle: textTheme.button), + overline: GoogleFonts.averageSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Averia Gruesa Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Averia+Gruesa+Libre + static TextStyle averiaGruesaLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3c60fda1756722c9f8d80009e0627d49eb2106d9eada7962d132e3ebef09c96a', + 111344, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AveriaGruesaLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Averia Gruesa Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Averia+Gruesa+Libre + static TextTheme averiaGruesaLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.caption), + button: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.button), + overline: GoogleFonts.averiaGruesaLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Averia Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Averia+Libre + static TextStyle averiaLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '446105043cce1cc90406cda4c387ef2100b294d9d63b3946d4a395d3f2a9ce07', + 108192, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c8a24e13d7d611dd8a4e15743ac34b163b1e96d1c9a9e82746f0bd9d3a878613', + 133544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2b819eb7a1c11f4de65f3bfe1a8f658ea56fc62b2b7a24b2cf8688e9ced04c96', + 108468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '793d505e83fbdbef6ceeabd6897693fb515a4890b822623deb545b53e7ec68dd', + 128848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6b157a260e6fd6b7cdd2d54fc4f46e1a72fbb33034b74a6929cbc4d0a7d83e3d', + 112228, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '08c2c28ffffd04d884122fa538e0c615e52983959363269b543084794a60955f', + 135664, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AveriaLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Averia Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Averia+Libre + static TextTheme averiaLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.averiaLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.averiaLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.averiaLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.averiaLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.averiaLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.averiaLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.averiaLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.averiaLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.averiaLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.averiaLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.averiaLibre(textStyle: textTheme.caption), + button: GoogleFonts.averiaLibre(textStyle: textTheme.button), + overline: GoogleFonts.averiaLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Averia Sans Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Averia+Sans+Libre + static TextStyle averiaSansLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '452436a08a43ba5da912a2ed71aa4e0c67ae680532317c5affb99278cedc4eb8', + 107752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '056589edb0d0f068b768b9b9f6361bb5c4a2d53a33006288c9d089b1e6421f66', + 134200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c5f843350837023c845544f24fa59e8c71cbe7bc284c0ea4127aa872c4fcac41', + 108360, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a79e7e7aecba032e6272d99a93c69868328db8d34091d1c70ccfd4a839f70489', + 128896, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8af8ea3669721038ea729e975cadce19a0032e981378e23c8377e2faf979aca', + 113016, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0509fc7d0b873424deb4340ab1bafca704241ecfda08cdafeab623999d12bdfd', + 135852, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AveriaSansLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Averia Sans Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Averia+Sans+Libre + static TextTheme averiaSansLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.averiaSansLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.averiaSansLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.averiaSansLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.averiaSansLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.averiaSansLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.averiaSansLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.averiaSansLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.averiaSansLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.averiaSansLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.averiaSansLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.averiaSansLibre(textStyle: textTheme.caption), + button: GoogleFonts.averiaSansLibre(textStyle: textTheme.button), + overline: GoogleFonts.averiaSansLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Averia Serif Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Averia+Serif+Libre + static TextStyle averiaSerifLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '605722d0534e8b2a7a4ce36ebc7ecfa14868d5aeae52ba3419e14a19e67c92ba', + 109972, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4b675f9e2f2962fb69b7145f35ea9df241cdc9b91744abeac3cdfbf7aca1740b', + 135976, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1939fc59e6192c78872b151f71d328c64c84552c1f8f7548f3278d3db023959f', + 109988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '383c63d8878e96726e26c44d5a631030fcf28d4abdcb9bdadd86dbb01a623de9', + 130956, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '19af7d57b5ea32ff5df3f2405e0d51759fdbab503fa4cfd420a5eb4943805fcc', + 113956, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '164c3a01088756eebd948641705d6759b2fc7dabfd77d6e36490aa39befa0028', + 138208, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'AveriaSerifLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Averia Serif Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Averia+Serif+Libre + static TextTheme averiaSerifLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.averiaSerifLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.averiaSerifLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.averiaSerifLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.averiaSerifLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.averiaSerifLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.averiaSerifLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.averiaSerifLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.averiaSerifLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.averiaSerifLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.averiaSerifLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.averiaSerifLibre(textStyle: textTheme.caption), + button: GoogleFonts.averiaSerifLibre(textStyle: textTheme.button), + overline: GoogleFonts.averiaSerifLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the B612 font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/B612 + static TextStyle b612({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b11c6d50f8a4ef2abd6df134192e3770a9b392c814caf916bcf0efa87e6743d2', + 89048, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4250a2e42f4ceda476c771828532dfb8cb2e9170ceb541e8aecc34ecea7977b4', + 92732, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd3f9b01c62cb7bf3bc87cbc07452bc98a3058af8a40db93b64528fb711a429ea', + 88700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f930926cd0cbbde94c51659420d91fb464c93fa3109c6bdf553a706985e307e2', + 91740, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'B612', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the B612 font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/B612 + static TextTheme b612TextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.b612(textStyle: textTheme.headline1), + headline2: GoogleFonts.b612(textStyle: textTheme.headline2), + headline3: GoogleFonts.b612(textStyle: textTheme.headline3), + headline4: GoogleFonts.b612(textStyle: textTheme.headline4), + headline5: GoogleFonts.b612(textStyle: textTheme.headline5), + headline6: GoogleFonts.b612(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.b612(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.b612(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.b612(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.b612(textStyle: textTheme.bodyText2), + caption: GoogleFonts.b612(textStyle: textTheme.caption), + button: GoogleFonts.b612(textStyle: textTheme.button), + overline: GoogleFonts.b612(textStyle: textTheme.overline), + ); + } + + /// Applies the B612 Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/B612+Mono + static TextStyle b612Mono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ffa9cacfa6fcd1a7a413d3b87f6f5ac6e2b201649b64695d976e0af5a46d512', + 86196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '55c1dcdfe00e2848cd4e1946617c601f62a0828e6ba3c73924b8b4f4e705785c', + 88684, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '515c42e5f2790fd973f2ee9685301efa0110bc2dfb33df69b57875318ad1e100', + 85172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a4a6d28684fe7467e89b15c82070e98ed4c0623a5df5a9a05d347f757cda41e6', + 87488, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'B612Mono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the B612 Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/B612+Mono + static TextTheme b612MonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.b612Mono(textStyle: textTheme.headline1), + headline2: GoogleFonts.b612Mono(textStyle: textTheme.headline2), + headline3: GoogleFonts.b612Mono(textStyle: textTheme.headline3), + headline4: GoogleFonts.b612Mono(textStyle: textTheme.headline4), + headline5: GoogleFonts.b612Mono(textStyle: textTheme.headline5), + headline6: GoogleFonts.b612Mono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.b612Mono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.b612Mono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.b612Mono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.b612Mono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.b612Mono(textStyle: textTheme.caption), + button: GoogleFonts.b612Mono(textStyle: textTheme.button), + overline: GoogleFonts.b612Mono(textStyle: textTheme.overline), + ); + } + + /// Applies the Bad Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bad+Script + static TextStyle badScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '85388546eb146e3e3bf5803d4a47f053ad2a9491ee3470c23912777bfbfbc111', + 54372, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BadScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bad Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bad+Script + static TextTheme badScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.badScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.badScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.badScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.badScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.badScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.badScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.badScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.badScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.badScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.badScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.badScript(textStyle: textTheme.caption), + button: GoogleFonts.badScript(textStyle: textTheme.button), + overline: GoogleFonts.badScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Bahiana font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bahiana + static TextStyle bahiana({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1134edff7d2708933a16883c07c5223938a3500e9880b289c754c2602b9181f7', + 51296, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bahiana', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bahiana font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bahiana + static TextTheme bahianaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bahiana(textStyle: textTheme.headline1), + headline2: GoogleFonts.bahiana(textStyle: textTheme.headline2), + headline3: GoogleFonts.bahiana(textStyle: textTheme.headline3), + headline4: GoogleFonts.bahiana(textStyle: textTheme.headline4), + headline5: GoogleFonts.bahiana(textStyle: textTheme.headline5), + headline6: GoogleFonts.bahiana(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bahiana(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bahiana(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bahiana(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bahiana(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bahiana(textStyle: textTheme.caption), + button: GoogleFonts.bahiana(textStyle: textTheme.button), + overline: GoogleFonts.bahiana(textStyle: textTheme.overline), + ); + } + + /// Applies the Bahianita font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bahianita + static TextStyle bahianita({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8eae7d3828ad86d4af376a41fb9bd577433f7b9acf6f561f8c3383bf8f37224b', + 91540, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bahianita', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bahianita font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bahianita + static TextTheme bahianitaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bahianita(textStyle: textTheme.headline1), + headline2: GoogleFonts.bahianita(textStyle: textTheme.headline2), + headline3: GoogleFonts.bahianita(textStyle: textTheme.headline3), + headline4: GoogleFonts.bahianita(textStyle: textTheme.headline4), + headline5: GoogleFonts.bahianita(textStyle: textTheme.headline5), + headline6: GoogleFonts.bahianita(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bahianita(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bahianita(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bahianita(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bahianita(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bahianita(textStyle: textTheme.caption), + button: GoogleFonts.bahianita(textStyle: textTheme.button), + overline: GoogleFonts.bahianita(textStyle: textTheme.overline), + ); + } + + /// Applies the Bai Jamjuree font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bai+Jamjuree + static TextStyle baiJamjuree({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fdb9acd5c9a309240a161cc16a0a5e3a1f3bf9258d1f2cf14fdfdf6f79d83c8e', + 78044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fff587a7a746a3d84947c3982968551180877152f29ac4e6b58a5d060e741ee3', + 83600, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '253ea5a1c8d0d3dacbf5b9f0db496617c2af6b95a5e0680df9c9c62b989b1799', + 78384, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c31f0c72862a5db7605a1625ddf34cc3c20c1c8a756b7d8848bf7f57a2707e0c', + 83780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c1dad5e37560fcacf02277fc359aecaab78b734f4a4839c6cf910296b20101fa', + 78416, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e8939d2176c550b12487aed8e2fbc3b25917494c1174787534ed05c61be397f2', + 83856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9f9c01d94ba412108985bed479c74ca19d6b1b8c6982ee1fc113a970d5d323ea', + 78428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '01569d323f908485836ed8c94772695fc05a4b02812f4f29a62ec257f911b55b', + 83944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a2ef2b81cbfb6b9a14a4bb8931a87a0887e676e237a098c40aa9e61d601dcbd2', + 78412, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7db95e5673e505c331643e67b6172b4465e72300e3642242b55e75a28d7f5883', + 83776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e456eaafee629c1aa6ffda2fbc121b9b76b54ab7f4b6dcaac6a4a523263b2237', + 78104, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3445df11af52dc901fce718f3b68b4df5dc14a6c7b2ae6399dcf47c7fa7dd34b', + 83360, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BaiJamjuree', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bai Jamjuree font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bai+Jamjuree + static TextTheme baiJamjureeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.baiJamjuree(textStyle: textTheme.headline1), + headline2: GoogleFonts.baiJamjuree(textStyle: textTheme.headline2), + headline3: GoogleFonts.baiJamjuree(textStyle: textTheme.headline3), + headline4: GoogleFonts.baiJamjuree(textStyle: textTheme.headline4), + headline5: GoogleFonts.baiJamjuree(textStyle: textTheme.headline5), + headline6: GoogleFonts.baiJamjuree(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.baiJamjuree(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.baiJamjuree(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.baiJamjuree(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.baiJamjuree(textStyle: textTheme.bodyText2), + caption: GoogleFonts.baiJamjuree(textStyle: textTheme.caption), + button: GoogleFonts.baiJamjuree(textStyle: textTheme.button), + overline: GoogleFonts.baiJamjuree(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo + static TextStyle baloo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2466b115f1d612b5be7c3c51aa118d952041ad4c9ebc6b790d3659c11ae3681d', + 386736, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Baloo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo + static TextTheme balooTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.baloo(textStyle: textTheme.headline1), + headline2: GoogleFonts.baloo(textStyle: textTheme.headline2), + headline3: GoogleFonts.baloo(textStyle: textTheme.headline3), + headline4: GoogleFonts.baloo(textStyle: textTheme.headline4), + headline5: GoogleFonts.baloo(textStyle: textTheme.headline5), + headline6: GoogleFonts.baloo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.baloo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.baloo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.baloo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.baloo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.baloo(textStyle: textTheme.caption), + button: GoogleFonts.baloo(textStyle: textTheme.button), + overline: GoogleFonts.baloo(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Bhai font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Bhai + static TextStyle balooBhai({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '678bfe33602fe168ee8732abcdc1ea3a454798cd99cb4f81f7e9d16581a7e2ed', + 277392, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooBhai', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Bhai font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Bhai + static TextTheme balooBhaiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooBhai(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooBhai(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooBhai(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooBhai(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooBhai(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooBhai(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooBhai(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooBhai(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooBhai(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooBhai(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooBhai(textStyle: textTheme.caption), + button: GoogleFonts.balooBhai(textStyle: textTheme.button), + overline: GoogleFonts.balooBhai(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Bhaijaan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Bhaijaan + static TextStyle balooBhaijaan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '52b00fb70a18a89da089a7492d3d97836ec7bd211288d3ec4ad6a60914db3dd3', + 171132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooBhaijaan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Bhaijaan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Bhaijaan + static TextTheme balooBhaijaanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooBhaijaan(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooBhaijaan(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooBhaijaan(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooBhaijaan(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooBhaijaan(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooBhaijaan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooBhaijaan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooBhaijaan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooBhaijaan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooBhaijaan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooBhaijaan(textStyle: textTheme.caption), + button: GoogleFonts.balooBhaijaan(textStyle: textTheme.button), + overline: GoogleFonts.balooBhaijaan(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Bhaina font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Bhaina + static TextStyle balooBhaina({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '86bbf2a9f2b3936c4b1907de7136a4ca0f71efacfe22b7a6fa1b8a8a81f86282', + 262212, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooBhaina', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Bhaina font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Bhaina + static TextTheme balooBhainaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooBhaina(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooBhaina(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooBhaina(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooBhaina(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooBhaina(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooBhaina(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooBhaina(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooBhaina(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooBhaina(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooBhaina(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooBhaina(textStyle: textTheme.caption), + button: GoogleFonts.balooBhaina(textStyle: textTheme.button), + overline: GoogleFonts.balooBhaina(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Chettan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Chettan + static TextStyle balooChettan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5e430d6e47dbe9220996407624585cda368b6ce19a23c3f46844a06db3c0a679', + 217796, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooChettan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Chettan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Chettan + static TextTheme balooChettanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooChettan(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooChettan(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooChettan(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooChettan(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooChettan(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooChettan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooChettan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooChettan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooChettan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooChettan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooChettan(textStyle: textTheme.caption), + button: GoogleFonts.balooChettan(textStyle: textTheme.button), + overline: GoogleFonts.balooChettan(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Da font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Da + static TextStyle balooDa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '88a331b2ae3e4db09605af2b1076b22c3734e2ecfd1b4ef1f4ca57446672e6cf', + 288676, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooDa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Da font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Da + static TextTheme balooDaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooDa(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooDa(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooDa(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooDa(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooDa(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooDa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooDa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooDa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooDa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooDa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooDa(textStyle: textTheme.caption), + button: GoogleFonts.balooDa(textStyle: textTheme.button), + overline: GoogleFonts.balooDa(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Paaji font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Paaji + static TextStyle balooPaaji({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '95ba9f62ad854dc07958f311af18c674ca943fa7450fa4f6640d18e8eccdfe3f', + 185064, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooPaaji', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Paaji font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Paaji + static TextTheme balooPaajiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooPaaji(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooPaaji(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooPaaji(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooPaaji(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooPaaji(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooPaaji(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooPaaji(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooPaaji(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooPaaji(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooPaaji(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooPaaji(textStyle: textTheme.caption), + button: GoogleFonts.balooPaaji(textStyle: textTheme.button), + overline: GoogleFonts.balooPaaji(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Tamma font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Tamma + static TextStyle balooTamma({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8005871563cf3cfadf580fba66361b46649b342e9e1765d65405765af6e92c4', + 389440, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooTamma', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Tamma font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Tamma + static TextTheme balooTammaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooTamma(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooTamma(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooTamma(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooTamma(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooTamma(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooTamma(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooTamma(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooTamma(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooTamma(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooTamma(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooTamma(textStyle: textTheme.caption), + button: GoogleFonts.balooTamma(textStyle: textTheme.button), + overline: GoogleFonts.balooTamma(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Tammudu font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Tammudu + static TextStyle balooTammudu({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7bc7db26ac47d3561769f8cb3dfb93afd2767965efbd2770a77f8ffb33c5a013', + 406812, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooTammudu', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Tammudu font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Tammudu + static TextTheme balooTammuduTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooTammudu(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooTammudu(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooTammudu(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooTammudu(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooTammudu(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooTammudu(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooTammudu(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooTammudu(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooTammudu(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooTammudu(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooTammudu(textStyle: textTheme.caption), + button: GoogleFonts.balooTammudu(textStyle: textTheme.button), + overline: GoogleFonts.balooTammudu(textStyle: textTheme.overline), + ); + } + + /// Applies the Baloo Thambi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Thambi + static TextStyle balooThambi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5eb4d30c776f864b83a43cfbbcf1d05dda4a119a042f5a735adb014fdb4707e3', + 200468, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalooThambi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baloo Thambi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baloo+Thambi + static TextTheme balooThambiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balooThambi(textStyle: textTheme.headline1), + headline2: GoogleFonts.balooThambi(textStyle: textTheme.headline2), + headline3: GoogleFonts.balooThambi(textStyle: textTheme.headline3), + headline4: GoogleFonts.balooThambi(textStyle: textTheme.headline4), + headline5: GoogleFonts.balooThambi(textStyle: textTheme.headline5), + headline6: GoogleFonts.balooThambi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balooThambi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balooThambi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balooThambi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balooThambi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balooThambi(textStyle: textTheme.caption), + button: GoogleFonts.balooThambi(textStyle: textTheme.button), + overline: GoogleFonts.balooThambi(textStyle: textTheme.overline), + ); + } + + /// Applies the Balsamiq Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Balsamiq+Sans + static TextStyle balsamiqSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e06cc657444119a9850424b46ff940639699d52e1c3031047cb7fc3691a6c33e', + 303084, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '029988fdbc0ec2b09771bb360c222d7c13d7247fd1c37c3e82858febc4f78349', + 283788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'de004fda1323e24a4c16a3f11bb31263cbef6c1ed531a72ff49866f47c488fa1', + 275832, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f7734baad3cbcee8aea5640e4c79b22fe23e57a1a619020095e4e4d2d723f98b', + 257140, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BalsamiqSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Balsamiq Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Balsamiq+Sans + static TextTheme balsamiqSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balsamiqSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.balsamiqSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.balsamiqSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.balsamiqSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.balsamiqSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.balsamiqSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balsamiqSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balsamiqSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balsamiqSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balsamiqSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balsamiqSans(textStyle: textTheme.caption), + button: GoogleFonts.balsamiqSans(textStyle: textTheme.button), + overline: GoogleFonts.balsamiqSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Balthazar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Balthazar + static TextStyle balthazar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6f532266accd2179da995d74ed36fa8bf3095162e9404d68381594561a335b66', + 28176, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Balthazar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Balthazar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Balthazar + static TextTheme balthazarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.balthazar(textStyle: textTheme.headline1), + headline2: GoogleFonts.balthazar(textStyle: textTheme.headline2), + headline3: GoogleFonts.balthazar(textStyle: textTheme.headline3), + headline4: GoogleFonts.balthazar(textStyle: textTheme.headline4), + headline5: GoogleFonts.balthazar(textStyle: textTheme.headline5), + headline6: GoogleFonts.balthazar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.balthazar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.balthazar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.balthazar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.balthazar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.balthazar(textStyle: textTheme.caption), + button: GoogleFonts.balthazar(textStyle: textTheme.button), + overline: GoogleFonts.balthazar(textStyle: textTheme.overline), + ); + } + + /// Applies the Bangers font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bangers + static TextStyle bangers({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '42a6646ed15dc91b9430f7e69e6259203235b48fa12c9cc10b6b72afab348de0', + 75700, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bangers', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bangers font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bangers + static TextTheme bangersTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bangers(textStyle: textTheme.headline1), + headline2: GoogleFonts.bangers(textStyle: textTheme.headline2), + headline3: GoogleFonts.bangers(textStyle: textTheme.headline3), + headline4: GoogleFonts.bangers(textStyle: textTheme.headline4), + headline5: GoogleFonts.bangers(textStyle: textTheme.headline5), + headline6: GoogleFonts.bangers(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bangers(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bangers(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bangers(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bangers(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bangers(textStyle: textTheme.caption), + button: GoogleFonts.bangers(textStyle: textTheme.button), + overline: GoogleFonts.bangers(textStyle: textTheme.overline), + ); + } + + /// Applies the Barlow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barlow + static TextStyle barlow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cbc7c82fdee3fa8b92bb23c3b9a2e8030733dbbc7322cd0c547b7c1889e7ecc0', + 61884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f69e0bff8f7ab1739bd00636f1efa74a5937c7d34ae95b4ce353b4baad0eae33', + 65692, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6759b2d507f1549918b6b4a394efcca8982958de5ac4134d359b7162e12701ba', + 62392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f750383a2bd7ca69e5e24c2f3fcf974a67a9e98818703c12d9fd2600d62b49cf', + 66844, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f582c8c58e673f459c2daf36fb9e1d3522dd5a7c50e0b8ee02d5a95089fff221', + 64984, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5ccb6cff74b4b842a4da09f1543e6f2ab54f86a0e75b997b7ef375159d0f9bca', + 68556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c1e3cf893b74f13d898b529820f0e01dd59c5c3f6f69635604600893cc99c914', + 62316, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '512de0e21c7303a0b6718ff5cf57c376345786cc521ce3851053764f55398e53', + 66936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6ed898f9a3aa42d3615c69b731f57305ce7006e87e29042e8467203889f0ff3a', + 64904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b84f9e4475585d31451021e3e9d27e8336f00eac47c6753193de4033f15ea30d', + 68204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '88497110ef5b50e3903b3c97ee671e01497a9a6d49f64218c9a70fd5042c3b49', + 62368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '53cad3b96c2a07c4af9d7111e1b6eaf07718e6510b0ccf65140b1ee7040da9b3', + 67272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7513399e0a26a50c0f81fab7a114c8f40337b1d2edd0f28abed3f23ff5232c1', + 62356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '274e649f86e4323b0b8553520d855c49523b84eb9269b8e0cf9f41d201e76068', + 65900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6063124468c1350716105b1b52edec1c02bbbea85a0d675477016f425f457c9a', + 64856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a4cbccba78e5ea3a5c9560b15ff91d04b88b7a8cadb3c81b64ceb9ebd5fc266f', + 68012, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fb60a33ebebe512faae572e414c6865041ea47c278458a28cdcadc762958bd4b', + 61268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cabd84f11a9c742e6116cea169752a0f8c03073eeb60dc0ab4532987bd853878', + 66736, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Barlow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Barlow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barlow + static TextTheme barlowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.barlow(textStyle: textTheme.headline1), + headline2: GoogleFonts.barlow(textStyle: textTheme.headline2), + headline3: GoogleFonts.barlow(textStyle: textTheme.headline3), + headline4: GoogleFonts.barlow(textStyle: textTheme.headline4), + headline5: GoogleFonts.barlow(textStyle: textTheme.headline5), + headline6: GoogleFonts.barlow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.barlow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.barlow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.barlow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.barlow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.barlow(textStyle: textTheme.caption), + button: GoogleFonts.barlow(textStyle: textTheme.button), + overline: GoogleFonts.barlow(textStyle: textTheme.overline), + ); + } + + /// Applies the Barlow Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barlow+Condensed + static TextStyle barlowCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c6f3686935062113e7b09390ffc3c690c608aa440f3e30db068b64420664ec5d', + 60532, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ea5455d6f97ca5ea27d76f30e87b842dc23d6a9fdd9566ccffb6415a3a56bcb0', + 65992, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '410b2efcf0b449d214182287f404b669840f4cc0a3c2f04940cee2d94b6eed4e', + 60752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bba549e676526ff4957a986006a9290f70d407fc1fd00d34135a1291ce6138d4', + 65952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9bcf33e336ef2238ede09a908f8b86c6cca1586df6b1fbe0d59e462e3149b8ba', + 60544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '49c62182eb883aeeab13fa2dbfcde072f2aac31e8bf77a232696bebc3b14e856', + 65664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4e5dff25ad8b2553decdba77625dc57cdcba97555b53612a9c9bfa40f43f953c', + 60524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '65d8e8aa8d380e24c33fe4d2da62c7f9ec3de8e3429671ef5ff32782d21d649a', + 65840, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8014ab571e1d04db59a24744420219343b4d1806c983ac73e808a9e96c638306', + 60404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dc26bbeb004e7e2084d0662973c4742fa65fd15b7eda3cb74826a27d686f44b0', + 65284, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '36127289f54d9e42dd6bba46b0f52ce7e1839e79ce1b4d8fc5b22a54ee7c30f3', + 63120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '70e3edc6f039c1a69acb610d298d522d5b46330458810ec9647e08c87b476dbb', + 66768, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ec8d231a02a1e88872bef49e1099c712e93f3a723722a3d3ddc0fe2bfbe40962', + 63072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'edbf575a42819a83bc5539e63b01efa4299d750d2f679579ef7673c972e3211e', + 66532, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e17df55a2cb70a97d869d33d55b38a29d60d31ae75c0bcaf61aca5f1215702cd', + 62876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '34b5cbd8a9497c32949bcad7e8bd3f63019f7d28e693401b3ac39a69b5cd778d', + 66084, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5db2f838d3b4d86fe437bcaef0fb569cf99cfda6377a230687348897a816eeb5', + 61360, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'de353be0369b799b090de4e2e272ebe13c6fd496973ff92b9e391656334ad1f2', + 64724, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BarlowCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Barlow Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barlow+Condensed + static TextTheme barlowCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.barlowCondensed(textStyle: textTheme.headline1), + headline2: GoogleFonts.barlowCondensed(textStyle: textTheme.headline2), + headline3: GoogleFonts.barlowCondensed(textStyle: textTheme.headline3), + headline4: GoogleFonts.barlowCondensed(textStyle: textTheme.headline4), + headline5: GoogleFonts.barlowCondensed(textStyle: textTheme.headline5), + headline6: GoogleFonts.barlowCondensed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.barlowCondensed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.barlowCondensed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.barlowCondensed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.barlowCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.barlowCondensed(textStyle: textTheme.caption), + button: GoogleFonts.barlowCondensed(textStyle: textTheme.button), + overline: GoogleFonts.barlowCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Barlow Semi Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barlow+Semi+Condensed + static TextStyle barlowSemiCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '429d1fa72c7702c9b3dcb38d750756505166e563306daaf1b66cb753a68f9e2d', + 62376, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '39a411a6e0b959d02638199381cb91af60eb4da3e34ac231c61bea08043966e1', + 67272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd4d4a161e4199c955202ca92d228838efee2dfa3cf68a0cf388085e19395aa5f', + 62680, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '79508f19bd17b1cdbf0b5b6f486c964d65c4a893a7f8f739a63cb71d206bb157', + 67540, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1b2c8175065ed2235c4db66650397fad918d8f97db3f1b3991125f2df604b76c', + 62680, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b1eca79a9e101dd60e1836afb98fee66886d6042c2870f88b7ec822a7b97877b', + 67388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a9dca109aaa256a5afb98477989b87e0e102269f948949e5573b65b45779d4e', + 62588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '97fff70c506e46d82a769311aa3efd01c86a10161c92dee921fb6c75da5ba39c', + 67012, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '73e602f9d74684f25a9d352cc61a0cfefc4ab505dfecb50b843492b1b5a87c3e', + 62528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f1b5d4427848534739c734c5af7bdae1967a666e5c68e04156f0c5a60c1a1c78', + 66868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b98dce5b8a6c1c5c2804cd26be37b203c56aee083840f4bad5d1907c4bf0b295', + 65064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '82e1d9e57f5b1c3fba390bb1e428d9b26538ead3342f04c40e60ded6325cc06e', + 68404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'acfd284673d183fe78a563ebf695ce70f7800151495260debfa9532d93289a55', + 65208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e07191b9549a6c8c553608c75269487bb83c555c9e2fd9c08cfe704a5416e750', + 68320, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b42194ff2e3637db2ee27a0720eed118d756d564014725a948bcdc8964d25901', + 65240, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '36f4cee581975816949c810a10be068d6131acdc211a99acb3a2ce6c9586174f', + 68236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2305373351846fd5f75bfb35b24697021e9bd4ea4fac80bb25bfe62c9afcb604', + 63764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '29476cff7567544f2a04e61c90254033e0eb160089bfae4dea9871e8f6fbe2f9', + 67124, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BarlowSemiCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Barlow Semi Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barlow+Semi+Condensed + static TextTheme barlowSemiCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.headline1), + headline2: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.headline2), + headline3: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.headline3), + headline4: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.headline4), + headline5: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.headline5), + headline6: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.barlowSemiCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.barlowSemiCondensed(textStyle: textTheme.caption), + button: GoogleFonts.barlowSemiCondensed(textStyle: textTheme.button), + overline: GoogleFonts.barlowSemiCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Barriecito font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barriecito + static TextStyle barriecito({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cbd439bbca5ece3347c1497394d9cdfd488742cc10ccd2413cdba4e819f236bb', + 167636, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Barriecito', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Barriecito font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barriecito + static TextTheme barriecitoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.barriecito(textStyle: textTheme.headline1), + headline2: GoogleFonts.barriecito(textStyle: textTheme.headline2), + headline3: GoogleFonts.barriecito(textStyle: textTheme.headline3), + headline4: GoogleFonts.barriecito(textStyle: textTheme.headline4), + headline5: GoogleFonts.barriecito(textStyle: textTheme.headline5), + headline6: GoogleFonts.barriecito(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.barriecito(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.barriecito(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.barriecito(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.barriecito(textStyle: textTheme.bodyText2), + caption: GoogleFonts.barriecito(textStyle: textTheme.caption), + button: GoogleFonts.barriecito(textStyle: textTheme.button), + overline: GoogleFonts.barriecito(textStyle: textTheme.overline), + ); + } + + /// Applies the Barrio font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barrio + static TextStyle barrio({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e1745250902305ccc432fd4ac10b9b248159dddd57634c31c70b8b4f3e3983f1', + 146692, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Barrio', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Barrio font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Barrio + static TextTheme barrioTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.barrio(textStyle: textTheme.headline1), + headline2: GoogleFonts.barrio(textStyle: textTheme.headline2), + headline3: GoogleFonts.barrio(textStyle: textTheme.headline3), + headline4: GoogleFonts.barrio(textStyle: textTheme.headline4), + headline5: GoogleFonts.barrio(textStyle: textTheme.headline5), + headline6: GoogleFonts.barrio(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.barrio(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.barrio(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.barrio(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.barrio(textStyle: textTheme.bodyText2), + caption: GoogleFonts.barrio(textStyle: textTheme.caption), + button: GoogleFonts.barrio(textStyle: textTheme.button), + overline: GoogleFonts.barrio(textStyle: textTheme.overline), + ); + } + + /// Applies the Basic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Basic + static TextStyle basic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '29cf0f576451b712f706b5f33a2e8e1b6e2be41ed145ebce30bcf8828ec37960', + 45400, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Basic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Basic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Basic + static TextTheme basicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.basic(textStyle: textTheme.headline1), + headline2: GoogleFonts.basic(textStyle: textTheme.headline2), + headline3: GoogleFonts.basic(textStyle: textTheme.headline3), + headline4: GoogleFonts.basic(textStyle: textTheme.headline4), + headline5: GoogleFonts.basic(textStyle: textTheme.headline5), + headline6: GoogleFonts.basic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.basic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.basic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.basic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.basic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.basic(textStyle: textTheme.caption), + button: GoogleFonts.basic(textStyle: textTheme.button), + overline: GoogleFonts.basic(textStyle: textTheme.overline), + ); + } + + /// Applies the Baskervville font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baskervville + static TextStyle baskervville({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4f83292ed3ada742c822e6b55c57b05a68a0d27b136b872ed2cb3edaf2dd778c', + 46788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fdcacb6cacae51af7ce0b4bc57b4400feedcf38a9e21898b144205607cd15185', + 48936, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Baskervville', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baskervville font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baskervville + static TextTheme baskervvilleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.baskervville(textStyle: textTheme.headline1), + headline2: GoogleFonts.baskervville(textStyle: textTheme.headline2), + headline3: GoogleFonts.baskervville(textStyle: textTheme.headline3), + headline4: GoogleFonts.baskervville(textStyle: textTheme.headline4), + headline5: GoogleFonts.baskervville(textStyle: textTheme.headline5), + headline6: GoogleFonts.baskervville(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.baskervville(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.baskervville(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.baskervville(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.baskervville(textStyle: textTheme.bodyText2), + caption: GoogleFonts.baskervville(textStyle: textTheme.caption), + button: GoogleFonts.baskervville(textStyle: textTheme.button), + overline: GoogleFonts.baskervville(textStyle: textTheme.overline), + ); + } + + /// Applies the Baumans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baumans + static TextStyle baumans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9f9e8b94de7e96a118ae0165a927ffde8127bb9105f38bc5c39359622c7c40f4', + 38752, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Baumans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Baumans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Baumans + static TextTheme baumansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.baumans(textStyle: textTheme.headline1), + headline2: GoogleFonts.baumans(textStyle: textTheme.headline2), + headline3: GoogleFonts.baumans(textStyle: textTheme.headline3), + headline4: GoogleFonts.baumans(textStyle: textTheme.headline4), + headline5: GoogleFonts.baumans(textStyle: textTheme.headline5), + headline6: GoogleFonts.baumans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.baumans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.baumans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.baumans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.baumans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.baumans(textStyle: textTheme.caption), + button: GoogleFonts.baumans(textStyle: textTheme.button), + overline: GoogleFonts.baumans(textStyle: textTheme.overline), + ); + } + + /// Applies the Be Vietnam font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Be+Vietnam + static TextStyle beVietnam({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0cc0f5cd392e42154ccdcf1ffc6987159ee0807caf89c6ac0796a273c9c80cd4', + 43452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '11b1d7f41abb8a24b4ba203416df07809dbaf7de51619a1d167ab9af0361b6b7', + 44588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '03d32b9f1d2ddaa56a41075b22ab477cbc078409bda7fe7f7e030491bf70988a', + 43992, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a46d7c089e1fe8c124bc2de7b2cdf8a7f23fc0e9724766f3029c5c528b88b2cf', + 45400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '79220c67d8f8488a5dc457833419e884bef66e01eae43ec9c9b7e2944c5d88f0', + 43896, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e2928c1924824c824cac4ddaa74885a1fb9f3723429fa145c579cde5e79eeba5', + 45368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8d504a978c86a628884d737bacc817b24a74963f8e36e6cab5e9b81b9977b1f4', + 43948, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a2af11a383bfb3ee1ef8731946b78f349dce66a9151e6724f9428a29af43faac', + 45316, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '94efd29230ff40c08cd89d8ae44d0e847ad17d53088280868a4bfbe29bc9afe0', + 43864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2e18bd0f37b3e15856f513a8bd6b5d019948460f502359bf06716759b5b07664', + 45424, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6f6fdb78c7c80b7871c787918369b6f9908cb55d29a6f68602b90d557a0ef839', + 43720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c54104de856f3762629b69585ceb0eed536f7f7a19d2a2e1cdb44c1b1398e6b8', + 45380, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '920f1f8cbfb2d9b94b66296e1f4ddf430a02ce638be482c79c598832645fda13', + 43640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2140e6025b6df417db0a543e64c090a9a5aa119d7523fd43a5f806a1550bdb37', + 45296, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BeVietnam', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Be Vietnam font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Be+Vietnam + static TextTheme beVietnamTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.beVietnam(textStyle: textTheme.headline1), + headline2: GoogleFonts.beVietnam(textStyle: textTheme.headline2), + headline3: GoogleFonts.beVietnam(textStyle: textTheme.headline3), + headline4: GoogleFonts.beVietnam(textStyle: textTheme.headline4), + headline5: GoogleFonts.beVietnam(textStyle: textTheme.headline5), + headline6: GoogleFonts.beVietnam(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.beVietnam(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.beVietnam(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.beVietnam(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.beVietnam(textStyle: textTheme.bodyText2), + caption: GoogleFonts.beVietnam(textStyle: textTheme.caption), + button: GoogleFonts.beVietnam(textStyle: textTheme.button), + overline: GoogleFonts.beVietnam(textStyle: textTheme.overline), + ); + } + + /// Applies the Bebas Neue font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bebas+Neue + static TextStyle bebasNeue({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bd16210fc689a14930beb51e89f3890e3167bdb105c0e7618abb62d6c4a2cc5d', + 37392, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BebasNeue', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bebas Neue font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bebas+Neue + static TextTheme bebasNeueTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bebasNeue(textStyle: textTheme.headline1), + headline2: GoogleFonts.bebasNeue(textStyle: textTheme.headline2), + headline3: GoogleFonts.bebasNeue(textStyle: textTheme.headline3), + headline4: GoogleFonts.bebasNeue(textStyle: textTheme.headline4), + headline5: GoogleFonts.bebasNeue(textStyle: textTheme.headline5), + headline6: GoogleFonts.bebasNeue(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bebasNeue(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bebasNeue(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bebasNeue(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bebasNeue(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bebasNeue(textStyle: textTheme.caption), + button: GoogleFonts.bebasNeue(textStyle: textTheme.button), + overline: GoogleFonts.bebasNeue(textStyle: textTheme.overline), + ); + } + + /// Applies the Belgrano font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Belgrano + static TextStyle belgrano({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4b66b889e699bfe12ea9cc04621e48eed308f79ef2955cd4f20d0e7ddbcbaeab', + 29028, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Belgrano', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Belgrano font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Belgrano + static TextTheme belgranoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.belgrano(textStyle: textTheme.headline1), + headline2: GoogleFonts.belgrano(textStyle: textTheme.headline2), + headline3: GoogleFonts.belgrano(textStyle: textTheme.headline3), + headline4: GoogleFonts.belgrano(textStyle: textTheme.headline4), + headline5: GoogleFonts.belgrano(textStyle: textTheme.headline5), + headline6: GoogleFonts.belgrano(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.belgrano(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.belgrano(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.belgrano(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.belgrano(textStyle: textTheme.bodyText2), + caption: GoogleFonts.belgrano(textStyle: textTheme.caption), + button: GoogleFonts.belgrano(textStyle: textTheme.button), + overline: GoogleFonts.belgrano(textStyle: textTheme.overline), + ); + } + + /// Applies the Bellefair font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bellefair + static TextStyle bellefair({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '581fd752c6fe9933425b7868917fe51b6d222b42336b931e58385cea219007a0', + 46492, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bellefair', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bellefair font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bellefair + static TextTheme bellefairTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bellefair(textStyle: textTheme.headline1), + headline2: GoogleFonts.bellefair(textStyle: textTheme.headline2), + headline3: GoogleFonts.bellefair(textStyle: textTheme.headline3), + headline4: GoogleFonts.bellefair(textStyle: textTheme.headline4), + headline5: GoogleFonts.bellefair(textStyle: textTheme.headline5), + headline6: GoogleFonts.bellefair(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bellefair(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bellefair(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bellefair(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bellefair(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bellefair(textStyle: textTheme.caption), + button: GoogleFonts.bellefair(textStyle: textTheme.button), + overline: GoogleFonts.bellefair(textStyle: textTheme.overline), + ); + } + + /// Applies the Belleza font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Belleza + static TextStyle belleza({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '916c38d3ec21ba4e080cbb7c82b60f62b023224acf789357a9338460a610def2', + 27772, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Belleza', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Belleza font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Belleza + static TextTheme bellezaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.belleza(textStyle: textTheme.headline1), + headline2: GoogleFonts.belleza(textStyle: textTheme.headline2), + headline3: GoogleFonts.belleza(textStyle: textTheme.headline3), + headline4: GoogleFonts.belleza(textStyle: textTheme.headline4), + headline5: GoogleFonts.belleza(textStyle: textTheme.headline5), + headline6: GoogleFonts.belleza(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.belleza(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.belleza(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.belleza(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.belleza(textStyle: textTheme.bodyText2), + caption: GoogleFonts.belleza(textStyle: textTheme.caption), + button: GoogleFonts.belleza(textStyle: textTheme.button), + overline: GoogleFonts.belleza(textStyle: textTheme.overline), + ); + } + + /// Applies the Bellota font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bellota + static TextStyle bellota({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '29b1164370f0eca544e3c2cb64f06324bd098c99c35f5ecdd5527d6642e5a78f', + 87324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2876a1892bc886d0df661eef1cc4fd3273dc8bce9563d1a7fba2c72987e340c5', + 90184, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0ae1ca7fd73a6c369b6bf3b7326788cb2a360b467fa83a298140dac4166b8efa', + 86996, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd628b046cfc942ee35db112226b78f9ac3973ccaf005074bbbe867656201b8ec', + 89836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ac23e7ab6ffb89ee1593424695c867b8150bd97cd85fdbe2a3d7f89bf32a0973', + 87220, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e876bb51e7fba1f8fadcef59f4b68e3020a0909557cef70a98c84253c9e32f2f', + 90052, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bellota', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bellota font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bellota + static TextTheme bellotaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bellota(textStyle: textTheme.headline1), + headline2: GoogleFonts.bellota(textStyle: textTheme.headline2), + headline3: GoogleFonts.bellota(textStyle: textTheme.headline3), + headline4: GoogleFonts.bellota(textStyle: textTheme.headline4), + headline5: GoogleFonts.bellota(textStyle: textTheme.headline5), + headline6: GoogleFonts.bellota(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bellota(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bellota(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bellota(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bellota(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bellota(textStyle: textTheme.caption), + button: GoogleFonts.bellota(textStyle: textTheme.button), + overline: GoogleFonts.bellota(textStyle: textTheme.overline), + ); + } + + /// Applies the Bellota Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bellota+Text + static TextStyle bellotaText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a0643b4ed7b9e5fe0a6023e98e3c731ac5ed3dd6a93688e6d319415902455806', + 85396, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e0b3916debc6fdfc7a7fd3129785215a68039360ca58fff2137a5855ee962138', + 88396, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bd71701b5f03e11645c6c76521346bb0658b950d8e568f92dbad4c0f832775eb', + 85276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cab1408381b8c09a1322d14913d773a9ecd2af835363efced81df2db8aa5107b', + 88112, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4c08136cdca5423cf6e4f79255b1d8968b3ce107c396b03445f6c49c286dd349', + 85352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ec9c1edafbe6c75409ba2200628821ee1f0dbad581d6f79db100aeb366b12ee4', + 88192, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BellotaText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bellota Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bellota+Text + static TextTheme bellotaTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bellotaText(textStyle: textTheme.headline1), + headline2: GoogleFonts.bellotaText(textStyle: textTheme.headline2), + headline3: GoogleFonts.bellotaText(textStyle: textTheme.headline3), + headline4: GoogleFonts.bellotaText(textStyle: textTheme.headline4), + headline5: GoogleFonts.bellotaText(textStyle: textTheme.headline5), + headline6: GoogleFonts.bellotaText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bellotaText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bellotaText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bellotaText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bellotaText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bellotaText(textStyle: textTheme.caption), + button: GoogleFonts.bellotaText(textStyle: textTheme.button), + overline: GoogleFonts.bellotaText(textStyle: textTheme.overline), + ); + } + + /// Applies the BenchNine font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/BenchNine + static TextStyle benchNine({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '819e7479fd3310e52e9754666e7a85aae97b6ea92363f425c93d1763341c5720', + 38056, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6ff13f62cc4e1011ea688bc0bdad0ec34826a3c14cbc1b9ec0ed2b768a756be1', + 38812, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ad7761d772dd04c7cf6c3ea55ea6f5bc9ca1540a2961a12251b37aee5d067022', + 38748, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BenchNine', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the BenchNine font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/BenchNine + static TextTheme benchNineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.benchNine(textStyle: textTheme.headline1), + headline2: GoogleFonts.benchNine(textStyle: textTheme.headline2), + headline3: GoogleFonts.benchNine(textStyle: textTheme.headline3), + headline4: GoogleFonts.benchNine(textStyle: textTheme.headline4), + headline5: GoogleFonts.benchNine(textStyle: textTheme.headline5), + headline6: GoogleFonts.benchNine(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.benchNine(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.benchNine(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.benchNine(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.benchNine(textStyle: textTheme.bodyText2), + caption: GoogleFonts.benchNine(textStyle: textTheme.caption), + button: GoogleFonts.benchNine(textStyle: textTheme.button), + overline: GoogleFonts.benchNine(textStyle: textTheme.overline), + ); + } + + /// Applies the Bentham font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bentham + static TextStyle bentham({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '36b9c399aae73bd09e01d76e51e8697f80e9e34f14e954b929a08d6cfbc5f697', + 40176, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bentham', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bentham font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bentham + static TextTheme benthamTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bentham(textStyle: textTheme.headline1), + headline2: GoogleFonts.bentham(textStyle: textTheme.headline2), + headline3: GoogleFonts.bentham(textStyle: textTheme.headline3), + headline4: GoogleFonts.bentham(textStyle: textTheme.headline4), + headline5: GoogleFonts.bentham(textStyle: textTheme.headline5), + headline6: GoogleFonts.bentham(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bentham(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bentham(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bentham(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bentham(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bentham(textStyle: textTheme.caption), + button: GoogleFonts.bentham(textStyle: textTheme.button), + overline: GoogleFonts.bentham(textStyle: textTheme.overline), + ); + } + + /// Applies the Berkshire Swash font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Berkshire+Swash + static TextStyle berkshireSwash({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2e73eb938ce44215938a21b199bc0a7eba8e1805d0d2528c3300ad7a1813d5e0', + 57948, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BerkshireSwash', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Berkshire Swash font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Berkshire+Swash + static TextTheme berkshireSwashTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.berkshireSwash(textStyle: textTheme.headline1), + headline2: GoogleFonts.berkshireSwash(textStyle: textTheme.headline2), + headline3: GoogleFonts.berkshireSwash(textStyle: textTheme.headline3), + headline4: GoogleFonts.berkshireSwash(textStyle: textTheme.headline4), + headline5: GoogleFonts.berkshireSwash(textStyle: textTheme.headline5), + headline6: GoogleFonts.berkshireSwash(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.berkshireSwash(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.berkshireSwash(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.berkshireSwash(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.berkshireSwash(textStyle: textTheme.bodyText2), + caption: GoogleFonts.berkshireSwash(textStyle: textTheme.caption), + button: GoogleFonts.berkshireSwash(textStyle: textTheme.button), + overline: GoogleFonts.berkshireSwash(textStyle: textTheme.overline), + ); + } + + /// Applies the Beth Ellen font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Beth+Ellen + static TextStyle bethEllen({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '33f7d9b097ad741e56ef314b447fa4e0d310aab981ba6aea5db368053b65bc56', + 115600, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BethEllen', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Beth Ellen font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Beth+Ellen + static TextTheme bethEllenTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bethEllen(textStyle: textTheme.headline1), + headline2: GoogleFonts.bethEllen(textStyle: textTheme.headline2), + headline3: GoogleFonts.bethEllen(textStyle: textTheme.headline3), + headline4: GoogleFonts.bethEllen(textStyle: textTheme.headline4), + headline5: GoogleFonts.bethEllen(textStyle: textTheme.headline5), + headline6: GoogleFonts.bethEllen(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bethEllen(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bethEllen(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bethEllen(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bethEllen(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bethEllen(textStyle: textTheme.caption), + button: GoogleFonts.bethEllen(textStyle: textTheme.button), + overline: GoogleFonts.bethEllen(textStyle: textTheme.overline), + ); + } + + /// Applies the Bevan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bevan + static TextStyle bevan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '95fb9ca931c31e79c8312fb66d76a2239472f842f9aeed9c261367a55723370f', + 55536, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bevan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bevan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bevan + static TextTheme bevanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bevan(textStyle: textTheme.headline1), + headline2: GoogleFonts.bevan(textStyle: textTheme.headline2), + headline3: GoogleFonts.bevan(textStyle: textTheme.headline3), + headline4: GoogleFonts.bevan(textStyle: textTheme.headline4), + headline5: GoogleFonts.bevan(textStyle: textTheme.headline5), + headline6: GoogleFonts.bevan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bevan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bevan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bevan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bevan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bevan(textStyle: textTheme.caption), + button: GoogleFonts.bevan(textStyle: textTheme.button), + overline: GoogleFonts.bevan(textStyle: textTheme.overline), + ); + } + + /// Applies the Big Shoulders Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Display + static TextStyle bigShouldersDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '243bc59e9459b35c35fa0bc5cc49219e1cbf248be840664569ca730a8a7a7e5e', + 60384, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f9d601dd24fc0f4bb73ca5a9bc3fb23c2d744597df0f10a2894d566903ba1154', + 64044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0d1c3a1a7aca284022f6d11318ac148fe815d11c400a02d20e25768bbcf17f16', + 63888, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '782f7156f414a376945013c065917553e525e9f55dc801588c0f2f47406a51a3', + 63824, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'abf50d14f1c83beca50dbf4875c46279d06f2120f997bd0b3670236cf24bf1aa', + 63924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '908c135c2591d12f000c0af1d59e56e72fb77beb39c1ba091505f250575b4ea6', + 63876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '19b8e205eb51647a9245e28993f1aa99df1cdc107cab1e823db05dce048363ca', + 63916, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '71c2e1ad1b8e3abbf78e31165b5b054095b45b80cdd32410b9df8abaa45a631f', + 65188, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BigShouldersDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Big Shoulders Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Display + static TextTheme bigShouldersDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.headline1), + headline2: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.headline2), + headline3: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.headline3), + headline4: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.headline4), + headline5: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.headline5), + headline6: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.bigShouldersDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bigShouldersDisplay(textStyle: textTheme.caption), + button: GoogleFonts.bigShouldersDisplay(textStyle: textTheme.button), + overline: GoogleFonts.bigShouldersDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Big Shoulders Inline Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Inline+Display + static TextStyle bigShouldersInlineDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cecd28ac71e6d26fe426d809a967ca89fd34ebf00666daf5e72be698043690f8', + 98144, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3710b6162121414170f4ee83003c9a801a07d3a8b78f6abbab39e670edc08a0b', + 99972, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '45fd384c9df07fc26138ac660041a108fad83e7e900169cd69ff9e1ff683c79e', + 100792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4485432c8a8581e0b3f3b507691b848e4673ba5d3606ccc8c51d573b9950d995', + 101060, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8429a118926e0997b6894777f001d3c63d792b7b82f9bbd3ee909b393e049c73', + 101340, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '80e5e506aebe63f25614ef4b8b1a69935d750ff148abb1ed248d7c94b23cfb19', + 101752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e1b12519d38230d280f84445cb7e50edb127c715cdd6fb9e7697e29f7f77a0bf', + 102272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d986bf2e9666f76e4a791c20a4aa9255ec6f92d62eac8c45365f456e9b64bc1', + 102192, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BigShouldersInlineDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Big Shoulders Inline Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Inline+Display + static TextTheme bigShouldersInlineDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.headline1), + headline2: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.headline2), + headline3: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.headline3), + headline4: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.headline4), + headline5: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.headline5), + headline6: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.bodyText2), + caption: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.caption), + button: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.button), + overline: + GoogleFonts.bigShouldersInlineDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Big Shoulders Inline Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Inline+Text + static TextStyle bigShouldersInlineText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '914a99a3f7a36509645da4d56298db3eaf53f8fe091adc6f511305a5b5415d94', + 98832, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a4e1ca3362feca7026abcdc3f6cd27be00d437bdca4963451e70f627fc47285e', + 100608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8171ef16c4d2ccf81271d6bb77a9a25723b54e3033e75e930b47738e9f8f738c', + 101584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '07dddac8ecdf608d7eecb9031c91626e78dc9e0721d6e3861ce58cd5b205d8a7', + 101584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b3e3a0152deb77bbf594da21360ad2cd1012e94424ef6fb664f876cbeec5ee45', + 101692, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a0a7d5ffddfee40b18b44e3f89aac2801f82ed5cabcc11e6707b05525a55d3bb', + 102024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '26b8f325b1bcca1f6b88728184699789e3bf7ec260804d04421b5db694ae4157', + 102752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0169fdfd36818b76f6f2182152276acbf8129be7a3e4d0ad77755b6d069acb71', + 102380, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BigShouldersInlineText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Big Shoulders Inline Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Inline+Text + static TextTheme bigShouldersInlineTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.headline1), + headline2: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.headline2), + headline3: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.headline3), + headline4: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.headline4), + headline5: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.headline5), + headline6: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bigShouldersInlineText(textStyle: textTheme.caption), + button: GoogleFonts.bigShouldersInlineText(textStyle: textTheme.button), + overline: + GoogleFonts.bigShouldersInlineText(textStyle: textTheme.overline), + ); + } + + /// Applies the Big Shoulders Stencil Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Stencil+Display + static TextStyle bigShouldersStencilDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e745115111f02d5a11cdf1328f3eecff1bb5f775cb0f2b06b4d8f24b196ac32e', + 57612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0f312a4998a7fdb735ce3e5c2cebb4c88987d6b221039c3ec51117af72a7a92d', + 59556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3b8e0ce085bdd03707db89704d38ea6f6523ee0a6dc14dbe5e41ca65b3266958', + 59596, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d0ca21a6f86141b1d824eecc8a4b221e2f9b0a2d99c35b4b8da6132324a2431', + 59536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1c5b5b3228b0893035ab61f43b1666de4e2ac70346c6b5a0af6212dc881b2895', + 59488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f18fa1842c04a9bb7b65cd8865d8db3ad6129de5aba757f7dac332de21e2e557', + 59548, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '999379e5037b63a0d57539a9aa7b10a200910a43531557a752265827a074c079', + 59848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6055fdd83b00cf395678263ba7a8d07c043046f85db67776ca586dfd72ced1a5', + 59592, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BigShouldersStencilDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Big Shoulders Stencil Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Stencil+Display + static TextTheme bigShouldersStencilDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.headline1), + headline2: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.headline2), + headline3: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.headline3), + headline4: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.headline4), + headline5: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.headline5), + headline6: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bigShouldersStencilDisplay( + textStyle: textTheme.bodyText2), + caption: + GoogleFonts.bigShouldersStencilDisplay(textStyle: textTheme.caption), + button: + GoogleFonts.bigShouldersStencilDisplay(textStyle: textTheme.button), + overline: + GoogleFonts.bigShouldersStencilDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Big Shoulders Stencil Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Stencil+Text + static TextStyle bigShouldersStencilText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ce5239dead961193d7ed14ae8ad117d8ac7c38b3004ce5268f79858cb05dff20', + 58792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b72cc9791d7c353499dd3cdd8cb057f1b737306474a92e64d32b94e60e63300a', + 60148, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1c3218546f3f3c56203170cf14894c6b0f93024f0759022205174bd64fe18b52', + 60140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0b32127d757a06294d75c04041ebf65257d3b861075010b125b52b1872f0164a', + 60000, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f502e0a1bfb3a7c94c8bd1d80fce760f9dbc080b53d928803846e0705859c342', + 59900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3e82a1e08ebbaaabd1a452bd3461bc4174ec94b641c99774dd41a1d552de12a7', + 59980, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '814371b884bf588132731087f41533e3852bfa4953739fca42c71fcba588f073', + 59980, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4b6e75385f85cfb30647c3935bf4ed6f0dfad6012a0a38bad71cf46c32d2d9ce', + 59508, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BigShouldersStencilText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Big Shoulders Stencil Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Stencil+Text + static TextTheme bigShouldersStencilTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.headline1), + headline2: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.headline2), + headline3: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.headline3), + headline4: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.headline4), + headline5: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.headline5), + headline6: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.bodyText2), + caption: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.caption), + button: GoogleFonts.bigShouldersStencilText(textStyle: textTheme.button), + overline: + GoogleFonts.bigShouldersStencilText(textStyle: textTheme.overline), + ); + } + + /// Applies the Big Shoulders Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Text + static TextStyle bigShouldersText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '627d92b7b60e71b44920b0badb4fab35e76dc999346110b16b5503642b274d9c', + 60972, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8aef88ac2024c3940f399eee0642162cf1880de4b3072c385da26169385aaff9', + 64304, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3b28c250237404079c092e1f0bbe96a9877935f854758b23d0c596474d2dc0a9', + 64348, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ceadafc7d9e2a44c734bb0219be7688bb6f03e1d0788f1a6fdaff25989c7c821', + 64240, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '891fff63a87492e0329b1ad1261d5d60e1e276099f63a26b28497f66fddb1e58', + 64288, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '089e74d0e80e3f820d20c2dadb61e35e88025df110b9bfdf6878dd0c88300f35', + 64144, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c3090bbff39b913daac1ce49ed0afcd52cba93db2e114faba5840a983ff222f0', + 64208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6a6e0bec5c1e7d0a62882e4f6be1b781665211f69d499f61aa439ad6bb097e60', + 65320, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BigShouldersText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Big Shoulders Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Big+Shoulders+Text + static TextTheme bigShouldersTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bigShouldersText(textStyle: textTheme.headline1), + headline2: GoogleFonts.bigShouldersText(textStyle: textTheme.headline2), + headline3: GoogleFonts.bigShouldersText(textStyle: textTheme.headline3), + headline4: GoogleFonts.bigShouldersText(textStyle: textTheme.headline4), + headline5: GoogleFonts.bigShouldersText(textStyle: textTheme.headline5), + headline6: GoogleFonts.bigShouldersText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bigShouldersText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bigShouldersText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bigShouldersText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bigShouldersText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bigShouldersText(textStyle: textTheme.caption), + button: GoogleFonts.bigShouldersText(textStyle: textTheme.button), + overline: GoogleFonts.bigShouldersText(textStyle: textTheme.overline), + ); + } + + /// Applies the Bigelow Rules font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bigelow+Rules + static TextStyle bigelowRules({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b86229b1bc741bc11ef0517467d96769485504f74278c1011120697a17d74d26', + 59028, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BigelowRules', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bigelow Rules font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bigelow+Rules + static TextTheme bigelowRulesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bigelowRules(textStyle: textTheme.headline1), + headline2: GoogleFonts.bigelowRules(textStyle: textTheme.headline2), + headline3: GoogleFonts.bigelowRules(textStyle: textTheme.headline3), + headline4: GoogleFonts.bigelowRules(textStyle: textTheme.headline4), + headline5: GoogleFonts.bigelowRules(textStyle: textTheme.headline5), + headline6: GoogleFonts.bigelowRules(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bigelowRules(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bigelowRules(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bigelowRules(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bigelowRules(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bigelowRules(textStyle: textTheme.caption), + button: GoogleFonts.bigelowRules(textStyle: textTheme.button), + overline: GoogleFonts.bigelowRules(textStyle: textTheme.overline), + ); + } + + /// Applies the Bigshot One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bigshot+One + static TextStyle bigshotOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cd6b11ed5794f665b3e412e676ae624b63b086b93992d6c0b00c9afd26180c79', + 36972, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BigshotOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bigshot One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bigshot+One + static TextTheme bigshotOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bigshotOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.bigshotOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.bigshotOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.bigshotOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.bigshotOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.bigshotOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bigshotOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bigshotOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bigshotOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bigshotOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bigshotOne(textStyle: textTheme.caption), + button: GoogleFonts.bigshotOne(textStyle: textTheme.button), + overline: GoogleFonts.bigshotOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Bilbo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bilbo + static TextStyle bilbo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '55d2e6fb7257d5ade5d2419927eebf1f0c78ba65154b64d0cb737b6c8fa6a7df', + 42864, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bilbo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bilbo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bilbo + static TextTheme bilboTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bilbo(textStyle: textTheme.headline1), + headline2: GoogleFonts.bilbo(textStyle: textTheme.headline2), + headline3: GoogleFonts.bilbo(textStyle: textTheme.headline3), + headline4: GoogleFonts.bilbo(textStyle: textTheme.headline4), + headline5: GoogleFonts.bilbo(textStyle: textTheme.headline5), + headline6: GoogleFonts.bilbo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bilbo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bilbo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bilbo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bilbo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bilbo(textStyle: textTheme.caption), + button: GoogleFonts.bilbo(textStyle: textTheme.button), + overline: GoogleFonts.bilbo(textStyle: textTheme.overline), + ); + } + + /// Applies the Bilbo Swash Caps font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bilbo+Swash+Caps + static TextStyle bilboSwashCaps({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e55126acc93a6cae98b3736d06e24e1301a26f9aa4ac2173998ab1fa142b1736', + 58124, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BilboSwashCaps', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bilbo Swash Caps font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bilbo+Swash+Caps + static TextTheme bilboSwashCapsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bilboSwashCaps(textStyle: textTheme.headline1), + headline2: GoogleFonts.bilboSwashCaps(textStyle: textTheme.headline2), + headline3: GoogleFonts.bilboSwashCaps(textStyle: textTheme.headline3), + headline4: GoogleFonts.bilboSwashCaps(textStyle: textTheme.headline4), + headline5: GoogleFonts.bilboSwashCaps(textStyle: textTheme.headline5), + headline6: GoogleFonts.bilboSwashCaps(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bilboSwashCaps(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bilboSwashCaps(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bilboSwashCaps(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bilboSwashCaps(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bilboSwashCaps(textStyle: textTheme.caption), + button: GoogleFonts.bilboSwashCaps(textStyle: textTheme.button), + overline: GoogleFonts.bilboSwashCaps(textStyle: textTheme.overline), + ); + } + + /// Applies the BioRhyme font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/BioRhyme + static TextStyle bioRhyme({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8c7047e02059b7ea10893cf7bcfe3dc06e450dd3fb6000e05171462fedc43f7e', + 69848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b9ee5307ca507a88bed949ef452d4b6c835e503ef09b30cbb1ace6d65030e873', + 72476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bfe90585ffc1c3fc0d661d75c86187e9b6176836b56026b7882465f43a328616', + 71764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cd56fec3e00f732e0ff393a16cd304a5b4818b7b5bc437e4f418142a976284e6', + 71756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '43c38cd7da3c0c61638db3dbfd450b28e4abcacc9a48011176274140cf681c2b', + 68792, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BioRhyme', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the BioRhyme font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/BioRhyme + static TextTheme bioRhymeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bioRhyme(textStyle: textTheme.headline1), + headline2: GoogleFonts.bioRhyme(textStyle: textTheme.headline2), + headline3: GoogleFonts.bioRhyme(textStyle: textTheme.headline3), + headline4: GoogleFonts.bioRhyme(textStyle: textTheme.headline4), + headline5: GoogleFonts.bioRhyme(textStyle: textTheme.headline5), + headline6: GoogleFonts.bioRhyme(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bioRhyme(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bioRhyme(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bioRhyme(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bioRhyme(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bioRhyme(textStyle: textTheme.caption), + button: GoogleFonts.bioRhyme(textStyle: textTheme.button), + overline: GoogleFonts.bioRhyme(textStyle: textTheme.overline), + ); + } + + /// Applies the BioRhyme Expanded font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/BioRhyme+Expanded + static TextStyle bioRhymeExpanded({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7770459b3448470de7eebc842dd6d1b27857480f955caa6fda9114f30f9c487a', + 69024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '564af9bc89e9baac8c99c4a2b2bb1262ed16deaec1971840ab3e348ed0dc8e22', + 72648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1fa6003a77f1c41cfe89fc6db7c98358f0e6fa62b61c965e0e1a04ed960601b9', + 72028, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '89375361cdabf9dbf2e57378fa40cc8c19512e518617d5e8502c9db8aa4ee2a1', + 71960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '586a8d74b8042767a173971c026734fb6cb75934497b3c9d2ebd80ad9e60c31d', + 71188, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BioRhymeExpanded', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the BioRhyme Expanded font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/BioRhyme+Expanded + static TextTheme bioRhymeExpandedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.headline1), + headline2: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.headline2), + headline3: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.headline3), + headline4: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.headline4), + headline5: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.headline5), + headline6: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.caption), + button: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.button), + overline: GoogleFonts.bioRhymeExpanded(textStyle: textTheme.overline), + ); + } + + /// Applies the Biryani font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Biryani + static TextStyle biryani({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f65303a20787e99a61c757c6e4cbc9ee68af544a375dac932049def734163642', + 123500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '842f2d86cd486de76ca080714383fb99a105dfb85b3bae4360d00e8ac8db8c9f', + 124924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '16e70205340aba8294e2da2cc8581ec3c5fb3f2af846d51a3de360f447d6f254', + 124200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '80169a7f1fadd79859c89b0e9a066fd8dbbc460f13a4e5df8389cd853dc67be9', + 124224, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8834894534eb39412acdbc906f20b8d4addd5339d6777eaf647ee1ecbd44538c', + 123988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba9bcb5882f72d4ac114689fb32db356c2be660bc64a16c88ac2457bdbefd777', + 124032, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5bad25e5e05861d1da7ddd858aefac18d200688fc997bf2760059fcc2c2ad30d', + 123080, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Biryani', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Biryani font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Biryani + static TextTheme biryaniTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.biryani(textStyle: textTheme.headline1), + headline2: GoogleFonts.biryani(textStyle: textTheme.headline2), + headline3: GoogleFonts.biryani(textStyle: textTheme.headline3), + headline4: GoogleFonts.biryani(textStyle: textTheme.headline4), + headline5: GoogleFonts.biryani(textStyle: textTheme.headline5), + headline6: GoogleFonts.biryani(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.biryani(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.biryani(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.biryani(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.biryani(textStyle: textTheme.bodyText2), + caption: GoogleFonts.biryani(textStyle: textTheme.caption), + button: GoogleFonts.biryani(textStyle: textTheme.button), + overline: GoogleFonts.biryani(textStyle: textTheme.overline), + ); + } + + /// Applies the Bitter font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bitter + static TextStyle bitter({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '937e0cb8bbc92b1b89eafc86f73c06dec677f4e8d2c39de72208ae4fffedc7fa', + 24208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7a9ae7d2a6428de7df36662a7014e91b880c5d09663ae9c66abb8a928c0ad371', + 39064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c41cd10ef080e4d415bc6da6d86b29b73fe87ba84afe455423476109ed6addbd', + 25616, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bitter', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bitter font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bitter + static TextTheme bitterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bitter(textStyle: textTheme.headline1), + headline2: GoogleFonts.bitter(textStyle: textTheme.headline2), + headline3: GoogleFonts.bitter(textStyle: textTheme.headline3), + headline4: GoogleFonts.bitter(textStyle: textTheme.headline4), + headline5: GoogleFonts.bitter(textStyle: textTheme.headline5), + headline6: GoogleFonts.bitter(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bitter(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bitter(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bitter(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bitter(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bitter(textStyle: textTheme.caption), + button: GoogleFonts.bitter(textStyle: textTheme.button), + overline: GoogleFonts.bitter(textStyle: textTheme.overline), + ); + } + + /// Applies the Black And White Picture font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Black+And+White+Picture + static TextStyle blackAndWhitePicture({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0c951e047e8f1e152232363c35791b975f78ae96c97bfa6f14634c7a2551970c', + 9586680, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BlackAndWhitePicture', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Black And White Picture font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Black+And+White+Picture + static TextTheme blackAndWhitePictureTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.headline1), + headline2: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.headline2), + headline3: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.headline3), + headline4: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.headline4), + headline5: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.headline5), + headline6: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.blackAndWhitePicture(textStyle: textTheme.bodyText2), + caption: GoogleFonts.blackAndWhitePicture(textStyle: textTheme.caption), + button: GoogleFonts.blackAndWhitePicture(textStyle: textTheme.button), + overline: GoogleFonts.blackAndWhitePicture(textStyle: textTheme.overline), + ); + } + + /// Applies the Black Han Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Black+Han+Sans + static TextStyle blackHanSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ea3e07623642e89ce9ae84a698b9557dd6361db9bc40b993b7715531404db088', + 382952, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BlackHanSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Black Han Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Black+Han+Sans + static TextTheme blackHanSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.blackHanSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.blackHanSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.blackHanSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.blackHanSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.blackHanSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.blackHanSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.blackHanSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.blackHanSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.blackHanSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.blackHanSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.blackHanSans(textStyle: textTheme.caption), + button: GoogleFonts.blackHanSans(textStyle: textTheme.button), + overline: GoogleFonts.blackHanSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Black Ops One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Black+Ops+One + static TextStyle blackOpsOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9a9eebffdb4d3c168c63bfcd5d0ec80a1571160a66e46ef698786f9c56922256', + 41404, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BlackOpsOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Black Ops One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Black+Ops+One + static TextTheme blackOpsOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.blackOpsOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.blackOpsOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.blackOpsOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.blackOpsOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.blackOpsOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.blackOpsOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.blackOpsOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.blackOpsOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.blackOpsOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.blackOpsOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.blackOpsOne(textStyle: textTheme.caption), + button: GoogleFonts.blackOpsOne(textStyle: textTheme.button), + overline: GoogleFonts.blackOpsOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Blinker font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Blinker + static TextStyle blinker({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7c240948a3fc8d5d8689c3a63f7f8ebc6306f7c85e807823569843f0f54195f9', + 47168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2a79a8324609cc2b3bcdaec6541902337b886042ed55c471dbb6f257c65b280f', + 48596, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3dd96a764325a06a02dcd84be7a03f3a2f2b6808e40d63328015690bf81f6c96', + 48440, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '51b0da89566f911a7458b35be7b50dd97cb0ac23dff1eeb067b4d64a79911f3c', + 47676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a51856bff19a13b746d4d2d4b3ebb07157b40df14a94c526837c9e5586337f01', + 53416, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6eba9015f99f6f510f713d65f3f324ba543c2e9d3bc5eac9cbdd446b738eda1f', + 48892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd898f7f6b1fb3ed914d6dfaa20bc29b0f94d293822df46b2a78b5759f2637549', + 53068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d02003dcc4ca64b3de96560fffcdd9e05125270589caabebc0da78d05d0f61e', + 52352, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Blinker', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Blinker font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Blinker + static TextTheme blinkerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.blinker(textStyle: textTheme.headline1), + headline2: GoogleFonts.blinker(textStyle: textTheme.headline2), + headline3: GoogleFonts.blinker(textStyle: textTheme.headline3), + headline4: GoogleFonts.blinker(textStyle: textTheme.headline4), + headline5: GoogleFonts.blinker(textStyle: textTheme.headline5), + headline6: GoogleFonts.blinker(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.blinker(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.blinker(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.blinker(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.blinker(textStyle: textTheme.bodyText2), + caption: GoogleFonts.blinker(textStyle: textTheme.caption), + button: GoogleFonts.blinker(textStyle: textTheme.button), + overline: GoogleFonts.blinker(textStyle: textTheme.overline), + ); + } + + /// Applies the Bonbon font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bonbon + static TextStyle bonbon({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7c2ebdfc96584f15448c9196a29a7983cad1097756e748e6d3d89db0cab6796', + 38740, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bonbon', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bonbon font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bonbon + static TextTheme bonbonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bonbon(textStyle: textTheme.headline1), + headline2: GoogleFonts.bonbon(textStyle: textTheme.headline2), + headline3: GoogleFonts.bonbon(textStyle: textTheme.headline3), + headline4: GoogleFonts.bonbon(textStyle: textTheme.headline4), + headline5: GoogleFonts.bonbon(textStyle: textTheme.headline5), + headline6: GoogleFonts.bonbon(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bonbon(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bonbon(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bonbon(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bonbon(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bonbon(textStyle: textTheme.caption), + button: GoogleFonts.bonbon(textStyle: textTheme.button), + overline: GoogleFonts.bonbon(textStyle: textTheme.overline), + ); + } + + /// Applies the Boogaloo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Boogaloo + static TextStyle boogaloo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ecd8d89eafeb4669ce51f02cef4e529aa97180ed7c2a9cfcbad4714ed9ede46f', + 33880, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Boogaloo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Boogaloo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Boogaloo + static TextTheme boogalooTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.boogaloo(textStyle: textTheme.headline1), + headline2: GoogleFonts.boogaloo(textStyle: textTheme.headline2), + headline3: GoogleFonts.boogaloo(textStyle: textTheme.headline3), + headline4: GoogleFonts.boogaloo(textStyle: textTheme.headline4), + headline5: GoogleFonts.boogaloo(textStyle: textTheme.headline5), + headline6: GoogleFonts.boogaloo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.boogaloo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.boogaloo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.boogaloo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.boogaloo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.boogaloo(textStyle: textTheme.caption), + button: GoogleFonts.boogaloo(textStyle: textTheme.button), + overline: GoogleFonts.boogaloo(textStyle: textTheme.overline), + ); + } + + /// Applies the Bowlby One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bowlby+One + static TextStyle bowlbyOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d04430262e4d8e8e549ffcc4c97a27cb31ad26f9d2d85b2ba224381697b1a8d', + 61596, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BowlbyOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bowlby One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bowlby+One + static TextTheme bowlbyOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bowlbyOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.bowlbyOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.bowlbyOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.bowlbyOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.bowlbyOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.bowlbyOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bowlbyOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bowlbyOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bowlbyOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bowlbyOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bowlbyOne(textStyle: textTheme.caption), + button: GoogleFonts.bowlbyOne(textStyle: textTheme.button), + overline: GoogleFonts.bowlbyOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Bowlby One SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bowlby+One+SC + static TextStyle bowlbyOneSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e2826dfb2cc015f4d1a83c121524eff701bea716ad41719d21b0baaf0462abae', + 45072, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BowlbyOneSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bowlby One SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bowlby+One+SC + static TextTheme bowlbyOneScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bowlbyOneSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.bowlbyOneSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.bowlbyOneSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.bowlbyOneSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.bowlbyOneSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.bowlbyOneSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bowlbyOneSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bowlbyOneSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bowlbyOneSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bowlbyOneSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bowlbyOneSc(textStyle: textTheme.caption), + button: GoogleFonts.bowlbyOneSc(textStyle: textTheme.button), + overline: GoogleFonts.bowlbyOneSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Brawler font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Brawler + static TextStyle brawler({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '58683ec3f93abe0d96615faa1fc7fce9f3297205572a4c8c6265d0be27219279', + 64320, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Brawler', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Brawler font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Brawler + static TextTheme brawlerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.brawler(textStyle: textTheme.headline1), + headline2: GoogleFonts.brawler(textStyle: textTheme.headline2), + headline3: GoogleFonts.brawler(textStyle: textTheme.headline3), + headline4: GoogleFonts.brawler(textStyle: textTheme.headline4), + headline5: GoogleFonts.brawler(textStyle: textTheme.headline5), + headline6: GoogleFonts.brawler(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.brawler(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.brawler(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.brawler(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.brawler(textStyle: textTheme.bodyText2), + caption: GoogleFonts.brawler(textStyle: textTheme.caption), + button: GoogleFonts.brawler(textStyle: textTheme.button), + overline: GoogleFonts.brawler(textStyle: textTheme.overline), + ); + } + + /// Applies the Bree Serif font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bree+Serif + static TextStyle breeSerif({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9a7248ed16d47821a8836aa345a8297f6c44d86162fdbc6475497bc799db0e9f', + 46612, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BreeSerif', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bree Serif font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bree+Serif + static TextTheme breeSerifTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.breeSerif(textStyle: textTheme.headline1), + headline2: GoogleFonts.breeSerif(textStyle: textTheme.headline2), + headline3: GoogleFonts.breeSerif(textStyle: textTheme.headline3), + headline4: GoogleFonts.breeSerif(textStyle: textTheme.headline4), + headline5: GoogleFonts.breeSerif(textStyle: textTheme.headline5), + headline6: GoogleFonts.breeSerif(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.breeSerif(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.breeSerif(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.breeSerif(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.breeSerif(textStyle: textTheme.bodyText2), + caption: GoogleFonts.breeSerif(textStyle: textTheme.caption), + button: GoogleFonts.breeSerif(textStyle: textTheme.button), + overline: GoogleFonts.breeSerif(textStyle: textTheme.overline), + ); + } + + /// Applies the Bubblegum Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bubblegum+Sans + static TextStyle bubblegumSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '53e2f591d5b22787b4fd506e06145d2652da6014e1707f782a92395533188726', + 38772, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BubblegumSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bubblegum Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bubblegum+Sans + static TextTheme bubblegumSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bubblegumSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.bubblegumSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.bubblegumSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.bubblegumSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.bubblegumSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.bubblegumSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bubblegumSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bubblegumSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bubblegumSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bubblegumSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bubblegumSans(textStyle: textTheme.caption), + button: GoogleFonts.bubblegumSans(textStyle: textTheme.button), + overline: GoogleFonts.bubblegumSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Bubbler One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bubbler+One + static TextStyle bubblerOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fd7ed8791a88cc19effc14df166be456cef77a85b707501822da21df19386254', + 30944, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BubblerOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bubbler One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bubbler+One + static TextTheme bubblerOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bubblerOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.bubblerOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.bubblerOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.bubblerOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.bubblerOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.bubblerOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bubblerOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bubblerOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bubblerOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bubblerOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bubblerOne(textStyle: textTheme.caption), + button: GoogleFonts.bubblerOne(textStyle: textTheme.button), + overline: GoogleFonts.bubblerOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Buda font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Buda + static TextStyle buda({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '385d4247a0218281950ea513488d597434ce1d22bafe1b9e0b0853fce9304338', + 90392, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Buda', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Buda font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Buda + static TextTheme budaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.buda(textStyle: textTheme.headline1), + headline2: GoogleFonts.buda(textStyle: textTheme.headline2), + headline3: GoogleFonts.buda(textStyle: textTheme.headline3), + headline4: GoogleFonts.buda(textStyle: textTheme.headline4), + headline5: GoogleFonts.buda(textStyle: textTheme.headline5), + headline6: GoogleFonts.buda(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.buda(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.buda(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.buda(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.buda(textStyle: textTheme.bodyText2), + caption: GoogleFonts.buda(textStyle: textTheme.caption), + button: GoogleFonts.buda(textStyle: textTheme.button), + overline: GoogleFonts.buda(textStyle: textTheme.overline), + ); + } + + /// Applies the Buenard font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Buenard + static TextStyle buenard({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '98e52931f613305f11ff078f1cb569682195e516554178bf3c4127f644df907a', + 59764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b680cec9af406d125f721b89472951a526fcf17393adea7449be902ffb7f5cd', + 58608, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Buenard', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Buenard font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Buenard + static TextTheme buenardTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.buenard(textStyle: textTheme.headline1), + headline2: GoogleFonts.buenard(textStyle: textTheme.headline2), + headline3: GoogleFonts.buenard(textStyle: textTheme.headline3), + headline4: GoogleFonts.buenard(textStyle: textTheme.headline4), + headline5: GoogleFonts.buenard(textStyle: textTheme.headline5), + headline6: GoogleFonts.buenard(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.buenard(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.buenard(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.buenard(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.buenard(textStyle: textTheme.bodyText2), + caption: GoogleFonts.buenard(textStyle: textTheme.caption), + button: GoogleFonts.buenard(textStyle: textTheme.button), + overline: GoogleFonts.buenard(textStyle: textTheme.overline), + ); + } + + /// Applies the Bungee font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee + static TextStyle bungee({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ee34fb3fe185999f9942b2b39a37688866c1a4e25eab17c7a67765e7f47f6dbe', + 110116, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Bungee', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bungee font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee + static TextTheme bungeeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bungee(textStyle: textTheme.headline1), + headline2: GoogleFonts.bungee(textStyle: textTheme.headline2), + headline3: GoogleFonts.bungee(textStyle: textTheme.headline3), + headline4: GoogleFonts.bungee(textStyle: textTheme.headline4), + headline5: GoogleFonts.bungee(textStyle: textTheme.headline5), + headline6: GoogleFonts.bungee(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bungee(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bungee(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bungee(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bungee(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bungee(textStyle: textTheme.caption), + button: GoogleFonts.bungee(textStyle: textTheme.button), + overline: GoogleFonts.bungee(textStyle: textTheme.overline), + ); + } + + /// Applies the Bungee Hairline font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee+Hairline + static TextStyle bungeeHairline({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7082ad6f58a7ae0bdd49f1c56b50fdd5f19c8e5a7a760de15f353ff47bf2c391', + 97300, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BungeeHairline', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bungee Hairline font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee+Hairline + static TextTheme bungeeHairlineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bungeeHairline(textStyle: textTheme.headline1), + headline2: GoogleFonts.bungeeHairline(textStyle: textTheme.headline2), + headline3: GoogleFonts.bungeeHairline(textStyle: textTheme.headline3), + headline4: GoogleFonts.bungeeHairline(textStyle: textTheme.headline4), + headline5: GoogleFonts.bungeeHairline(textStyle: textTheme.headline5), + headline6: GoogleFonts.bungeeHairline(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bungeeHairline(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bungeeHairline(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bungeeHairline(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bungeeHairline(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bungeeHairline(textStyle: textTheme.caption), + button: GoogleFonts.bungeeHairline(textStyle: textTheme.button), + overline: GoogleFonts.bungeeHairline(textStyle: textTheme.overline), + ); + } + + /// Applies the Bungee Inline font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee+Inline + static TextStyle bungeeInline({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c34108c66136e4485dbe7f75f62e6d782066911952901a3b1657b8d37d5bf414', + 147660, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BungeeInline', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bungee Inline font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee+Inline + static TextTheme bungeeInlineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bungeeInline(textStyle: textTheme.headline1), + headline2: GoogleFonts.bungeeInline(textStyle: textTheme.headline2), + headline3: GoogleFonts.bungeeInline(textStyle: textTheme.headline3), + headline4: GoogleFonts.bungeeInline(textStyle: textTheme.headline4), + headline5: GoogleFonts.bungeeInline(textStyle: textTheme.headline5), + headline6: GoogleFonts.bungeeInline(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bungeeInline(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bungeeInline(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bungeeInline(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bungeeInline(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bungeeInline(textStyle: textTheme.caption), + button: GoogleFonts.bungeeInline(textStyle: textTheme.button), + overline: GoogleFonts.bungeeInline(textStyle: textTheme.overline), + ); + } + + /// Applies the Bungee Outline font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee+Outline + static TextStyle bungeeOutline({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '53bb5dbad57c06403c9f7c9503b0397f17f001d2a0881305c5bee9de3c610f78', + 200136, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BungeeOutline', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bungee Outline font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee+Outline + static TextTheme bungeeOutlineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bungeeOutline(textStyle: textTheme.headline1), + headline2: GoogleFonts.bungeeOutline(textStyle: textTheme.headline2), + headline3: GoogleFonts.bungeeOutline(textStyle: textTheme.headline3), + headline4: GoogleFonts.bungeeOutline(textStyle: textTheme.headline4), + headline5: GoogleFonts.bungeeOutline(textStyle: textTheme.headline5), + headline6: GoogleFonts.bungeeOutline(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bungeeOutline(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bungeeOutline(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bungeeOutline(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bungeeOutline(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bungeeOutline(textStyle: textTheme.caption), + button: GoogleFonts.bungeeOutline(textStyle: textTheme.button), + overline: GoogleFonts.bungeeOutline(textStyle: textTheme.overline), + ); + } + + /// Applies the Bungee Shade font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee+Shade + static TextStyle bungeeShade({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bd736a1fd1e9468b036a7df272341d90fa2864fa1a985cfef42c164898cadd99', + 330628, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'BungeeShade', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Bungee Shade font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Bungee+Shade + static TextTheme bungeeShadeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.bungeeShade(textStyle: textTheme.headline1), + headline2: GoogleFonts.bungeeShade(textStyle: textTheme.headline2), + headline3: GoogleFonts.bungeeShade(textStyle: textTheme.headline3), + headline4: GoogleFonts.bungeeShade(textStyle: textTheme.headline4), + headline5: GoogleFonts.bungeeShade(textStyle: textTheme.headline5), + headline6: GoogleFonts.bungeeShade(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.bungeeShade(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.bungeeShade(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.bungeeShade(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.bungeeShade(textStyle: textTheme.bodyText2), + caption: GoogleFonts.bungeeShade(textStyle: textTheme.caption), + button: GoogleFonts.bungeeShade(textStyle: textTheme.button), + overline: GoogleFonts.bungeeShade(textStyle: textTheme.overline), + ); + } + + /// Applies the Butcherman font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Butcherman + static TextStyle butcherman({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5bcf1ab19e7b312ef6a3f23116fef277d7af2240e6ee5719e5a8688f36f00e23', + 66300, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Butcherman', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Butcherman font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Butcherman + static TextTheme butchermanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.butcherman(textStyle: textTheme.headline1), + headline2: GoogleFonts.butcherman(textStyle: textTheme.headline2), + headline3: GoogleFonts.butcherman(textStyle: textTheme.headline3), + headline4: GoogleFonts.butcherman(textStyle: textTheme.headline4), + headline5: GoogleFonts.butcherman(textStyle: textTheme.headline5), + headline6: GoogleFonts.butcherman(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.butcherman(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.butcherman(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.butcherman(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.butcherman(textStyle: textTheme.bodyText2), + caption: GoogleFonts.butcherman(textStyle: textTheme.caption), + button: GoogleFonts.butcherman(textStyle: textTheme.button), + overline: GoogleFonts.butcherman(textStyle: textTheme.overline), + ); + } + + /// Applies the Butterfly Kids font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Butterfly+Kids + static TextStyle butterflyKids({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3e78c92335db0b2820b46df2d4a84c41e8690af1bac099b4a552e36736643b61', + 202408, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ButterflyKids', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Butterfly Kids font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Butterfly+Kids + static TextTheme butterflyKidsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.butterflyKids(textStyle: textTheme.headline1), + headline2: GoogleFonts.butterflyKids(textStyle: textTheme.headline2), + headline3: GoogleFonts.butterflyKids(textStyle: textTheme.headline3), + headline4: GoogleFonts.butterflyKids(textStyle: textTheme.headline4), + headline5: GoogleFonts.butterflyKids(textStyle: textTheme.headline5), + headline6: GoogleFonts.butterflyKids(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.butterflyKids(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.butterflyKids(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.butterflyKids(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.butterflyKids(textStyle: textTheme.bodyText2), + caption: GoogleFonts.butterflyKids(textStyle: textTheme.caption), + button: GoogleFonts.butterflyKids(textStyle: textTheme.button), + overline: GoogleFonts.butterflyKids(textStyle: textTheme.overline), + ); + } + + /// Applies the Cabin font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cabin + static TextStyle cabin({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ff30e9e9a66cf6a4e65d444d6bf8afdea7d574b27589397657972c2f9b2194f', + 81084, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'db35751de9b88dfbea004784c70c96bca9d813b5521cf320e5cb30adfd7384a2', + 80436, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4851465297f9c9aa19d41a969b28272f070f43271c7f279eb6daf3f291a47609', + 81516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2f1dff32a90462507aca783f85d6b2ed780858dd81a2a13bf217afbbfe5cce77', + 81408, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b7e9674a2fca64e9eddd32df2987e72643c1fbadb5cc8158e4a429f8a99ea39a', + 81656, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'da97f68bcdcff651e97b599499a784fc828a6e26feb94f391324076d060e3f7f', + 81548, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9adb3df669ae368a467dbe74951a83ec476b74739063459b95b664e6ea2bf36a', + 78196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e4a3605f6b618e79e1d2bc2e4890babb2828cca85fee80608cb7d4a810b06eab', + 80320, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cabin', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cabin font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cabin + static TextTheme cabinTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cabin(textStyle: textTheme.headline1), + headline2: GoogleFonts.cabin(textStyle: textTheme.headline2), + headline3: GoogleFonts.cabin(textStyle: textTheme.headline3), + headline4: GoogleFonts.cabin(textStyle: textTheme.headline4), + headline5: GoogleFonts.cabin(textStyle: textTheme.headline5), + headline6: GoogleFonts.cabin(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cabin(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cabin(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cabin(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cabin(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cabin(textStyle: textTheme.caption), + button: GoogleFonts.cabin(textStyle: textTheme.button), + overline: GoogleFonts.cabin(textStyle: textTheme.overline), + ); + } + + /// Applies the Cabin Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cabin+Condensed + static TextStyle cabinCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8864cf658e1904654fb267649af1a35b07c0f9e7b2df523910efcfa047857270', + 75132, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '19d7c8b72085fd1898042b6adfa002bee67aa85565ea042e3383c6d9718262f3', + 74864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '204e4e214a76e3cc970598f75636fbe098a6541146bb02dd3d1ec67c8e155e5b', + 74872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b3d243ed807d45b1666f9a3866bc69260a7d81fe656a1d0fc9335302b4d82fa', + 74732, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CabinCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cabin Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cabin+Condensed + static TextTheme cabinCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cabinCondensed(textStyle: textTheme.headline1), + headline2: GoogleFonts.cabinCondensed(textStyle: textTheme.headline2), + headline3: GoogleFonts.cabinCondensed(textStyle: textTheme.headline3), + headline4: GoogleFonts.cabinCondensed(textStyle: textTheme.headline4), + headline5: GoogleFonts.cabinCondensed(textStyle: textTheme.headline5), + headline6: GoogleFonts.cabinCondensed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cabinCondensed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cabinCondensed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cabinCondensed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cabinCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cabinCondensed(textStyle: textTheme.caption), + button: GoogleFonts.cabinCondensed(textStyle: textTheme.button), + overline: GoogleFonts.cabinCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Cabin Sketch font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cabin+Sketch + static TextStyle cabinSketch({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c56ec3d2c6227ce0f5959e906b36dda6fbf2ea830ed4edeb9000ee53197c122e', + 155128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6dab969699fde26ddd2636960d9e77e5178036db4b98b1f3761df0e74e17ca88', + 269912, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CabinSketch', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cabin Sketch font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cabin+Sketch + static TextTheme cabinSketchTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cabinSketch(textStyle: textTheme.headline1), + headline2: GoogleFonts.cabinSketch(textStyle: textTheme.headline2), + headline3: GoogleFonts.cabinSketch(textStyle: textTheme.headline3), + headline4: GoogleFonts.cabinSketch(textStyle: textTheme.headline4), + headline5: GoogleFonts.cabinSketch(textStyle: textTheme.headline5), + headline6: GoogleFonts.cabinSketch(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cabinSketch(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cabinSketch(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cabinSketch(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cabinSketch(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cabinSketch(textStyle: textTheme.caption), + button: GoogleFonts.cabinSketch(textStyle: textTheme.button), + overline: GoogleFonts.cabinSketch(textStyle: textTheme.overline), + ); + } + + /// Applies the Caesar Dressing font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caesar+Dressing + static TextStyle caesarDressing({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ee89ad88164ca8c3eeb747410087b9deecb5d306172af188f53bd267ec033f9c', + 89212, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CaesarDressing', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Caesar Dressing font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caesar+Dressing + static TextTheme caesarDressingTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.caesarDressing(textStyle: textTheme.headline1), + headline2: GoogleFonts.caesarDressing(textStyle: textTheme.headline2), + headline3: GoogleFonts.caesarDressing(textStyle: textTheme.headline3), + headline4: GoogleFonts.caesarDressing(textStyle: textTheme.headline4), + headline5: GoogleFonts.caesarDressing(textStyle: textTheme.headline5), + headline6: GoogleFonts.caesarDressing(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.caesarDressing(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.caesarDressing(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.caesarDressing(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.caesarDressing(textStyle: textTheme.bodyText2), + caption: GoogleFonts.caesarDressing(textStyle: textTheme.caption), + button: GoogleFonts.caesarDressing(textStyle: textTheme.button), + overline: GoogleFonts.caesarDressing(textStyle: textTheme.overline), + ); + } + + /// Applies the Cagliostro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cagliostro + static TextStyle cagliostro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3f57e12bc813bf3381233056c5544a970ea10f321f64dc63eef3ae1e650b2b93', + 37772, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cagliostro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cagliostro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cagliostro + static TextTheme cagliostroTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cagliostro(textStyle: textTheme.headline1), + headline2: GoogleFonts.cagliostro(textStyle: textTheme.headline2), + headline3: GoogleFonts.cagliostro(textStyle: textTheme.headline3), + headline4: GoogleFonts.cagliostro(textStyle: textTheme.headline4), + headline5: GoogleFonts.cagliostro(textStyle: textTheme.headline5), + headline6: GoogleFonts.cagliostro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cagliostro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cagliostro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cagliostro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cagliostro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cagliostro(textStyle: textTheme.caption), + button: GoogleFonts.cagliostro(textStyle: textTheme.button), + overline: GoogleFonts.cagliostro(textStyle: textTheme.overline), + ); + } + + /// Applies the Cairo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cairo + static TextStyle cairo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4f4138b4fc3c1369eee1151ad813f76e1b371364feb318c2dfed606c6c7a98dc', + 105268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '22d57a326952ad111119348fad278153f66b456e3f1e1b3eba074a4dc167f96e', + 104816, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1537c4e5a58de46dea37716791ce13157250bce598772e19adbf07abdaa2f5c0', + 103204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1f5b7f284695e2fd50ce750d2a479bcbdc7f701be3c33893f0773866193c8fba', + 104040, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '56f0547834a0a361e7216604988268770c085dcbd6f3241778f613b02d6db926', + 98368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4cf0e64d282c925bd689d2224fc9f34075e4586dbbebdbfa585ebab25a42059c', + 105544, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cairo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cairo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cairo + static TextTheme cairoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cairo(textStyle: textTheme.headline1), + headline2: GoogleFonts.cairo(textStyle: textTheme.headline2), + headline3: GoogleFonts.cairo(textStyle: textTheme.headline3), + headline4: GoogleFonts.cairo(textStyle: textTheme.headline4), + headline5: GoogleFonts.cairo(textStyle: textTheme.headline5), + headline6: GoogleFonts.cairo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cairo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cairo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cairo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cairo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cairo(textStyle: textTheme.caption), + button: GoogleFonts.cairo(textStyle: textTheme.button), + overline: GoogleFonts.cairo(textStyle: textTheme.overline), + ); + } + + /// Applies the Caladea font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caladea + static TextStyle caladea({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '60f1d4e3a572497f3530ac2ae1478709e606b3bdaaa56f97fd7efbc48e01de08', + 51516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a200599eb491ec914c9ce2fe7b2cdda1f14b4d082af53d054932993d3db7e7bb', + 50840, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fb25a8c8d05e937b9c5c3a001d1801276ba670641e4332a5f5d83cdc357cc5c3', + 52576, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0d6a8296a9489017c434820f994212d73ffe43b80bc9b3913f0eec7a4b3d4ed5', + 50968, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Caladea', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Caladea font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caladea + static TextTheme caladeaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.caladea(textStyle: textTheme.headline1), + headline2: GoogleFonts.caladea(textStyle: textTheme.headline2), + headline3: GoogleFonts.caladea(textStyle: textTheme.headline3), + headline4: GoogleFonts.caladea(textStyle: textTheme.headline4), + headline5: GoogleFonts.caladea(textStyle: textTheme.headline5), + headline6: GoogleFonts.caladea(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.caladea(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.caladea(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.caladea(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.caladea(textStyle: textTheme.bodyText2), + caption: GoogleFonts.caladea(textStyle: textTheme.caption), + button: GoogleFonts.caladea(textStyle: textTheme.button), + overline: GoogleFonts.caladea(textStyle: textTheme.overline), + ); + } + + /// Applies the Calistoga font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Calistoga + static TextStyle calistoga({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bbcc8c6618b098df3f7de4ee7afbe7a4ebe1832e5d8cca3579199c4e73ef5e8f', + 77552, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Calistoga', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Calistoga font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Calistoga + static TextTheme calistogaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.calistoga(textStyle: textTheme.headline1), + headline2: GoogleFonts.calistoga(textStyle: textTheme.headline2), + headline3: GoogleFonts.calistoga(textStyle: textTheme.headline3), + headline4: GoogleFonts.calistoga(textStyle: textTheme.headline4), + headline5: GoogleFonts.calistoga(textStyle: textTheme.headline5), + headline6: GoogleFonts.calistoga(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.calistoga(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.calistoga(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.calistoga(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.calistoga(textStyle: textTheme.bodyText2), + caption: GoogleFonts.calistoga(textStyle: textTheme.caption), + button: GoogleFonts.calistoga(textStyle: textTheme.button), + overline: GoogleFonts.calistoga(textStyle: textTheme.overline), + ); + } + + /// Applies the Calligraffitti font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Calligraffitti + static TextStyle calligraffitti({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '580e522ce80a61e980096a261015c86696213b70822d677e4de3902787578e63', + 46940, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Calligraffitti', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Calligraffitti font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Calligraffitti + static TextTheme calligraffittiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.calligraffitti(textStyle: textTheme.headline1), + headline2: GoogleFonts.calligraffitti(textStyle: textTheme.headline2), + headline3: GoogleFonts.calligraffitti(textStyle: textTheme.headline3), + headline4: GoogleFonts.calligraffitti(textStyle: textTheme.headline4), + headline5: GoogleFonts.calligraffitti(textStyle: textTheme.headline5), + headline6: GoogleFonts.calligraffitti(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.calligraffitti(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.calligraffitti(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.calligraffitti(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.calligraffitti(textStyle: textTheme.bodyText2), + caption: GoogleFonts.calligraffitti(textStyle: textTheme.caption), + button: GoogleFonts.calligraffitti(textStyle: textTheme.button), + overline: GoogleFonts.calligraffitti(textStyle: textTheme.overline), + ); + } + + /// Applies the Cambay font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cambay + static TextStyle cambay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7bad4e2ac4cc5bdeef53e890b4b3d52b065fdae8ebe5f754f263384995f7c73', + 140024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e821a1eb24db547646223e8b5065d6feeed373e25daf722bd4c3499785d3b6aa', + 155856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ece04d3d10726b39914e7a3c3ebbef7ccadcf7a26272fc090c83d3bf7690eea4', + 139576, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd17daa8d61f0a8bdd69696d0da7fc566e3a13141eb0ae45e512b48dcafb92565', + 151048, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cambay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cambay font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cambay + static TextTheme cambayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cambay(textStyle: textTheme.headline1), + headline2: GoogleFonts.cambay(textStyle: textTheme.headline2), + headline3: GoogleFonts.cambay(textStyle: textTheme.headline3), + headline4: GoogleFonts.cambay(textStyle: textTheme.headline4), + headline5: GoogleFonts.cambay(textStyle: textTheme.headline5), + headline6: GoogleFonts.cambay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cambay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cambay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cambay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cambay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cambay(textStyle: textTheme.caption), + button: GoogleFonts.cambay(textStyle: textTheme.button), + overline: GoogleFonts.cambay(textStyle: textTheme.overline), + ); + } + + /// Applies the Cambo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cambo + static TextStyle cambo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d8d683131ae5168d1210d9676808b76b985ad2a151d3a7514ec02f7b8a776b9', + 29056, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cambo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cambo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cambo + static TextTheme camboTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cambo(textStyle: textTheme.headline1), + headline2: GoogleFonts.cambo(textStyle: textTheme.headline2), + headline3: GoogleFonts.cambo(textStyle: textTheme.headline3), + headline4: GoogleFonts.cambo(textStyle: textTheme.headline4), + headline5: GoogleFonts.cambo(textStyle: textTheme.headline5), + headline6: GoogleFonts.cambo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cambo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cambo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cambo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cambo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cambo(textStyle: textTheme.caption), + button: GoogleFonts.cambo(textStyle: textTheme.button), + overline: GoogleFonts.cambo(textStyle: textTheme.overline), + ); + } + + /// Applies the Candal font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Candal + static TextStyle candal({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2e16795a5489340834dda623038868a2e7f48f4bc0f154f98c1a1962894a2598', + 32200, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Candal', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Candal font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Candal + static TextTheme candalTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.candal(textStyle: textTheme.headline1), + headline2: GoogleFonts.candal(textStyle: textTheme.headline2), + headline3: GoogleFonts.candal(textStyle: textTheme.headline3), + headline4: GoogleFonts.candal(textStyle: textTheme.headline4), + headline5: GoogleFonts.candal(textStyle: textTheme.headline5), + headline6: GoogleFonts.candal(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.candal(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.candal(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.candal(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.candal(textStyle: textTheme.bodyText2), + caption: GoogleFonts.candal(textStyle: textTheme.caption), + button: GoogleFonts.candal(textStyle: textTheme.button), + overline: GoogleFonts.candal(textStyle: textTheme.overline), + ); + } + + /// Applies the Cantarell font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cantarell + static TextStyle cantarell({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1e62d82800c92f72ed501733b5d52d7b8a5d88d1c6315bfdaf7f8ce781108c00', + 47436, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6d9559dd0df30daed7da97dc8ef05e7f39b72205fb9bd7a055ddaa5242afd36f', + 50000, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'db0c34021061680135f973a2cb5565811527ea91f2fa07d023f4e105eb6f45d3', + 49208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bb2c0f469972ec2016c3b8b8254ea0077f46207efb249afb3c4d356cf2c5418e', + 52132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cantarell', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cantarell font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cantarell + static TextTheme cantarellTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cantarell(textStyle: textTheme.headline1), + headline2: GoogleFonts.cantarell(textStyle: textTheme.headline2), + headline3: GoogleFonts.cantarell(textStyle: textTheme.headline3), + headline4: GoogleFonts.cantarell(textStyle: textTheme.headline4), + headline5: GoogleFonts.cantarell(textStyle: textTheme.headline5), + headline6: GoogleFonts.cantarell(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cantarell(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cantarell(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cantarell(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cantarell(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cantarell(textStyle: textTheme.caption), + button: GoogleFonts.cantarell(textStyle: textTheme.button), + overline: GoogleFonts.cantarell(textStyle: textTheme.overline), + ); + } + + /// Applies the Cantata One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cantata+One + static TextStyle cantataOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b58597daf95866fac678391238aefbae4bc3e31e826a3b85a2c749c3844a4dfe', + 57144, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CantataOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cantata One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cantata+One + static TextTheme cantataOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cantataOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.cantataOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.cantataOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.cantataOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.cantataOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.cantataOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cantataOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cantataOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cantataOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cantataOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cantataOne(textStyle: textTheme.caption), + button: GoogleFonts.cantataOne(textStyle: textTheme.button), + overline: GoogleFonts.cantataOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Cantora One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cantora+One + static TextStyle cantoraOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '242d2167789079107cbe59c3e9ccd0339ca51419245296a4659c6b3ad73cc41c', + 109236, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CantoraOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cantora One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cantora+One + static TextTheme cantoraOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cantoraOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.cantoraOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.cantoraOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.cantoraOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.cantoraOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.cantoraOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cantoraOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cantoraOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cantoraOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cantoraOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cantoraOne(textStyle: textTheme.caption), + button: GoogleFonts.cantoraOne(textStyle: textTheme.button), + overline: GoogleFonts.cantoraOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Capriola font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Capriola + static TextStyle capriola({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '938d0b1c7f521513ee9bb1114d92827718670e0e5a495ccd564d70b0ddc59594', + 78168, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Capriola', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Capriola font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Capriola + static TextTheme capriolaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.capriola(textStyle: textTheme.headline1), + headline2: GoogleFonts.capriola(textStyle: textTheme.headline2), + headline3: GoogleFonts.capriola(textStyle: textTheme.headline3), + headline4: GoogleFonts.capriola(textStyle: textTheme.headline4), + headline5: GoogleFonts.capriola(textStyle: textTheme.headline5), + headline6: GoogleFonts.capriola(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.capriola(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.capriola(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.capriola(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.capriola(textStyle: textTheme.bodyText2), + caption: GoogleFonts.capriola(textStyle: textTheme.caption), + button: GoogleFonts.capriola(textStyle: textTheme.button), + overline: GoogleFonts.capriola(textStyle: textTheme.overline), + ); + } + + /// Applies the Cardo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cardo + static TextStyle cardo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '286e6a4bde92ea6087b503978338898808df924a3cdd8144741fa780d11603a2', + 400420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '43bee56e6bb3d2ad574558a859227592f0b0ac881a70fd8f2cf74b808bb9be00', + 262820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '10c0bab22a674656a3d5e94e05e64f9c6c6ea25acce0d0fc846f964985b142ce', + 348296, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cardo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cardo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cardo + static TextTheme cardoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cardo(textStyle: textTheme.headline1), + headline2: GoogleFonts.cardo(textStyle: textTheme.headline2), + headline3: GoogleFonts.cardo(textStyle: textTheme.headline3), + headline4: GoogleFonts.cardo(textStyle: textTheme.headline4), + headline5: GoogleFonts.cardo(textStyle: textTheme.headline5), + headline6: GoogleFonts.cardo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cardo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cardo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cardo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cardo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cardo(textStyle: textTheme.caption), + button: GoogleFonts.cardo(textStyle: textTheme.button), + overline: GoogleFonts.cardo(textStyle: textTheme.overline), + ); + } + + /// Applies the Carme font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Carme + static TextStyle carme({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '79973fb109b078d0e49d90287e9f6527dc8829c6076c878ed07743d78cfb988b', + 60852, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Carme', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Carme font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Carme + static TextTheme carmeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.carme(textStyle: textTheme.headline1), + headline2: GoogleFonts.carme(textStyle: textTheme.headline2), + headline3: GoogleFonts.carme(textStyle: textTheme.headline3), + headline4: GoogleFonts.carme(textStyle: textTheme.headline4), + headline5: GoogleFonts.carme(textStyle: textTheme.headline5), + headline6: GoogleFonts.carme(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.carme(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.carme(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.carme(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.carme(textStyle: textTheme.bodyText2), + caption: GoogleFonts.carme(textStyle: textTheme.caption), + button: GoogleFonts.carme(textStyle: textTheme.button), + overline: GoogleFonts.carme(textStyle: textTheme.overline), + ); + } + + /// Applies the Carrois Gothic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Carrois+Gothic + static TextStyle carroisGothic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd013d780a3d17a244794f0d2649a6214a1946f102ddf0a02fe366fa7bb8bb6ec', + 26212, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CarroisGothic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Carrois Gothic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Carrois+Gothic + static TextTheme carroisGothicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.carroisGothic(textStyle: textTheme.headline1), + headline2: GoogleFonts.carroisGothic(textStyle: textTheme.headline2), + headline3: GoogleFonts.carroisGothic(textStyle: textTheme.headline3), + headline4: GoogleFonts.carroisGothic(textStyle: textTheme.headline4), + headline5: GoogleFonts.carroisGothic(textStyle: textTheme.headline5), + headline6: GoogleFonts.carroisGothic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.carroisGothic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.carroisGothic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.carroisGothic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.carroisGothic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.carroisGothic(textStyle: textTheme.caption), + button: GoogleFonts.carroisGothic(textStyle: textTheme.button), + overline: GoogleFonts.carroisGothic(textStyle: textTheme.overline), + ); + } + + /// Applies the Carrois Gothic SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Carrois+Gothic+SC + static TextStyle carroisGothicSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b50b78ae9eb35706d3d9923b420465d6c6245e9469dcbe4a96c30d118338edf', + 26084, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CarroisGothicSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Carrois Gothic SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Carrois+Gothic+SC + static TextTheme carroisGothicScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.carroisGothicSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.carroisGothicSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.carroisGothicSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.carroisGothicSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.carroisGothicSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.carroisGothicSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.carroisGothicSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.carroisGothicSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.carroisGothicSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.carroisGothicSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.carroisGothicSc(textStyle: textTheme.caption), + button: GoogleFonts.carroisGothicSc(textStyle: textTheme.button), + overline: GoogleFonts.carroisGothicSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Carter One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Carter+One + static TextStyle carterOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '64cdbf0babf6eb9e23f0a780f283a930636589b4b8d9a5d0cdf24888a7719292', + 63872, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CarterOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Carter One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Carter+One + static TextTheme carterOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.carterOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.carterOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.carterOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.carterOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.carterOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.carterOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.carterOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.carterOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.carterOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.carterOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.carterOne(textStyle: textTheme.caption), + button: GoogleFonts.carterOne(textStyle: textTheme.button), + overline: GoogleFonts.carterOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Castoro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Castoro + static TextStyle castoro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a1c0fdc4bf42e6acc4514d8e123a56bfa4101a0bf4d339c2f0a71bfcb0f6d02e', + 70892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '14b88401404e0d4111e8147bff13b3e811ece5feb299cd9259f3571ceb0de230', + 72080, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Castoro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Castoro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Castoro + static TextTheme castoroTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.castoro(textStyle: textTheme.headline1), + headline2: GoogleFonts.castoro(textStyle: textTheme.headline2), + headline3: GoogleFonts.castoro(textStyle: textTheme.headline3), + headline4: GoogleFonts.castoro(textStyle: textTheme.headline4), + headline5: GoogleFonts.castoro(textStyle: textTheme.headline5), + headline6: GoogleFonts.castoro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.castoro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.castoro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.castoro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.castoro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.castoro(textStyle: textTheme.caption), + button: GoogleFonts.castoro(textStyle: textTheme.button), + overline: GoogleFonts.castoro(textStyle: textTheme.overline), + ); + } + + /// Applies the Catamaran font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Catamaran + static TextStyle catamaran({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8e9d704be93826d9781f133277934bb6184afd9522b149f005c78f5d89e62ac', + 51516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3f24bc068d63c199fab01e5c0690d6e034f485057c3c19571b656e705a78756b', + 51520, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '853537ef3cef46cebdd3f2ee0f94b33861095d50b2584d6f96a47725f6f4b79d', + 51428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6af095039ae2cc21b9f8e147b290dc6fae99dd4f45843dd262a9e30557dd4e65', + 51200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2b80fad7d7ef99a42af9235090775e879520d07fb7b3deda4986a64c81be4a96', + 51172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd77e1072b0d92cfa66cc458ff7e053b1e33cfa9dd663fb52f75062ba9a134122', + 51028, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '47d32e32345049db4c0f41c0ffba707afcf0ac18cb7000817fd26ae811255728', + 50828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '342bd0052b9b81ca6df68a9cdda635ad6f77c796e37045545bfa1d0a071c0bc8', + 50464, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fa466db090fa897764fa413a006d0c4f7a975a118db3de634988a14f674446cb', + 50220, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Catamaran', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Catamaran font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Catamaran + static TextTheme catamaranTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.catamaran(textStyle: textTheme.headline1), + headline2: GoogleFonts.catamaran(textStyle: textTheme.headline2), + headline3: GoogleFonts.catamaran(textStyle: textTheme.headline3), + headline4: GoogleFonts.catamaran(textStyle: textTheme.headline4), + headline5: GoogleFonts.catamaran(textStyle: textTheme.headline5), + headline6: GoogleFonts.catamaran(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.catamaran(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.catamaran(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.catamaran(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.catamaran(textStyle: textTheme.bodyText2), + caption: GoogleFonts.catamaran(textStyle: textTheme.caption), + button: GoogleFonts.catamaran(textStyle: textTheme.button), + overline: GoogleFonts.catamaran(textStyle: textTheme.overline), + ); + } + + /// Applies the Caudex font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caudex + static TextStyle caudex({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e0c195632ea06158f87e86ee898119dd8a7f59788999552ed79be77c33c6a726', + 466276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '53374860983e21bb358d83d1162c824903649ae49f873a963c665b066514bb9d', + 559392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '09a6db433fd45eb3e1423e9947afe5b766008cc358cb482b42103970fc840676', + 471660, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '45c118976f77e53a2a5122e22cace7fb846373a14892fbb7e0ff61e1a46de1d4', + 555108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Caudex', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Caudex font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caudex + static TextTheme caudexTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.caudex(textStyle: textTheme.headline1), + headline2: GoogleFonts.caudex(textStyle: textTheme.headline2), + headline3: GoogleFonts.caudex(textStyle: textTheme.headline3), + headline4: GoogleFonts.caudex(textStyle: textTheme.headline4), + headline5: GoogleFonts.caudex(textStyle: textTheme.headline5), + headline6: GoogleFonts.caudex(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.caudex(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.caudex(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.caudex(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.caudex(textStyle: textTheme.bodyText2), + caption: GoogleFonts.caudex(textStyle: textTheme.caption), + button: GoogleFonts.caudex(textStyle: textTheme.button), + overline: GoogleFonts.caudex(textStyle: textTheme.overline), + ); + } + + /// Applies the Caveat font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caveat + static TextStyle caveat({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0ffe3acdd9c8d91838d7ba021d1c4e9111151e34a104318a8aafe0efeda5755f', + 165376, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6993da01fa90c359d45a03be9927b46be80d261978de6f5805f43d75ed2d172f', + 166236, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Caveat', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Caveat font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caveat + static TextTheme caveatTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.caveat(textStyle: textTheme.headline1), + headline2: GoogleFonts.caveat(textStyle: textTheme.headline2), + headline3: GoogleFonts.caveat(textStyle: textTheme.headline3), + headline4: GoogleFonts.caveat(textStyle: textTheme.headline4), + headline5: GoogleFonts.caveat(textStyle: textTheme.headline5), + headline6: GoogleFonts.caveat(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.caveat(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.caveat(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.caveat(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.caveat(textStyle: textTheme.bodyText2), + caption: GoogleFonts.caveat(textStyle: textTheme.caption), + button: GoogleFonts.caveat(textStyle: textTheme.button), + overline: GoogleFonts.caveat(textStyle: textTheme.overline), + ); + } + + /// Applies the Caveat Brush font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caveat+Brush + static TextStyle caveatBrush({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '70de81a815f44819880ddba3c93eda87ab6bd1a4b21db15e5ba29c9271cba521', + 232640, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CaveatBrush', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Caveat Brush font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Caveat+Brush + static TextTheme caveatBrushTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.caveatBrush(textStyle: textTheme.headline1), + headline2: GoogleFonts.caveatBrush(textStyle: textTheme.headline2), + headline3: GoogleFonts.caveatBrush(textStyle: textTheme.headline3), + headline4: GoogleFonts.caveatBrush(textStyle: textTheme.headline4), + headline5: GoogleFonts.caveatBrush(textStyle: textTheme.headline5), + headline6: GoogleFonts.caveatBrush(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.caveatBrush(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.caveatBrush(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.caveatBrush(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.caveatBrush(textStyle: textTheme.bodyText2), + caption: GoogleFonts.caveatBrush(textStyle: textTheme.caption), + button: GoogleFonts.caveatBrush(textStyle: textTheme.button), + overline: GoogleFonts.caveatBrush(textStyle: textTheme.overline), + ); + } + + /// Applies the Cedarville Cursive font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cedarville+Cursive + static TextStyle cedarvilleCursive({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b1296a081a20bf4a1936ace5eac4d05fa6702cdfaab5f94a5088af4c0aa46c3d', + 68704, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CedarvilleCursive', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cedarville Cursive font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cedarville+Cursive + static TextTheme cedarvilleCursiveTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cedarvilleCursive(textStyle: textTheme.headline1), + headline2: GoogleFonts.cedarvilleCursive(textStyle: textTheme.headline2), + headline3: GoogleFonts.cedarvilleCursive(textStyle: textTheme.headline3), + headline4: GoogleFonts.cedarvilleCursive(textStyle: textTheme.headline4), + headline5: GoogleFonts.cedarvilleCursive(textStyle: textTheme.headline5), + headline6: GoogleFonts.cedarvilleCursive(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cedarvilleCursive(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cedarvilleCursive(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cedarvilleCursive(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cedarvilleCursive(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cedarvilleCursive(textStyle: textTheme.caption), + button: GoogleFonts.cedarvilleCursive(textStyle: textTheme.button), + overline: GoogleFonts.cedarvilleCursive(textStyle: textTheme.overline), + ); + } + + /// Applies the Ceviche One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ceviche+One + static TextStyle cevicheOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ed3cdc36bf356dbe366b2198c633acbf26815fc96c14ba05a7847b274043909', + 36688, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CevicheOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ceviche One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ceviche+One + static TextTheme cevicheOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cevicheOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.cevicheOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.cevicheOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.cevicheOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.cevicheOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.cevicheOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cevicheOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cevicheOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cevicheOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cevicheOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cevicheOne(textStyle: textTheme.caption), + button: GoogleFonts.cevicheOne(textStyle: textTheme.button), + overline: GoogleFonts.cevicheOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Chakra Petch font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chakra+Petch + static TextStyle chakraPetch({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ecaf4ae2d67c61e2a3fa8df13a271ccea00d43000ba74107e7bfda439f60b1d2', + 70452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '020376f9083d9c7e6f32ecb879dee72b6fadef64ea9a3df0bd01d4952a06f1aa', + 72720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6854c9992a9a1345525235ab8e75582a0f6f3f828c37e4720a78aad1de6c0aa5', + 70160, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '114572d34834d0022111a2a7a0eaf1d6bb7e3b70537f2c52e283219fa86ccd02', + 72412, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '179d4e7774a67d1c01789bcf1bf48e72fbc37fa173f3373470769b54a505ad17', + 70152, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f7172b64774efd15a32d833b00836c9e30c0ee766c096a08de2a427c904f5c2d', + 72504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a6b54f7d68496d966460fe300af5b72cc91ca631822110de9fbc976ceabb2591', + 70164, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a7a04e1ebef703c41253da2ca8a90c83a63649e471590d939c69828a0e0e591f', + 72524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e409c139ac42c535be29bfb904109788499a4b3971f95c0853dce713da259ea9', + 70068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '86042cd1693573443cb56c465a3f44172486eb888d707fcc03eb3dc8600008cb', + 72408, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ChakraPetch', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chakra Petch font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chakra+Petch + static TextTheme chakraPetchTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chakraPetch(textStyle: textTheme.headline1), + headline2: GoogleFonts.chakraPetch(textStyle: textTheme.headline2), + headline3: GoogleFonts.chakraPetch(textStyle: textTheme.headline3), + headline4: GoogleFonts.chakraPetch(textStyle: textTheme.headline4), + headline5: GoogleFonts.chakraPetch(textStyle: textTheme.headline5), + headline6: GoogleFonts.chakraPetch(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chakraPetch(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chakraPetch(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chakraPetch(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chakraPetch(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chakraPetch(textStyle: textTheme.caption), + button: GoogleFonts.chakraPetch(textStyle: textTheme.button), + overline: GoogleFonts.chakraPetch(textStyle: textTheme.overline), + ); + } + + /// Applies the Changa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Changa + static TextStyle changa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e248c51b3bc1f8fd1d6b980400670c54bf2cdf89f4c5e075bca29f09ecdb936b', + 81252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f083dc8e9965f9e9b8c6c977bcfac5a504f4ef820e8c8237f1217d4edf3bdd9a', + 80888, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '01d71ec0cc7235bb908cc0c3ae45d1e10a2f87e4a61ad5ef855af157f39e8a80', + 80184, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fb1d544301460f01712f06d94a05af7420497d1b5791bdf43b542c0351227242', + 80588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c22f4b8d7a97aaa32759b9336354bdcf999861dac5d589a4e02e7e5bb9504f98', + 80472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0a274e0c0a7aa46f455bf65caff8b972998ce8fc975bf677ae154d5765ac4c0f', + 79956, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5d419cee41ca204d194f089cfd5d8d35ea6bc706a8f606ecaa69132df9854893', + 79556, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Changa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Changa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Changa + static TextTheme changaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.changa(textStyle: textTheme.headline1), + headline2: GoogleFonts.changa(textStyle: textTheme.headline2), + headline3: GoogleFonts.changa(textStyle: textTheme.headline3), + headline4: GoogleFonts.changa(textStyle: textTheme.headline4), + headline5: GoogleFonts.changa(textStyle: textTheme.headline5), + headline6: GoogleFonts.changa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.changa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.changa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.changa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.changa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.changa(textStyle: textTheme.caption), + button: GoogleFonts.changa(textStyle: textTheme.button), + overline: GoogleFonts.changa(textStyle: textTheme.overline), + ); + } + + /// Applies the Changa One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Changa+One + static TextStyle changaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '55a043f0a2eb34269cfb137a6203fdc338019e9bdaabee1e685c6b37495cb962', + 22668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '241077b802e7b6209a41ea93aae98aa81d9f09e6f78fce924c863af6ca96b529', + 26680, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ChangaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Changa One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Changa+One + static TextTheme changaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.changaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.changaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.changaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.changaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.changaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.changaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.changaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.changaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.changaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.changaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.changaOne(textStyle: textTheme.caption), + button: GoogleFonts.changaOne(textStyle: textTheme.button), + overline: GoogleFonts.changaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Chango font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chango + static TextStyle chango({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '66d5dcae03b7a0d59f38640d05bb920cc6d3b4e2a1cdb176628330e20ab9a6ca', + 40684, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Chango', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chango font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chango + static TextTheme changoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chango(textStyle: textTheme.headline1), + headline2: GoogleFonts.chango(textStyle: textTheme.headline2), + headline3: GoogleFonts.chango(textStyle: textTheme.headline3), + headline4: GoogleFonts.chango(textStyle: textTheme.headline4), + headline5: GoogleFonts.chango(textStyle: textTheme.headline5), + headline6: GoogleFonts.chango(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chango(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chango(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chango(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chango(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chango(textStyle: textTheme.caption), + button: GoogleFonts.chango(textStyle: textTheme.button), + overline: GoogleFonts.chango(textStyle: textTheme.overline), + ); + } + + /// Applies the Charm font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Charm + static TextStyle charm({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b2803aafd875584dcb262e1eddd8dc7542342f4d2d76ac5f9b06c6b5e2bae18f', + 121276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '40f34767fa59a87e641da20236b9966135321cb03c1ed68d88a6234d432d2604', + 122112, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Charm', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Charm font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Charm + static TextTheme charmTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.charm(textStyle: textTheme.headline1), + headline2: GoogleFonts.charm(textStyle: textTheme.headline2), + headline3: GoogleFonts.charm(textStyle: textTheme.headline3), + headline4: GoogleFonts.charm(textStyle: textTheme.headline4), + headline5: GoogleFonts.charm(textStyle: textTheme.headline5), + headline6: GoogleFonts.charm(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.charm(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.charm(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.charm(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.charm(textStyle: textTheme.bodyText2), + caption: GoogleFonts.charm(textStyle: textTheme.caption), + button: GoogleFonts.charm(textStyle: textTheme.button), + overline: GoogleFonts.charm(textStyle: textTheme.overline), + ); + } + + /// Applies the Charmonman font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Charmonman + static TextStyle charmonman({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8c4d7f973e9f5d882d38668d863ec90889ddc79cd302e832da538621ac970513', + 100884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd1492915dc59b590610a5b5bcf4d1b9aca380c377b870a0a9de187fc05146908', + 100612, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Charmonman', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Charmonman font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Charmonman + static TextTheme charmonmanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.charmonman(textStyle: textTheme.headline1), + headline2: GoogleFonts.charmonman(textStyle: textTheme.headline2), + headline3: GoogleFonts.charmonman(textStyle: textTheme.headline3), + headline4: GoogleFonts.charmonman(textStyle: textTheme.headline4), + headline5: GoogleFonts.charmonman(textStyle: textTheme.headline5), + headline6: GoogleFonts.charmonman(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.charmonman(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.charmonman(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.charmonman(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.charmonman(textStyle: textTheme.bodyText2), + caption: GoogleFonts.charmonman(textStyle: textTheme.caption), + button: GoogleFonts.charmonman(textStyle: textTheme.button), + overline: GoogleFonts.charmonman(textStyle: textTheme.overline), + ); + } + + /// Applies the Chathura font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chathura + static TextStyle chathura({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '78a5a2532fd10bcf3317ec8440d1e758a309bd152369607ccea764abddbcb168', + 345716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7b8357f2b60bfe270ca77801978a0bd5e729870ffad8b19d54ff69cded800a1f', + 340972, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f8abdba026fb7a58e3f5b2cbe302ab4d9e817e69dfd7c6fce0ffbf22fe9600f5', + 330780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '129573e675c52db3364e6d6ac3d517a6cb8113531a3bc2b54276e1d28d28c11a', + 329608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c6190f40f502b8b950146bbe4ba7b7b02eea38047766ba5b56895059e3b6c655', + 328760, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Chathura', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chathura font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chathura + static TextTheme chathuraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chathura(textStyle: textTheme.headline1), + headline2: GoogleFonts.chathura(textStyle: textTheme.headline2), + headline3: GoogleFonts.chathura(textStyle: textTheme.headline3), + headline4: GoogleFonts.chathura(textStyle: textTheme.headline4), + headline5: GoogleFonts.chathura(textStyle: textTheme.headline5), + headline6: GoogleFonts.chathura(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chathura(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chathura(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chathura(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chathura(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chathura(textStyle: textTheme.caption), + button: GoogleFonts.chathura(textStyle: textTheme.button), + overline: GoogleFonts.chathura(textStyle: textTheme.overline), + ); + } + + /// Applies the Chau Philomene One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chau+Philomene+One + static TextStyle chauPhilomeneOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c44d00d1e4d0cfcf8ae3458b12571cdd000ce9df7849a29afa3dd3aadfdb6224', + 39692, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5be1fbfb8c59a78422d618850745eeabe8bebc7aef35518a599c765168ad124a', + 43992, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ChauPhilomeneOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chau Philomene One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chau+Philomene+One + static TextTheme chauPhilomeneOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.caption), + button: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.button), + overline: GoogleFonts.chauPhilomeneOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Chela One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chela+One + static TextStyle chelaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3efd79a48f37981dfb1dd9c73243093c103f990459d6cc0e0918ed692c2beef0', + 35492, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ChelaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chela One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chela+One + static TextTheme chelaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chelaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.chelaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.chelaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.chelaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.chelaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.chelaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chelaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chelaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chelaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chelaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chelaOne(textStyle: textTheme.caption), + button: GoogleFonts.chelaOne(textStyle: textTheme.button), + overline: GoogleFonts.chelaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Chelsea Market font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chelsea+Market + static TextStyle chelseaMarket({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7841b0525f53772efeff1353b0297e9faa176874f84319d11057dfa3d129147b', + 172508, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ChelseaMarket', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chelsea Market font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chelsea+Market + static TextTheme chelseaMarketTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chelseaMarket(textStyle: textTheme.headline1), + headline2: GoogleFonts.chelseaMarket(textStyle: textTheme.headline2), + headline3: GoogleFonts.chelseaMarket(textStyle: textTheme.headline3), + headline4: GoogleFonts.chelseaMarket(textStyle: textTheme.headline4), + headline5: GoogleFonts.chelseaMarket(textStyle: textTheme.headline5), + headline6: GoogleFonts.chelseaMarket(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chelseaMarket(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chelseaMarket(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chelseaMarket(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chelseaMarket(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chelseaMarket(textStyle: textTheme.caption), + button: GoogleFonts.chelseaMarket(textStyle: textTheme.button), + overline: GoogleFonts.chelseaMarket(textStyle: textTheme.overline), + ); + } + + /// Applies the Cherry Cream Soda font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cherry+Cream+Soda + static TextStyle cherryCreamSoda({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '47e79c87ca78a16fd9c841454bdf7ea5a7485a08a7f78baddcc83bbc2f510729', + 40208, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CherryCreamSoda', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cherry Cream Soda font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cherry+Cream+Soda + static TextTheme cherryCreamSodaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cherryCreamSoda(textStyle: textTheme.headline1), + headline2: GoogleFonts.cherryCreamSoda(textStyle: textTheme.headline2), + headline3: GoogleFonts.cherryCreamSoda(textStyle: textTheme.headline3), + headline4: GoogleFonts.cherryCreamSoda(textStyle: textTheme.headline4), + headline5: GoogleFonts.cherryCreamSoda(textStyle: textTheme.headline5), + headline6: GoogleFonts.cherryCreamSoda(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cherryCreamSoda(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cherryCreamSoda(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cherryCreamSoda(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cherryCreamSoda(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cherryCreamSoda(textStyle: textTheme.caption), + button: GoogleFonts.cherryCreamSoda(textStyle: textTheme.button), + overline: GoogleFonts.cherryCreamSoda(textStyle: textTheme.overline), + ); + } + + /// Applies the Cherry Swash font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cherry+Swash + static TextStyle cherrySwash({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c16f18e4a0ef56672f00dcd810fae50a7468eccc6174968c6890ca1ed1eb4dc0', + 30548, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '46fc53776950e3047f5b647b1819e4ec28a5521b733a7e614aa9d97562cb5371', + 29984, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CherrySwash', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cherry Swash font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cherry+Swash + static TextTheme cherrySwashTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cherrySwash(textStyle: textTheme.headline1), + headline2: GoogleFonts.cherrySwash(textStyle: textTheme.headline2), + headline3: GoogleFonts.cherrySwash(textStyle: textTheme.headline3), + headline4: GoogleFonts.cherrySwash(textStyle: textTheme.headline4), + headline5: GoogleFonts.cherrySwash(textStyle: textTheme.headline5), + headline6: GoogleFonts.cherrySwash(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cherrySwash(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cherrySwash(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cherrySwash(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cherrySwash(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cherrySwash(textStyle: textTheme.caption), + button: GoogleFonts.cherrySwash(textStyle: textTheme.button), + overline: GoogleFonts.cherrySwash(textStyle: textTheme.overline), + ); + } + + /// Applies the Chewy font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chewy + static TextStyle chewy({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd88ead910c7aca7ef7e4aec8e38bc7bd8ea2f85b93181a960e2747192d839469', + 36096, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Chewy', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chewy font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chewy + static TextTheme chewyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chewy(textStyle: textTheme.headline1), + headline2: GoogleFonts.chewy(textStyle: textTheme.headline2), + headline3: GoogleFonts.chewy(textStyle: textTheme.headline3), + headline4: GoogleFonts.chewy(textStyle: textTheme.headline4), + headline5: GoogleFonts.chewy(textStyle: textTheme.headline5), + headline6: GoogleFonts.chewy(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chewy(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chewy(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chewy(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chewy(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chewy(textStyle: textTheme.caption), + button: GoogleFonts.chewy(textStyle: textTheme.button), + overline: GoogleFonts.chewy(textStyle: textTheme.overline), + ); + } + + /// Applies the Chicle font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chicle + static TextStyle chicle({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '463fc42349dcac85fa8e161556aa92b7ae3f8d9cd174ef7b134ac072382d6069', + 40964, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Chicle', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chicle font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chicle + static TextTheme chicleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chicle(textStyle: textTheme.headline1), + headline2: GoogleFonts.chicle(textStyle: textTheme.headline2), + headline3: GoogleFonts.chicle(textStyle: textTheme.headline3), + headline4: GoogleFonts.chicle(textStyle: textTheme.headline4), + headline5: GoogleFonts.chicle(textStyle: textTheme.headline5), + headline6: GoogleFonts.chicle(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chicle(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chicle(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chicle(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chicle(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chicle(textStyle: textTheme.caption), + button: GoogleFonts.chicle(textStyle: textTheme.button), + overline: GoogleFonts.chicle(textStyle: textTheme.overline), + ); + } + + /// Applies the Chilanka font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chilanka + static TextStyle chilanka({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c0b4dcbe94cf228d02f67f71242fed2881a691a3b3516a791881a3428605d6dc', + 338888, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Chilanka', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chilanka font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chilanka + static TextTheme chilankaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chilanka(textStyle: textTheme.headline1), + headline2: GoogleFonts.chilanka(textStyle: textTheme.headline2), + headline3: GoogleFonts.chilanka(textStyle: textTheme.headline3), + headline4: GoogleFonts.chilanka(textStyle: textTheme.headline4), + headline5: GoogleFonts.chilanka(textStyle: textTheme.headline5), + headline6: GoogleFonts.chilanka(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chilanka(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chilanka(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chilanka(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chilanka(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chilanka(textStyle: textTheme.caption), + button: GoogleFonts.chilanka(textStyle: textTheme.button), + overline: GoogleFonts.chilanka(textStyle: textTheme.overline), + ); + } + + /// Applies the Chivo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chivo + static TextStyle chivo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '994635489f0d118a198cb7efcdd1b61cbd4431c9e6426fffad5b731c4d2c1a5c', + 44544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f512baee58b1fc81a387836a8de41c055d2bebbfde221bd5f6829c1db58d9baa', + 38544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c45551e766074f40061345617f0e07c5a4a2ecbd70ce90f3c7456284827c3184', + 41264, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1940d6e1383f625468fbb0231dc6d8ea95eda2d8483e23e66e94d6bb05996ca2', + 35312, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '49e634b98df69d1812b9406be76ebe8c76888e0202ae16c267aff5f9897d279f', + 33884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eea6f18e9fa02d840e18d03dfe74e65437743472807f1f0a93bb11254419cdb4', + 35400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b16f1d6acd367f8f1dd75d71e56027975f5f4c661b7272c0ae41a0635d55908a', + 34680, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'da92d63af2ecddbae2e8cf92a528caebcba3ed94b7b00e2ab04d228c4622c806', + 36840, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Chivo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chivo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chivo + static TextTheme chivoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chivo(textStyle: textTheme.headline1), + headline2: GoogleFonts.chivo(textStyle: textTheme.headline2), + headline3: GoogleFonts.chivo(textStyle: textTheme.headline3), + headline4: GoogleFonts.chivo(textStyle: textTheme.headline4), + headline5: GoogleFonts.chivo(textStyle: textTheme.headline5), + headline6: GoogleFonts.chivo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chivo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chivo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chivo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chivo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chivo(textStyle: textTheme.caption), + button: GoogleFonts.chivo(textStyle: textTheme.button), + overline: GoogleFonts.chivo(textStyle: textTheme.overline), + ); + } + + /// Applies the Chonburi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chonburi + static TextStyle chonburi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b8e4b1d59bd57981915ee60262422c0d7b7bc237ec938d181c684425e608baca', + 112300, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Chonburi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Chonburi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Chonburi + static TextTheme chonburiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.chonburi(textStyle: textTheme.headline1), + headline2: GoogleFonts.chonburi(textStyle: textTheme.headline2), + headline3: GoogleFonts.chonburi(textStyle: textTheme.headline3), + headline4: GoogleFonts.chonburi(textStyle: textTheme.headline4), + headline5: GoogleFonts.chonburi(textStyle: textTheme.headline5), + headline6: GoogleFonts.chonburi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.chonburi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.chonburi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.chonburi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.chonburi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.chonburi(textStyle: textTheme.caption), + button: GoogleFonts.chonburi(textStyle: textTheme.button), + overline: GoogleFonts.chonburi(textStyle: textTheme.overline), + ); + } + + /// Applies the Cinzel font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cinzel + static TextStyle cinzel({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a1d67206903b7688f4187df3dd0563dce75a49b26d036c7e88798adcd6c8fab', + 55732, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd385de045feb981ef4256fb3f82d128c1835f686ed5611dd1c5b01e8b615e7bb', + 57244, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fbb068fbb60eb4c57957c490b9e8c4b00d9c8cc14bd064d85fca96516f5ae46f', + 58144, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cinzel', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cinzel font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cinzel + static TextTheme cinzelTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cinzel(textStyle: textTheme.headline1), + headline2: GoogleFonts.cinzel(textStyle: textTheme.headline2), + headline3: GoogleFonts.cinzel(textStyle: textTheme.headline3), + headline4: GoogleFonts.cinzel(textStyle: textTheme.headline4), + headline5: GoogleFonts.cinzel(textStyle: textTheme.headline5), + headline6: GoogleFonts.cinzel(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cinzel(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cinzel(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cinzel(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cinzel(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cinzel(textStyle: textTheme.caption), + button: GoogleFonts.cinzel(textStyle: textTheme.button), + overline: GoogleFonts.cinzel(textStyle: textTheme.overline), + ); + } + + /// Applies the Cinzel Decorative font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cinzel+Decorative + static TextStyle cinzelDecorative({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e2559504f7da1fc2410b4eca9cb5ca6fee8c1ead7c3920a0b225ef4f1da9034f', + 60044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a01d62b7c7d50b908e2fd62beb09363fb5e99ea2f21e0e79f71e5a6c356ceba', + 61900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a9e463550cabc5d5d694e24c136e6d235212011e58c21d523229960a16bc5148', + 62320, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CinzelDecorative', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cinzel Decorative font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cinzel+Decorative + static TextTheme cinzelDecorativeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cinzelDecorative(textStyle: textTheme.headline1), + headline2: GoogleFonts.cinzelDecorative(textStyle: textTheme.headline2), + headline3: GoogleFonts.cinzelDecorative(textStyle: textTheme.headline3), + headline4: GoogleFonts.cinzelDecorative(textStyle: textTheme.headline4), + headline5: GoogleFonts.cinzelDecorative(textStyle: textTheme.headline5), + headline6: GoogleFonts.cinzelDecorative(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cinzelDecorative(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cinzelDecorative(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cinzelDecorative(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cinzelDecorative(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cinzelDecorative(textStyle: textTheme.caption), + button: GoogleFonts.cinzelDecorative(textStyle: textTheme.button), + overline: GoogleFonts.cinzelDecorative(textStyle: textTheme.overline), + ); + } + + /// Applies the Clicker Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Clicker+Script + static TextStyle clickerScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a5d266712bdee3e9dc58039be9fe3d6492b6d9de30e12c387ff7726b7bc43566', + 63596, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ClickerScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Clicker Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Clicker+Script + static TextTheme clickerScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.clickerScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.clickerScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.clickerScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.clickerScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.clickerScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.clickerScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.clickerScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.clickerScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.clickerScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.clickerScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.clickerScript(textStyle: textTheme.caption), + button: GoogleFonts.clickerScript(textStyle: textTheme.button), + overline: GoogleFonts.clickerScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Coda font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coda + static TextStyle coda({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3286b71ee83e8775ab6ae6fef1580c62d0344ad5a8a10ba144104648a36f9749', + 37032, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0f385f570ff23725ac544ecfcf2ec8b8cbca733a730d2038266a6eb8b071e4c0', + 31676, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Coda', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Coda font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coda + static TextTheme codaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.coda(textStyle: textTheme.headline1), + headline2: GoogleFonts.coda(textStyle: textTheme.headline2), + headline3: GoogleFonts.coda(textStyle: textTheme.headline3), + headline4: GoogleFonts.coda(textStyle: textTheme.headline4), + headline5: GoogleFonts.coda(textStyle: textTheme.headline5), + headline6: GoogleFonts.coda(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.coda(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.coda(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.coda(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.coda(textStyle: textTheme.bodyText2), + caption: GoogleFonts.coda(textStyle: textTheme.caption), + button: GoogleFonts.coda(textStyle: textTheme.button), + overline: GoogleFonts.coda(textStyle: textTheme.overline), + ); + } + + /// Applies the Coda Caption font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coda+Caption + static TextStyle codaCaption({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '28b801f8b4a3bbeae1f47a3081d64a60cba59d844b8d9719165a993bbfd5424b', + 59700, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CodaCaption', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Coda Caption font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coda+Caption + static TextTheme codaCaptionTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.codaCaption(textStyle: textTheme.headline1), + headline2: GoogleFonts.codaCaption(textStyle: textTheme.headline2), + headline3: GoogleFonts.codaCaption(textStyle: textTheme.headline3), + headline4: GoogleFonts.codaCaption(textStyle: textTheme.headline4), + headline5: GoogleFonts.codaCaption(textStyle: textTheme.headline5), + headline6: GoogleFonts.codaCaption(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.codaCaption(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.codaCaption(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.codaCaption(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.codaCaption(textStyle: textTheme.bodyText2), + caption: GoogleFonts.codaCaption(textStyle: textTheme.caption), + button: GoogleFonts.codaCaption(textStyle: textTheme.button), + overline: GoogleFonts.codaCaption(textStyle: textTheme.overline), + ); + } + + /// Applies the Codystar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Codystar + static TextStyle codystar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd8599cf77d1a295657a62a9be2067a1d7c27dad40e7ae89910c6516e57f1fdb1', + 101120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5d2fb67af692de14dd1f3b942de494168b78c1cef3cc103867d36c4281ac0b00', + 106084, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Codystar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Codystar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Codystar + static TextTheme codystarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.codystar(textStyle: textTheme.headline1), + headline2: GoogleFonts.codystar(textStyle: textTheme.headline2), + headline3: GoogleFonts.codystar(textStyle: textTheme.headline3), + headline4: GoogleFonts.codystar(textStyle: textTheme.headline4), + headline5: GoogleFonts.codystar(textStyle: textTheme.headline5), + headline6: GoogleFonts.codystar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.codystar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.codystar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.codystar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.codystar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.codystar(textStyle: textTheme.caption), + button: GoogleFonts.codystar(textStyle: textTheme.button), + overline: GoogleFonts.codystar(textStyle: textTheme.overline), + ); + } + + /// Applies the Coiny font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coiny + static TextStyle coiny({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd7c4ad8ba1a68159f3a01ce26a6ae52110298a54077d3aa35b12d216941a3f28', + 88036, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Coiny', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Coiny font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coiny + static TextTheme coinyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.coiny(textStyle: textTheme.headline1), + headline2: GoogleFonts.coiny(textStyle: textTheme.headline2), + headline3: GoogleFonts.coiny(textStyle: textTheme.headline3), + headline4: GoogleFonts.coiny(textStyle: textTheme.headline4), + headline5: GoogleFonts.coiny(textStyle: textTheme.headline5), + headline6: GoogleFonts.coiny(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.coiny(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.coiny(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.coiny(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.coiny(textStyle: textTheme.bodyText2), + caption: GoogleFonts.coiny(textStyle: textTheme.caption), + button: GoogleFonts.coiny(textStyle: textTheme.button), + overline: GoogleFonts.coiny(textStyle: textTheme.overline), + ); + } + + /// Applies the Combo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Combo + static TextStyle combo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bb7529647493cbe7db3d0199e9c64a31b084ffe6f9bc8408a5eef9a588daffdd', + 37416, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Combo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Combo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Combo + static TextTheme comboTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.combo(textStyle: textTheme.headline1), + headline2: GoogleFonts.combo(textStyle: textTheme.headline2), + headline3: GoogleFonts.combo(textStyle: textTheme.headline3), + headline4: GoogleFonts.combo(textStyle: textTheme.headline4), + headline5: GoogleFonts.combo(textStyle: textTheme.headline5), + headline6: GoogleFonts.combo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.combo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.combo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.combo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.combo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.combo(textStyle: textTheme.caption), + button: GoogleFonts.combo(textStyle: textTheme.button), + overline: GoogleFonts.combo(textStyle: textTheme.overline), + ); + } + + /// Applies the Comfortaa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Comfortaa + static TextStyle comfortaa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9c42dde162aca0ef35c66a372266676483320b31bd2d1069fd2ec3879d092000', + 106812, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b1a86afe9202b2f23f62ea6a901f0f299515c34673aea8cf0d8ab2270b4d7013', + 106948, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '30b5d292bb0fe9543a8ae812c3a2ce1ca57f9fd6701afafad31156536db5f08d', + 106956, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Comfortaa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Comfortaa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Comfortaa + static TextTheme comfortaaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.comfortaa(textStyle: textTheme.headline1), + headline2: GoogleFonts.comfortaa(textStyle: textTheme.headline2), + headline3: GoogleFonts.comfortaa(textStyle: textTheme.headline3), + headline4: GoogleFonts.comfortaa(textStyle: textTheme.headline4), + headline5: GoogleFonts.comfortaa(textStyle: textTheme.headline5), + headline6: GoogleFonts.comfortaa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.comfortaa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.comfortaa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.comfortaa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.comfortaa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.comfortaa(textStyle: textTheme.caption), + button: GoogleFonts.comfortaa(textStyle: textTheme.button), + overline: GoogleFonts.comfortaa(textStyle: textTheme.overline), + ); + } + + /// Applies the Comic Neue font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Comic+Neue + static TextStyle comicNeue({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '03e7eb4282b1113db14871908b545b6c90e66c01c71e25eebd86710af1675dc6', + 36488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e3f90ddc32d7c1de1802b67c219fcaa9a3363ffd6798d5135d4f660a1dda1b26', + 35420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d7ebe6d4d4dfaab467fe4a423295d991fdfbf4d1989fcaad2f84c5f338ab089', + 36536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b5fb7946d3c3a90935983acd29701d85ed3c845dbea8a353f82e297d2c3c0fc6', + 35484, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4b38da288c36361aa89d7bd2d0cb55585417eef4ae2b1c087d41fa9d3616eb70', + 35256, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '77d1c55b067195ccd5450ef65c41c0bc9adb016fdc56465fa2323318e59a9fef', + 35480, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ComicNeue', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Comic Neue font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Comic+Neue + static TextTheme comicNeueTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.comicNeue(textStyle: textTheme.headline1), + headline2: GoogleFonts.comicNeue(textStyle: textTheme.headline2), + headline3: GoogleFonts.comicNeue(textStyle: textTheme.headline3), + headline4: GoogleFonts.comicNeue(textStyle: textTheme.headline4), + headline5: GoogleFonts.comicNeue(textStyle: textTheme.headline5), + headline6: GoogleFonts.comicNeue(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.comicNeue(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.comicNeue(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.comicNeue(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.comicNeue(textStyle: textTheme.bodyText2), + caption: GoogleFonts.comicNeue(textStyle: textTheme.caption), + button: GoogleFonts.comicNeue(textStyle: textTheme.button), + overline: GoogleFonts.comicNeue(textStyle: textTheme.overline), + ); + } + + /// Applies the Coming Soon font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coming+Soon + static TextStyle comingSoon({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '193064f6768240e8165c7b8f6dec7b2dd4cf009b638b76c7b879098469346c5e', + 49836, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ComingSoon', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Coming Soon font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coming+Soon + static TextTheme comingSoonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.comingSoon(textStyle: textTheme.headline1), + headline2: GoogleFonts.comingSoon(textStyle: textTheme.headline2), + headline3: GoogleFonts.comingSoon(textStyle: textTheme.headline3), + headline4: GoogleFonts.comingSoon(textStyle: textTheme.headline4), + headline5: GoogleFonts.comingSoon(textStyle: textTheme.headline5), + headline6: GoogleFonts.comingSoon(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.comingSoon(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.comingSoon(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.comingSoon(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.comingSoon(textStyle: textTheme.bodyText2), + caption: GoogleFonts.comingSoon(textStyle: textTheme.caption), + button: GoogleFonts.comingSoon(textStyle: textTheme.button), + overline: GoogleFonts.comingSoon(textStyle: textTheme.overline), + ); + } + + /// Applies the Commissioner font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Commissioner + static TextStyle commissioner({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f3f150dcb086a17069e52d54fa21cb1f24dc198b7e05359b9b24fa4697da6bd7', + 345392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1978b19a2dcf7ed0ba2354f75892138d7ae51193a8afe0df8359513bff60c42e', + 352032, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '759373804a16aef0f59d2c1c0ef804972ad9ad65708142d58807d7eac8a311f6', + 356932, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ea57d9c20f9490ea132318ac9b31671cbe5253e441caf88d170d86d5f00d950', + 363648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e3fadda38391b661f465e8511fce1ae10c4f52b08b3e4879191039f0de43c75', + 364704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a56720c0fc63f34becc7efc84659cbdacd2bca91b73617065d62ff00f255c2f6', + 367584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a70994c9420407b957fdc6ed64040600d77318665536587db62dcd33b03e6516', + 368552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e80c7844535ca64a4b3af21c23f195c9b9bb1f10bd74b7520474fb574b967177', + 367652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '04a4f501c4e3bc2ac11cee31535057bad6c58b0bf9620c3f1acd704c333eb689', + 362176, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Commissioner', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Commissioner font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Commissioner + static TextTheme commissionerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.commissioner(textStyle: textTheme.headline1), + headline2: GoogleFonts.commissioner(textStyle: textTheme.headline2), + headline3: GoogleFonts.commissioner(textStyle: textTheme.headline3), + headline4: GoogleFonts.commissioner(textStyle: textTheme.headline4), + headline5: GoogleFonts.commissioner(textStyle: textTheme.headline5), + headline6: GoogleFonts.commissioner(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.commissioner(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.commissioner(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.commissioner(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.commissioner(textStyle: textTheme.bodyText2), + caption: GoogleFonts.commissioner(textStyle: textTheme.caption), + button: GoogleFonts.commissioner(textStyle: textTheme.button), + overline: GoogleFonts.commissioner(textStyle: textTheme.overline), + ); + } + + /// Applies the Concert One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Concert+One + static TextStyle concertOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2539111a44381dd36a5a1ab7f50323edd3755088027d0c83419b5ecb88ac14e2', + 44788, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ConcertOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Concert One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Concert+One + static TextTheme concertOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.concertOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.concertOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.concertOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.concertOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.concertOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.concertOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.concertOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.concertOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.concertOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.concertOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.concertOne(textStyle: textTheme.caption), + button: GoogleFonts.concertOne(textStyle: textTheme.button), + overline: GoogleFonts.concertOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Condiment font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Condiment + static TextStyle condiment({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '404ef1b407aafc9555242dbfc0416b9761054b9bc16abacf2ab328af7b034b66', + 43344, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Condiment', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Condiment font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Condiment + static TextTheme condimentTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.condiment(textStyle: textTheme.headline1), + headline2: GoogleFonts.condiment(textStyle: textTheme.headline2), + headline3: GoogleFonts.condiment(textStyle: textTheme.headline3), + headline4: GoogleFonts.condiment(textStyle: textTheme.headline4), + headline5: GoogleFonts.condiment(textStyle: textTheme.headline5), + headline6: GoogleFonts.condiment(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.condiment(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.condiment(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.condiment(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.condiment(textStyle: textTheme.bodyText2), + caption: GoogleFonts.condiment(textStyle: textTheme.caption), + button: GoogleFonts.condiment(textStyle: textTheme.button), + overline: GoogleFonts.condiment(textStyle: textTheme.overline), + ); + } + + /// Applies the Contrail One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Contrail+One + static TextStyle contrailOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '51cdbe97cef3cc835b94974aeff5d8805b5d25b1904ad5355836afe27b0cc199', + 31136, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ContrailOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Contrail One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Contrail+One + static TextTheme contrailOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.contrailOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.contrailOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.contrailOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.contrailOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.contrailOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.contrailOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.contrailOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.contrailOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.contrailOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.contrailOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.contrailOne(textStyle: textTheme.caption), + button: GoogleFonts.contrailOne(textStyle: textTheme.button), + overline: GoogleFonts.contrailOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Convergence font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Convergence + static TextStyle convergence({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bee94289e5374af0501d83d8b767d631571ce0a2ab1c16a765bad418a9fbbf22', + 30172, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Convergence', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Convergence font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Convergence + static TextTheme convergenceTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.convergence(textStyle: textTheme.headline1), + headline2: GoogleFonts.convergence(textStyle: textTheme.headline2), + headline3: GoogleFonts.convergence(textStyle: textTheme.headline3), + headline4: GoogleFonts.convergence(textStyle: textTheme.headline4), + headline5: GoogleFonts.convergence(textStyle: textTheme.headline5), + headline6: GoogleFonts.convergence(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.convergence(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.convergence(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.convergence(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.convergence(textStyle: textTheme.bodyText2), + caption: GoogleFonts.convergence(textStyle: textTheme.caption), + button: GoogleFonts.convergence(textStyle: textTheme.button), + overline: GoogleFonts.convergence(textStyle: textTheme.overline), + ); + } + + /// Applies the Cookie font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cookie + static TextStyle cookie({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8d01e7c434faf0f6a1c7c2f49021b8ac01590d10ba4cb8c15683299ed0997536', + 43752, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cookie', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cookie font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cookie + static TextTheme cookieTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cookie(textStyle: textTheme.headline1), + headline2: GoogleFonts.cookie(textStyle: textTheme.headline2), + headline3: GoogleFonts.cookie(textStyle: textTheme.headline3), + headline4: GoogleFonts.cookie(textStyle: textTheme.headline4), + headline5: GoogleFonts.cookie(textStyle: textTheme.headline5), + headline6: GoogleFonts.cookie(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cookie(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cookie(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cookie(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cookie(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cookie(textStyle: textTheme.caption), + button: GoogleFonts.cookie(textStyle: textTheme.button), + overline: GoogleFonts.cookie(textStyle: textTheme.overline), + ); + } + + /// Applies the Copse font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Copse + static TextStyle copse({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ace02d3cf195f5ddfbe562a9361241356d198ed56d25ec6d8dfb69e08a50133a', + 59116, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Copse', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Copse font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Copse + static TextTheme copseTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.copse(textStyle: textTheme.headline1), + headline2: GoogleFonts.copse(textStyle: textTheme.headline2), + headline3: GoogleFonts.copse(textStyle: textTheme.headline3), + headline4: GoogleFonts.copse(textStyle: textTheme.headline4), + headline5: GoogleFonts.copse(textStyle: textTheme.headline5), + headline6: GoogleFonts.copse(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.copse(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.copse(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.copse(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.copse(textStyle: textTheme.bodyText2), + caption: GoogleFonts.copse(textStyle: textTheme.caption), + button: GoogleFonts.copse(textStyle: textTheme.button), + overline: GoogleFonts.copse(textStyle: textTheme.overline), + ); + } + + /// Applies the Corben font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Corben + static TextStyle corben({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd7fa399441299ed2b575ab62e7d0338bebb9b110c569b1ab9661d8df90029b6e', + 35760, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '101e1a5b8d96f12fffab739f046c3a869a5edc6a0a4d2f980c26cef6648331c0', + 113588, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Corben', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Corben font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Corben + static TextTheme corbenTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.corben(textStyle: textTheme.headline1), + headline2: GoogleFonts.corben(textStyle: textTheme.headline2), + headline3: GoogleFonts.corben(textStyle: textTheme.headline3), + headline4: GoogleFonts.corben(textStyle: textTheme.headline4), + headline5: GoogleFonts.corben(textStyle: textTheme.headline5), + headline6: GoogleFonts.corben(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.corben(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.corben(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.corben(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.corben(textStyle: textTheme.bodyText2), + caption: GoogleFonts.corben(textStyle: textTheme.caption), + button: GoogleFonts.corben(textStyle: textTheme.button), + overline: GoogleFonts.corben(textStyle: textTheme.overline), + ); + } + + /// Applies the Cormorant font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant + static TextStyle cormorant({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25d9142c8c73577fb3546a40795e753bab11f4e22663e2f1168cbc485cbaa542', + 369920, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd90d995e2a130e04d6e32ee3778e059092e41f5d9c1c812a659c7ffb52951a19', + 241020, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fd04cb22306c1c15bb1727fc4b3d2344de940e929b75dbe3faa9b7f43f9e0d6d', + 370052, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1f64218505ec6321eba3b8df95d0806808f61c872f9c081bce39c00a402a4429', + 240392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '20c11bc6844b3f25ad300ce80d94c0c0fc2fb997b51e04cd1959156c6d78309d', + 369256, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '47bba53369e3f5bcda0e230d7e6fe60ae86b40b59b80d57c603c50e273d2f17c', + 240280, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c1821d5e327189284afba6a7a2a9831a3025677c5afb37910353410a72391791', + 369328, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c02d2b3a07288427fe5cd64e378eebe86d6a308b6d7dfe0e8cc4d1975d32e0d5', + 240048, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a91dc6bed8f499ba7dfc43c8259fa142dc1d0097d84aba2a73c003c35b409845', + 368108, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '01317d3f16a7d1e98e9fcb9e49778326433ab76c291971e501f5e721ac437b0d', + 239228, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cormorant', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cormorant font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant + static TextTheme cormorantTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cormorant(textStyle: textTheme.headline1), + headline2: GoogleFonts.cormorant(textStyle: textTheme.headline2), + headline3: GoogleFonts.cormorant(textStyle: textTheme.headline3), + headline4: GoogleFonts.cormorant(textStyle: textTheme.headline4), + headline5: GoogleFonts.cormorant(textStyle: textTheme.headline5), + headline6: GoogleFonts.cormorant(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cormorant(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cormorant(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cormorant(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cormorant(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cormorant(textStyle: textTheme.caption), + button: GoogleFonts.cormorant(textStyle: textTheme.button), + overline: GoogleFonts.cormorant(textStyle: textTheme.overline), + ); + } + + /// Applies the Cormorant Garamond font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+Garamond + static TextStyle cormorantGaramond({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e5ae2850e0033754375df527e1bb29ed63bd133553ce65b8d9313dd4cc944f8', + 674036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '86bc19f83cdf358de6e84a3bdbdc0f24e24d47bbdbf7cc2eac80d7bfe24dfdd4', + 426064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5a2dd210ea12467e5697bb32480d20e0ebfbe2c2af1c64b1679567cf3486a8a5', + 673208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4766c3793328466bbd4f974a3843b2bffb312bd22c98098b0dec8990ba48f5e2', + 424232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '31bc31d93d2a5c505ca03887ae0ad2ad816caf59499f35016d89fe4d5db18ced', + 672392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e2b5d7b06e08f325bc0513179903b1423183f6533fec2645b64a6e1f24ad699c', + 424904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25068099ded344cf0919185bae33e11bca97b6c8b1a528dede8ac80325e27c6b', + 671588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e316fc5e36acd433eb0c3ea1b28d8475a1ff9d0da27bf329fa1bd5d54eb870bf', + 424716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b273c7be0b4af1389631638e4f056f5d9066fc17d321e665b3a28d43001736af', + 670200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e1c32c701a4b7594cd169653bc0feceed0160066ce7cedd06999fc884ddd6c02', + 423900, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CormorantGaramond', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cormorant Garamond font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+Garamond + static TextTheme cormorantGaramondTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cormorantGaramond(textStyle: textTheme.headline1), + headline2: GoogleFonts.cormorantGaramond(textStyle: textTheme.headline2), + headline3: GoogleFonts.cormorantGaramond(textStyle: textTheme.headline3), + headline4: GoogleFonts.cormorantGaramond(textStyle: textTheme.headline4), + headline5: GoogleFonts.cormorantGaramond(textStyle: textTheme.headline5), + headline6: GoogleFonts.cormorantGaramond(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cormorantGaramond(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cormorantGaramond(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cormorantGaramond(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cormorantGaramond(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cormorantGaramond(textStyle: textTheme.caption), + button: GoogleFonts.cormorantGaramond(textStyle: textTheme.button), + overline: GoogleFonts.cormorantGaramond(textStyle: textTheme.overline), + ); + } + + /// Applies the Cormorant Infant font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+Infant + static TextStyle cormorantInfant({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9168080bdab2d447729e3f3046722e4d88cfd4cb5a1862dc6d916cba737791c5', + 674136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e6958c39fabaf907bdde7ba424eb0c17f3fef77c989edbaa01115b1fe5c6e067', + 425328, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '47164cf35cfe61e120d0e8c3e775559372e1a738f9e2c57cf85aa05e8c4bc806', + 673248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '84f78b4a61cce77b8c2c9663434b1c6cf0316b556002a2c9ea9df9265533cf6b', + 423500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d23820c90080bfb4aa4f9cec1e1ef64424729ef0c9b0e977e27806b21d81304', + 671764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f8a57af623179b25d7e59c823c1acd0563f9cfb6f1f03da9532e49bf49739dab', + 424168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f6a06c7e0bd73d14e395e0d977119af3b5fae58a9ce153ab18a277182316b424', + 671652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e1ae8191f481ca057de000de05308f0098090fd60456b76f13b1ffdc82ac1b1d', + 423936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a03a98979c43146bda66d723dfb38c68b77012ab2433f4eafcbda573433d75b5', + 670304, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ceb4474fec6832dee11e5cc5624186c760e7993898bc39599f3fe8248cbb1b70', + 423176, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CormorantInfant', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cormorant Infant font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+Infant + static TextTheme cormorantInfantTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cormorantInfant(textStyle: textTheme.headline1), + headline2: GoogleFonts.cormorantInfant(textStyle: textTheme.headline2), + headline3: GoogleFonts.cormorantInfant(textStyle: textTheme.headline3), + headline4: GoogleFonts.cormorantInfant(textStyle: textTheme.headline4), + headline5: GoogleFonts.cormorantInfant(textStyle: textTheme.headline5), + headline6: GoogleFonts.cormorantInfant(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cormorantInfant(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cormorantInfant(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cormorantInfant(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cormorantInfant(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cormorantInfant(textStyle: textTheme.caption), + button: GoogleFonts.cormorantInfant(textStyle: textTheme.button), + overline: GoogleFonts.cormorantInfant(textStyle: textTheme.overline), + ); + } + + /// Applies the Cormorant SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+SC + static TextStyle cormorantSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '20075e607eb45ea2e8f60f9365f2bf608df1251f443ae12295d751b425dd9b62', + 652740, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8c091c9484c2f6ac490d1613295b59e76d359ad34e1c52fb2f853a8c2ea0aac', + 651888, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '85cf334d625e0deec8283f8aa03ec6295e20a52c371096595411dcee4bef2039', + 650624, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2a187b0fe3cebc137da0b069c1017ad0c1cfb10ef8992089d21b8261bbc9ad0c', + 650308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '29e53a056b50572310c96ff3a83932d488c6954871aced226c122e7f3ff8b00b', + 648928, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CormorantSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cormorant SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+SC + static TextTheme cormorantScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cormorantSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.cormorantSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.cormorantSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.cormorantSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.cormorantSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.cormorantSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cormorantSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cormorantSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cormorantSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cormorantSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cormorantSc(textStyle: textTheme.caption), + button: GoogleFonts.cormorantSc(textStyle: textTheme.button), + overline: GoogleFonts.cormorantSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Cormorant Unicase font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+Unicase + static TextStyle cormorantUnicase({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b2f697aa9071850538a594d14122faff09a953f9e6b7897e5284ae9afe2c2b0', + 653392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a075bd869512a69bf9bfcb4b1987513cf71f5b0f8931adc373783f751c44553a', + 652624, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fa07955427124a8c76b2621bceba09805d61cc57efe1c57120f9fd91a46e04ce', + 651372, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '34d64ee75c05feffc586b864ce55af03115c3fd6a3c3fabeeef53742fd991848', + 651056, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ad4713eaa8a5f3198c0bed735f60707e4cb0c77de5643d8b4df7f61e8a8979a6', + 649664, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CormorantUnicase', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cormorant Unicase font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+Unicase + static TextTheme cormorantUnicaseTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cormorantUnicase(textStyle: textTheme.headline1), + headline2: GoogleFonts.cormorantUnicase(textStyle: textTheme.headline2), + headline3: GoogleFonts.cormorantUnicase(textStyle: textTheme.headline3), + headline4: GoogleFonts.cormorantUnicase(textStyle: textTheme.headline4), + headline5: GoogleFonts.cormorantUnicase(textStyle: textTheme.headline5), + headline6: GoogleFonts.cormorantUnicase(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cormorantUnicase(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cormorantUnicase(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cormorantUnicase(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cormorantUnicase(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cormorantUnicase(textStyle: textTheme.caption), + button: GoogleFonts.cormorantUnicase(textStyle: textTheme.button), + overline: GoogleFonts.cormorantUnicase(textStyle: textTheme.overline), + ); + } + + /// Applies the Cormorant Upright font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+Upright + static TextStyle cormorantUpright({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '29c9067ec4aab7f8532dfad801cd638d35f8738903ec7c40f80069030e231431', + 156128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd7c8d8d44c6591234b85e43c1b61a5f4adc82016e3c7f315b206cf31fda62572', + 155736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e1c85ea60d180f0a621d975977e7e75c7d398a4d4fcb569d2ccadd85c42adce', + 156096, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0d60d4f81c0c154612e2e9b3b5dd56c2ab5e74e4d8e8507d9725ce908a54c914', + 156140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '441604498e23b982bd6adbe6fe749140f9955eddd7a905329bb88bf4ca9a8f85', + 156320, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CormorantUpright', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cormorant Upright font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cormorant+Upright + static TextTheme cormorantUprightTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cormorantUpright(textStyle: textTheme.headline1), + headline2: GoogleFonts.cormorantUpright(textStyle: textTheme.headline2), + headline3: GoogleFonts.cormorantUpright(textStyle: textTheme.headline3), + headline4: GoogleFonts.cormorantUpright(textStyle: textTheme.headline4), + headline5: GoogleFonts.cormorantUpright(textStyle: textTheme.headline5), + headline6: GoogleFonts.cormorantUpright(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cormorantUpright(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cormorantUpright(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cormorantUpright(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cormorantUpright(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cormorantUpright(textStyle: textTheme.caption), + button: GoogleFonts.cormorantUpright(textStyle: textTheme.button), + overline: GoogleFonts.cormorantUpright(textStyle: textTheme.overline), + ); + } + + /// Applies the Courgette font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Courgette + static TextStyle courgette({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2754f22af579b8f14d78397e6cc4d3879519ad579085e8c047ba2f7719c592a4', + 93820, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Courgette', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Courgette font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Courgette + static TextTheme courgetteTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.courgette(textStyle: textTheme.headline1), + headline2: GoogleFonts.courgette(textStyle: textTheme.headline2), + headline3: GoogleFonts.courgette(textStyle: textTheme.headline3), + headline4: GoogleFonts.courgette(textStyle: textTheme.headline4), + headline5: GoogleFonts.courgette(textStyle: textTheme.headline5), + headline6: GoogleFonts.courgette(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.courgette(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.courgette(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.courgette(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.courgette(textStyle: textTheme.bodyText2), + caption: GoogleFonts.courgette(textStyle: textTheme.caption), + button: GoogleFonts.courgette(textStyle: textTheme.button), + overline: GoogleFonts.courgette(textStyle: textTheme.overline), + ); + } + + /// Applies the Courier Prime font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Courier+Prime + static TextStyle courierPrime({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ab28865b2644070e548699748855f2d5a34b5bf8adea09607e18d4a7adc8999', + 40588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7109c63818181b56013b7ced3e5da53d756aab727e6a9786a0c8a58affe4ec23', + 46896, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '385e70d216befbb71f12f5009f1824d235e0f4f2ab653bb0296d5d999afdfd3f', + 42136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3f61e15019812e414a4dba4f3b4fbdda453e8c4dd18deafacb7c55686cef11a7', + 47340, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CourierPrime', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Courier Prime font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Courier+Prime + static TextTheme courierPrimeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.courierPrime(textStyle: textTheme.headline1), + headline2: GoogleFonts.courierPrime(textStyle: textTheme.headline2), + headline3: GoogleFonts.courierPrime(textStyle: textTheme.headline3), + headline4: GoogleFonts.courierPrime(textStyle: textTheme.headline4), + headline5: GoogleFonts.courierPrime(textStyle: textTheme.headline5), + headline6: GoogleFonts.courierPrime(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.courierPrime(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.courierPrime(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.courierPrime(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.courierPrime(textStyle: textTheme.bodyText2), + caption: GoogleFonts.courierPrime(textStyle: textTheme.caption), + button: GoogleFonts.courierPrime(textStyle: textTheme.button), + overline: GoogleFonts.courierPrime(textStyle: textTheme.overline), + ); + } + + /// Applies the Cousine font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cousine + static TextStyle cousine({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '753f2dd34e36271520e1bf057a91850492b226f76d6da301cf6955b4b32177a1', + 191380, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '23ddf22bc3d06b028fce6e266632d38c97fa151a580be71b5ad43ee7d34d13a0', + 200304, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e472053ed3d50c647f75d5654f0d2ff42cbf5221cb14e1b1af3dc25dbbd6ea4', + 191172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8b14c04baa12f36602157da1c6c26f539163a93e571133c17d0b5acc34345bfa', + 199244, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cousine', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cousine font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cousine + static TextTheme cousineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cousine(textStyle: textTheme.headline1), + headline2: GoogleFonts.cousine(textStyle: textTheme.headline2), + headline3: GoogleFonts.cousine(textStyle: textTheme.headline3), + headline4: GoogleFonts.cousine(textStyle: textTheme.headline4), + headline5: GoogleFonts.cousine(textStyle: textTheme.headline5), + headline6: GoogleFonts.cousine(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cousine(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cousine(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cousine(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cousine(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cousine(textStyle: textTheme.caption), + button: GoogleFonts.cousine(textStyle: textTheme.button), + overline: GoogleFonts.cousine(textStyle: textTheme.overline), + ); + } + + /// Applies the Coustard font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coustard + static TextStyle coustard({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '657fe3ebd0e1b0402731533db6ddbe6120271871430adfff3ea617c35120f166', + 39700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c9288e8be500e6cb9ea6f0ae05167d9ee149c0d91fc8a422055f396236b1e413', + 42376, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Coustard', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Coustard font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Coustard + static TextTheme coustardTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.coustard(textStyle: textTheme.headline1), + headline2: GoogleFonts.coustard(textStyle: textTheme.headline2), + headline3: GoogleFonts.coustard(textStyle: textTheme.headline3), + headline4: GoogleFonts.coustard(textStyle: textTheme.headline4), + headline5: GoogleFonts.coustard(textStyle: textTheme.headline5), + headline6: GoogleFonts.coustard(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.coustard(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.coustard(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.coustard(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.coustard(textStyle: textTheme.bodyText2), + caption: GoogleFonts.coustard(textStyle: textTheme.caption), + button: GoogleFonts.coustard(textStyle: textTheme.button), + overline: GoogleFonts.coustard(textStyle: textTheme.overline), + ); + } + + /// Applies the Covered By Your Grace font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Covered+By+Your+Grace + static TextStyle coveredByYourGrace({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e2e2deb5e6914da1e25b2a2f5161ff4e08d65d6e00d26081708efc7ffacca93a', + 57040, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CoveredByYourGrace', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Covered By Your Grace font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Covered+By+Your+Grace + static TextTheme coveredByYourGraceTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.coveredByYourGrace(textStyle: textTheme.headline1), + headline2: GoogleFonts.coveredByYourGrace(textStyle: textTheme.headline2), + headline3: GoogleFonts.coveredByYourGrace(textStyle: textTheme.headline3), + headline4: GoogleFonts.coveredByYourGrace(textStyle: textTheme.headline4), + headline5: GoogleFonts.coveredByYourGrace(textStyle: textTheme.headline5), + headline6: GoogleFonts.coveredByYourGrace(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.coveredByYourGrace(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.coveredByYourGrace(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.coveredByYourGrace(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.coveredByYourGrace(textStyle: textTheme.bodyText2), + caption: GoogleFonts.coveredByYourGrace(textStyle: textTheme.caption), + button: GoogleFonts.coveredByYourGrace(textStyle: textTheme.button), + overline: GoogleFonts.coveredByYourGrace(textStyle: textTheme.overline), + ); + } + + /// Applies the Crafty Girls font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crafty+Girls + static TextStyle craftyGirls({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dc184885668047ca66db5a530c0462f1b1ef2f2d6867b7f938c59dbc9d282de2', + 61632, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CraftyGirls', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Crafty Girls font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crafty+Girls + static TextTheme craftyGirlsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.craftyGirls(textStyle: textTheme.headline1), + headline2: GoogleFonts.craftyGirls(textStyle: textTheme.headline2), + headline3: GoogleFonts.craftyGirls(textStyle: textTheme.headline3), + headline4: GoogleFonts.craftyGirls(textStyle: textTheme.headline4), + headline5: GoogleFonts.craftyGirls(textStyle: textTheme.headline5), + headline6: GoogleFonts.craftyGirls(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.craftyGirls(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.craftyGirls(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.craftyGirls(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.craftyGirls(textStyle: textTheme.bodyText2), + caption: GoogleFonts.craftyGirls(textStyle: textTheme.caption), + button: GoogleFonts.craftyGirls(textStyle: textTheme.button), + overline: GoogleFonts.craftyGirls(textStyle: textTheme.overline), + ); + } + + /// Applies the Creepster font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Creepster + static TextStyle creepster({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bb14e63f8fb5e6bd8706e47aea59d9e2b6b3da1b2f987d1468a6ba5cda2d1fc1', + 62700, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Creepster', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Creepster font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Creepster + static TextTheme creepsterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.creepster(textStyle: textTheme.headline1), + headline2: GoogleFonts.creepster(textStyle: textTheme.headline2), + headline3: GoogleFonts.creepster(textStyle: textTheme.headline3), + headline4: GoogleFonts.creepster(textStyle: textTheme.headline4), + headline5: GoogleFonts.creepster(textStyle: textTheme.headline5), + headline6: GoogleFonts.creepster(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.creepster(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.creepster(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.creepster(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.creepster(textStyle: textTheme.bodyText2), + caption: GoogleFonts.creepster(textStyle: textTheme.caption), + button: GoogleFonts.creepster(textStyle: textTheme.button), + overline: GoogleFonts.creepster(textStyle: textTheme.overline), + ); + } + + /// Applies the Crete Round font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crete+Round + static TextStyle creteRound({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '62fbd9c68fa6485a1a4fde14a03ed6a5268f26365fff7614e5704531390f0363', + 59264, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c8e915bc50126a1af673b8fbd3181aa9f8eac78545ec1b8d827ac5bac66b5cc5', + 67216, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CreteRound', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Crete Round font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crete+Round + static TextTheme creteRoundTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.creteRound(textStyle: textTheme.headline1), + headline2: GoogleFonts.creteRound(textStyle: textTheme.headline2), + headline3: GoogleFonts.creteRound(textStyle: textTheme.headline3), + headline4: GoogleFonts.creteRound(textStyle: textTheme.headline4), + headline5: GoogleFonts.creteRound(textStyle: textTheme.headline5), + headline6: GoogleFonts.creteRound(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.creteRound(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.creteRound(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.creteRound(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.creteRound(textStyle: textTheme.bodyText2), + caption: GoogleFonts.creteRound(textStyle: textTheme.caption), + button: GoogleFonts.creteRound(textStyle: textTheme.button), + overline: GoogleFonts.creteRound(textStyle: textTheme.overline), + ); + } + + /// Applies the Crimson Pro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crimson+Pro + static TextStyle crimsonPro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b66abfec21e34e91fc61b2ac08084816d4d166259ea2198ed01578a1ac727e5', + 89240, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9abd9060a62aa38f10dc60738f37bada274814485a3b3bef4353cbc2503358cc', + 89212, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '510241ec6793070724a690b137fdfb9f98422a611b8f81c1e6f22d345a0fef65', + 89216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c758f7367d51b291ba0a17386117e7269f7a438bb2dc40acedc1574b113e43e2', + 89248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a0668cef91f47f8b6609de80f66e247d934bc12467bed847c61ad8397297db31', + 89292, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '37a3b4d93b35047eba32401d0e748ed133547287e16a5bacc9e40c85d85b489c', + 89208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2fff124d10656b451037180b7611d390d0fb4f603400346db8986461325e2503', + 89300, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1e12367e6d503736e81c46a7e8dec43a84b804f31bcd06c8cd2e318cac7888b3', + 89264, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '02069dd1baa583bd54af1c82cd1979f3a078ee4087ddd6f64eb34b23c9370ee1', + 91212, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '96b97a5f9ec116f9f218a3b7de6daa5e95e9c6cb1c49b21f12e2df59d5ff2380', + 91168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '737b0264b20a8110302dc2f70673ca8320d865b82c59d69c354a1e54b2edde3e', + 91044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '654dd004b7fefe64e3ef615227b16e1da3abce493c844e6359cebe3bc1e98f18', + 91188, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c98a3ef2ed0a7bc571852f4b28fe383e22c671bf9696106fb88605680abfe9eb', + 91192, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dfc39b2565c337e814711b840e339b33b5f5b223042561963c34a8a4cfcd41c8', + 91052, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a2dfc4edba8a2ecffbdf37c1e7ffc640034bbf2e83449b7e5df15e39cd78be80', + 91200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a99ef7991d1f3adeaa296d774cdf32d4441511e024a0bf21a52b3cac625c49e9', + 91156, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CrimsonPro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Crimson Pro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crimson+Pro + static TextTheme crimsonProTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.crimsonPro(textStyle: textTheme.headline1), + headline2: GoogleFonts.crimsonPro(textStyle: textTheme.headline2), + headline3: GoogleFonts.crimsonPro(textStyle: textTheme.headline3), + headline4: GoogleFonts.crimsonPro(textStyle: textTheme.headline4), + headline5: GoogleFonts.crimsonPro(textStyle: textTheme.headline5), + headline6: GoogleFonts.crimsonPro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.crimsonPro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.crimsonPro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.crimsonPro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.crimsonPro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.crimsonPro(textStyle: textTheme.caption), + button: GoogleFonts.crimsonPro(textStyle: textTheme.button), + overline: GoogleFonts.crimsonPro(textStyle: textTheme.overline), + ); + } + + /// Applies the Crimson Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crimson+Text + static TextStyle crimsonText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '883d56072155a485051564cd3019bb34a608ddfa0553e2295413e7a59c67bd28', + 186656, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '33025a7588fc7f2ca1b8eb2b599e2420ad23278ee100a8f7e11c881d385af57a', + 98404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '37e75069b54a5c937eec2ba3fd3d193e3825fab2122bef2b86d86bc5ff1caab3', + 76316, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '15672e6c5d2b277c8dee2e6dcbffc17d3ba0c9a3018c446e199636f68dd227b1', + 74068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c6bfa338154c86d462eef6a8dc69f2443ecc35740bbdc2f2da06e7599c037cbc', + 92296, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c79dc3f51f37e16300b571c6835d06bff022a018b65d9ea69f1f897137acc238', + 74264, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CrimsonText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Crimson Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crimson+Text + static TextTheme crimsonTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.crimsonText(textStyle: textTheme.headline1), + headline2: GoogleFonts.crimsonText(textStyle: textTheme.headline2), + headline3: GoogleFonts.crimsonText(textStyle: textTheme.headline3), + headline4: GoogleFonts.crimsonText(textStyle: textTheme.headline4), + headline5: GoogleFonts.crimsonText(textStyle: textTheme.headline5), + headline6: GoogleFonts.crimsonText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.crimsonText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.crimsonText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.crimsonText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.crimsonText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.crimsonText(textStyle: textTheme.caption), + button: GoogleFonts.crimsonText(textStyle: textTheme.button), + overline: GoogleFonts.crimsonText(textStyle: textTheme.overline), + ); + } + + /// Applies the Croissant One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Croissant+One + static TextStyle croissantOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a51f330afdb3504b94cb09686589076855186483e4e89665623ebe0f655ce6ec', + 54696, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CroissantOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Croissant One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Croissant+One + static TextTheme croissantOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.croissantOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.croissantOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.croissantOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.croissantOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.croissantOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.croissantOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.croissantOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.croissantOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.croissantOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.croissantOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.croissantOne(textStyle: textTheme.caption), + button: GoogleFonts.croissantOne(textStyle: textTheme.button), + overline: GoogleFonts.croissantOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Crushed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crushed + static TextStyle crushed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f8487a87e68819238f02206a3eab5aedf7deae9e72b1010c364816df3934ab08', + 57404, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Crushed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Crushed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Crushed + static TextTheme crushedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.crushed(textStyle: textTheme.headline1), + headline2: GoogleFonts.crushed(textStyle: textTheme.headline2), + headline3: GoogleFonts.crushed(textStyle: textTheme.headline3), + headline4: GoogleFonts.crushed(textStyle: textTheme.headline4), + headline5: GoogleFonts.crushed(textStyle: textTheme.headline5), + headline6: GoogleFonts.crushed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.crushed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.crushed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.crushed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.crushed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.crushed(textStyle: textTheme.caption), + button: GoogleFonts.crushed(textStyle: textTheme.button), + overline: GoogleFonts.crushed(textStyle: textTheme.overline), + ); + } + + /// Applies the Cuprum font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cuprum + static TextStyle cuprum({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bddf1f3b7162539ab2c939e699c275d83ee353437fc657257d945347dce5c66d', + 69128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '27d4e15720e86dcbe0f0f3e93656c40e57203137b143f5a396d8a56e654963c8', + 73796, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0a3719a13307973f16e4ebfb3980da3f7d190316e71ada51aa42650b95524c97', + 68608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9bac99436b2027f87f8c0f692398a62b76be18874fbda4ea2b56aaa99553e6b2', + 73828, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cuprum', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cuprum font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cuprum + static TextTheme cuprumTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cuprum(textStyle: textTheme.headline1), + headline2: GoogleFonts.cuprum(textStyle: textTheme.headline2), + headline3: GoogleFonts.cuprum(textStyle: textTheme.headline3), + headline4: GoogleFonts.cuprum(textStyle: textTheme.headline4), + headline5: GoogleFonts.cuprum(textStyle: textTheme.headline5), + headline6: GoogleFonts.cuprum(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cuprum(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cuprum(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cuprum(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cuprum(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cuprum(textStyle: textTheme.caption), + button: GoogleFonts.cuprum(textStyle: textTheme.button), + overline: GoogleFonts.cuprum(textStyle: textTheme.overline), + ); + } + + /// Applies the Cute Font font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cute+Font + static TextStyle cuteFont({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '264e6741d6541397294f9de009ed33b609adf005445eaf7a346c99b03ae75feb', + 598524, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CuteFont', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cute Font font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cute+Font + static TextTheme cuteFontTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cuteFont(textStyle: textTheme.headline1), + headline2: GoogleFonts.cuteFont(textStyle: textTheme.headline2), + headline3: GoogleFonts.cuteFont(textStyle: textTheme.headline3), + headline4: GoogleFonts.cuteFont(textStyle: textTheme.headline4), + headline5: GoogleFonts.cuteFont(textStyle: textTheme.headline5), + headline6: GoogleFonts.cuteFont(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cuteFont(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cuteFont(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cuteFont(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cuteFont(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cuteFont(textStyle: textTheme.caption), + button: GoogleFonts.cuteFont(textStyle: textTheme.button), + overline: GoogleFonts.cuteFont(textStyle: textTheme.overline), + ); + } + + /// Applies the Cutive font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cutive + static TextStyle cutive({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2e0849ce3a9bd06c1d093ce26a2727da8b032430d3d39d191cfd79df0983d490', + 41960, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Cutive', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cutive font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cutive + static TextTheme cutiveTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cutive(textStyle: textTheme.headline1), + headline2: GoogleFonts.cutive(textStyle: textTheme.headline2), + headline3: GoogleFonts.cutive(textStyle: textTheme.headline3), + headline4: GoogleFonts.cutive(textStyle: textTheme.headline4), + headline5: GoogleFonts.cutive(textStyle: textTheme.headline5), + headline6: GoogleFonts.cutive(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cutive(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cutive(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cutive(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cutive(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cutive(textStyle: textTheme.caption), + button: GoogleFonts.cutive(textStyle: textTheme.button), + overline: GoogleFonts.cutive(textStyle: textTheme.overline), + ); + } + + /// Applies the Cutive Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cutive+Mono + static TextStyle cutiveMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0582d0fd288afe72a3eeebdace411705bd456580eb96ee5ef7214afd771ebfce', + 47056, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'CutiveMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Cutive Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Cutive+Mono + static TextTheme cutiveMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.cutiveMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.cutiveMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.cutiveMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.cutiveMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.cutiveMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.cutiveMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.cutiveMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.cutiveMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.cutiveMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.cutiveMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.cutiveMono(textStyle: textTheme.caption), + button: GoogleFonts.cutiveMono(textStyle: textTheme.button), + overline: GoogleFonts.cutiveMono(textStyle: textTheme.overline), + ); + } + + /// Applies the DM Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/DM+Mono + static TextStyle dmMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '67638f30d87fc69f052f1ff91f488200a8696ecf2b7e200036b6ba7134665f02', + 27896, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '531245107d1e3f2c1cd8ddeb9bbf214cc2f7412495cc15ffd4a9a6553b677537', + 29060, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a9692116a4d8c7abc9a734c6963264b73434254a7b6997a40c0df383364df2c2', + 27932, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eb74ddafb17f67359ab3426667e45e12054b3f2cd578a90880155a897a551ebf', + 29072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0c46ab9994bad814204dd36ade2daafac04937ed6c8620de135d159ee5a4aaad', + 27776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fe7c6a70b6d89fc903dcb90540d3cba6a078c080ad52ed9eda41becba14ff343', + 29096, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DMMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the DM Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/DM+Mono + static TextTheme dmMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dmMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.dmMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.dmMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.dmMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.dmMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.dmMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dmMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dmMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dmMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dmMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dmMono(textStyle: textTheme.caption), + button: GoogleFonts.dmMono(textStyle: textTheme.button), + overline: GoogleFonts.dmMono(textStyle: textTheme.overline), + ); + } + + /// Applies the DM Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/DM+Sans + static TextStyle dmSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e518fdb0a5c0ebe0d1d1b02a9025067837e79d235418ab9dc8366e7ce87fad55', + 43504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'de4a1215c7928ebdd157181021531f87614894038bb9396b05826b7ae9595611', + 44712, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '683cd0ce949642886f9652656cfe66d569a79d1530fcde104214769c266ae121', + 43300, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c3126b61a6d535d42dd4e6e4eb66648863d4d4f9bf639d63da74d20cb3fa1fb4', + 44576, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '940d8601e85100233071b73474474f0ea11612beecddd6da32efb7cd8a3971bd', + 43236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '579b8c8cd4a4fd71ee7ac563e399eacbcba63f3f8556516c95830d98bb9fbae9', + 44512, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DMSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the DM Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/DM+Sans + static TextTheme dmSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dmSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.dmSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.dmSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.dmSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.dmSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.dmSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dmSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dmSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dmSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dmSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dmSans(textStyle: textTheme.caption), + button: GoogleFonts.dmSans(textStyle: textTheme.button), + overline: GoogleFonts.dmSans(textStyle: textTheme.overline), + ); + } + + /// Applies the DM Serif Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/DM+Serif+Display + static TextStyle dmSerifDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e1157689ec181ea520aeee52f8f7f8c16e0ced52d30800c402aae31faf50985a', + 56068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '007cfd580d7b1323a1b43156d2591b8119745361daba6117832dcbfb0146a36a', + 50564, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DMSerifDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the DM Serif Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/DM+Serif+Display + static TextTheme dmSerifDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dmSerifDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.dmSerifDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.dmSerifDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.dmSerifDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.dmSerifDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.dmSerifDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dmSerifDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dmSerifDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dmSerifDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dmSerifDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dmSerifDisplay(textStyle: textTheme.caption), + button: GoogleFonts.dmSerifDisplay(textStyle: textTheme.button), + overline: GoogleFonts.dmSerifDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the DM Serif Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/DM+Serif+Text + static TextStyle dmSerifText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8fe3c6727cf74e86cfd545dfe7e6aa3a1dbdff9563e84e085acd65c07f633744', + 56120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '13b9bbb9c2b065c645eb14efbe2bc8dd2a4e41e635d12f8bc15b532e1d5fc628', + 50372, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DMSerifText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the DM Serif Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/DM+Serif+Text + static TextTheme dmSerifTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dmSerifText(textStyle: textTheme.headline1), + headline2: GoogleFonts.dmSerifText(textStyle: textTheme.headline2), + headline3: GoogleFonts.dmSerifText(textStyle: textTheme.headline3), + headline4: GoogleFonts.dmSerifText(textStyle: textTheme.headline4), + headline5: GoogleFonts.dmSerifText(textStyle: textTheme.headline5), + headline6: GoogleFonts.dmSerifText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dmSerifText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dmSerifText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dmSerifText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dmSerifText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dmSerifText(textStyle: textTheme.caption), + button: GoogleFonts.dmSerifText(textStyle: textTheme.button), + overline: GoogleFonts.dmSerifText(textStyle: textTheme.overline), + ); + } + + /// Applies the Damion font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Damion + static TextStyle damion({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2b178966c9329bdd54a10c83e076dc1647443dddd2471c9aa477780c6852294c', + 51972, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Damion', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Damion font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Damion + static TextTheme damionTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.damion(textStyle: textTheme.headline1), + headline2: GoogleFonts.damion(textStyle: textTheme.headline2), + headline3: GoogleFonts.damion(textStyle: textTheme.headline3), + headline4: GoogleFonts.damion(textStyle: textTheme.headline4), + headline5: GoogleFonts.damion(textStyle: textTheme.headline5), + headline6: GoogleFonts.damion(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.damion(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.damion(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.damion(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.damion(textStyle: textTheme.bodyText2), + caption: GoogleFonts.damion(textStyle: textTheme.caption), + button: GoogleFonts.damion(textStyle: textTheme.button), + overline: GoogleFonts.damion(textStyle: textTheme.overline), + ); + } + + /// Applies the Dancing Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dancing+Script + static TextStyle dancingScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '40f021e25f9f4e2b67f5072ac941218596581a1621931f44173cbf5245b91fd3', + 90100, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a2aa446dc86aad49ec46eb66fb313889bded9ef23f286664bba90a2eb156f87', + 89456, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DancingScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dancing Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dancing+Script + static TextTheme dancingScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dancingScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.dancingScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.dancingScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.dancingScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.dancingScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.dancingScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dancingScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dancingScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dancingScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dancingScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dancingScript(textStyle: textTheme.caption), + button: GoogleFonts.dancingScript(textStyle: textTheme.button), + overline: GoogleFonts.dancingScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Darker Grotesque font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Darker+Grotesque + static TextStyle darkerGrotesque({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f789e82ef267fb0b5f0798267ba5e3340b661840b52e1de87f7830b7d87a180e', + 40352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '60303e0b600c0176b00422a680228f744d38795fbd8d35344f494b02400628c1', + 42704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a6e1eb6614b97b3298d1d253f5ed4399556da5b06bb191596cebfc813bdd3505', + 42568, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3e516ad3d1d4cec56249227f367cba1e2830faa7cedbcf49abca81e7c202b434', + 42552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b56136288e57809ada8707a74f6756261c3763b3a2686398738c1fd25f157d9c', + 42600, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cf5f4f44b908aeed8723415a103b1ad9c5550388d2c8e139adab630a61a74712', + 42632, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eae6b24bfd325c090ef4a304519707f58942487ea7e118bfe036175f8c4690aa', + 42032, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DarkerGrotesque', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Darker Grotesque font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Darker+Grotesque + static TextTheme darkerGrotesqueTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.darkerGrotesque(textStyle: textTheme.headline1), + headline2: GoogleFonts.darkerGrotesque(textStyle: textTheme.headline2), + headline3: GoogleFonts.darkerGrotesque(textStyle: textTheme.headline3), + headline4: GoogleFonts.darkerGrotesque(textStyle: textTheme.headline4), + headline5: GoogleFonts.darkerGrotesque(textStyle: textTheme.headline5), + headline6: GoogleFonts.darkerGrotesque(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.darkerGrotesque(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.darkerGrotesque(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.darkerGrotesque(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.darkerGrotesque(textStyle: textTheme.bodyText2), + caption: GoogleFonts.darkerGrotesque(textStyle: textTheme.caption), + button: GoogleFonts.darkerGrotesque(textStyle: textTheme.button), + overline: GoogleFonts.darkerGrotesque(textStyle: textTheme.overline), + ); + } + + /// Applies the David Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/David+Libre + static TextStyle davidLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8319053cbaa4074884c0364b74327548dbe246119e76a214a864d9d55a12353d', + 91296, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '288d258f0790230352ec2d9b0eef7f533d14554250a99cd0b5cfc80c349d2b38', + 91348, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd02a7be354414e34512a70b5f00901c7c3c4e7df88c6bab47e8ed2e50c770c71', + 92540, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DavidLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the David Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/David+Libre + static TextTheme davidLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.davidLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.davidLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.davidLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.davidLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.davidLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.davidLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.davidLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.davidLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.davidLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.davidLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.davidLibre(textStyle: textTheme.caption), + button: GoogleFonts.davidLibre(textStyle: textTheme.button), + overline: GoogleFonts.davidLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Dawning of a New Day font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dawning+of+a+New+Day + static TextStyle dawningOfANewDay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c8fb2c187b599f0368577f599628c83a2543f4c757231bb2c0843e98624eeb4a', + 65320, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DawningofaNewDay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dawning of a New Day font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dawning+of+a+New+Day + static TextTheme dawningOfANewDayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dawningOfANewDay(textStyle: textTheme.headline1), + headline2: GoogleFonts.dawningOfANewDay(textStyle: textTheme.headline2), + headline3: GoogleFonts.dawningOfANewDay(textStyle: textTheme.headline3), + headline4: GoogleFonts.dawningOfANewDay(textStyle: textTheme.headline4), + headline5: GoogleFonts.dawningOfANewDay(textStyle: textTheme.headline5), + headline6: GoogleFonts.dawningOfANewDay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dawningOfANewDay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dawningOfANewDay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dawningOfANewDay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dawningOfANewDay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dawningOfANewDay(textStyle: textTheme.caption), + button: GoogleFonts.dawningOfANewDay(textStyle: textTheme.button), + overline: GoogleFonts.dawningOfANewDay(textStyle: textTheme.overline), + ); + } + + /// Applies the Days One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Days+One + static TextStyle daysOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd74812297ac57cf4ce637c47f01cbcab907136f76e2a4028e2ad1e80bd7b8ab0', + 65556, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DaysOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Days One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Days+One + static TextTheme daysOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.daysOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.daysOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.daysOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.daysOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.daysOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.daysOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.daysOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.daysOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.daysOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.daysOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.daysOne(textStyle: textTheme.caption), + button: GoogleFonts.daysOne(textStyle: textTheme.button), + overline: GoogleFonts.daysOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Dekko font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dekko + static TextStyle dekko({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '71d66d24dfda326e074654507fa7b6be6a766f318cf01f17b000fdc6f870fb4d', + 214656, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Dekko', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dekko font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dekko + static TextTheme dekkoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dekko(textStyle: textTheme.headline1), + headline2: GoogleFonts.dekko(textStyle: textTheme.headline2), + headline3: GoogleFonts.dekko(textStyle: textTheme.headline3), + headline4: GoogleFonts.dekko(textStyle: textTheme.headline4), + headline5: GoogleFonts.dekko(textStyle: textTheme.headline5), + headline6: GoogleFonts.dekko(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dekko(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dekko(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dekko(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dekko(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dekko(textStyle: textTheme.caption), + button: GoogleFonts.dekko(textStyle: textTheme.button), + overline: GoogleFonts.dekko(textStyle: textTheme.overline), + ); + } + + /// Applies the Delius font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Delius + static TextStyle delius({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '882839f3551cbef380971b00494ffc16ba5b2f9841166599a0248fa4f6855cae', + 77440, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Delius', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Delius font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Delius + static TextTheme deliusTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.delius(textStyle: textTheme.headline1), + headline2: GoogleFonts.delius(textStyle: textTheme.headline2), + headline3: GoogleFonts.delius(textStyle: textTheme.headline3), + headline4: GoogleFonts.delius(textStyle: textTheme.headline4), + headline5: GoogleFonts.delius(textStyle: textTheme.headline5), + headline6: GoogleFonts.delius(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.delius(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.delius(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.delius(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.delius(textStyle: textTheme.bodyText2), + caption: GoogleFonts.delius(textStyle: textTheme.caption), + button: GoogleFonts.delius(textStyle: textTheme.button), + overline: GoogleFonts.delius(textStyle: textTheme.overline), + ); + } + + /// Applies the Delius Swash Caps font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Delius+Swash+Caps + static TextStyle deliusSwashCaps({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8a724c6c792da2cb102b6583bf9f9ed02312ab78bbeeb3c6a6efb9ddb096ae29', + 63004, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DeliusSwashCaps', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Delius Swash Caps font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Delius+Swash+Caps + static TextTheme deliusSwashCapsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.deliusSwashCaps(textStyle: textTheme.headline1), + headline2: GoogleFonts.deliusSwashCaps(textStyle: textTheme.headline2), + headline3: GoogleFonts.deliusSwashCaps(textStyle: textTheme.headline3), + headline4: GoogleFonts.deliusSwashCaps(textStyle: textTheme.headline4), + headline5: GoogleFonts.deliusSwashCaps(textStyle: textTheme.headline5), + headline6: GoogleFonts.deliusSwashCaps(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.deliusSwashCaps(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.deliusSwashCaps(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.deliusSwashCaps(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.deliusSwashCaps(textStyle: textTheme.bodyText2), + caption: GoogleFonts.deliusSwashCaps(textStyle: textTheme.caption), + button: GoogleFonts.deliusSwashCaps(textStyle: textTheme.button), + overline: GoogleFonts.deliusSwashCaps(textStyle: textTheme.overline), + ); + } + + /// Applies the Delius Unicase font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Delius+Unicase + static TextStyle deliusUnicase({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3bbebd3cb94431156468b1ce457ee032a1f68d964171655b60f5ae2ecf0243cb', + 32856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f761b09efebd15e0a91eabc186d565aec75f56f2b04f9cb1ed1f72d91be340ef', + 36072, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DeliusUnicase', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Delius Unicase font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Delius+Unicase + static TextTheme deliusUnicaseTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.deliusUnicase(textStyle: textTheme.headline1), + headline2: GoogleFonts.deliusUnicase(textStyle: textTheme.headline2), + headline3: GoogleFonts.deliusUnicase(textStyle: textTheme.headline3), + headline4: GoogleFonts.deliusUnicase(textStyle: textTheme.headline4), + headline5: GoogleFonts.deliusUnicase(textStyle: textTheme.headline5), + headline6: GoogleFonts.deliusUnicase(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.deliusUnicase(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.deliusUnicase(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.deliusUnicase(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.deliusUnicase(textStyle: textTheme.bodyText2), + caption: GoogleFonts.deliusUnicase(textStyle: textTheme.caption), + button: GoogleFonts.deliusUnicase(textStyle: textTheme.button), + overline: GoogleFonts.deliusUnicase(textStyle: textTheme.overline), + ); + } + + /// Applies the Della Respira font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Della+Respira + static TextStyle dellaRespira({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '62fa46916df65faadfa21dd5608cda99cea245fc2f736046a2118b3a95fa93ff', + 51140, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DellaRespira', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Della Respira font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Della+Respira + static TextTheme dellaRespiraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dellaRespira(textStyle: textTheme.headline1), + headline2: GoogleFonts.dellaRespira(textStyle: textTheme.headline2), + headline3: GoogleFonts.dellaRespira(textStyle: textTheme.headline3), + headline4: GoogleFonts.dellaRespira(textStyle: textTheme.headline4), + headline5: GoogleFonts.dellaRespira(textStyle: textTheme.headline5), + headline6: GoogleFonts.dellaRespira(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dellaRespira(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dellaRespira(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dellaRespira(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dellaRespira(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dellaRespira(textStyle: textTheme.caption), + button: GoogleFonts.dellaRespira(textStyle: textTheme.button), + overline: GoogleFonts.dellaRespira(textStyle: textTheme.overline), + ); + } + + /// Applies the Denk One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Denk+One + static TextStyle denkOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '213821a54136d58fd7013e4aca0f3b0307e9ec564c83ce75d6a9e63bfb6b1714', + 36128, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DenkOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Denk One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Denk+One + static TextTheme denkOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.denkOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.denkOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.denkOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.denkOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.denkOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.denkOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.denkOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.denkOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.denkOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.denkOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.denkOne(textStyle: textTheme.caption), + button: GoogleFonts.denkOne(textStyle: textTheme.button), + overline: GoogleFonts.denkOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Devonshire font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Devonshire + static TextStyle devonshire({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c62bc196f0a12683281e3842a99600f4f4755582173bca74502c02f9cf997854', + 67192, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Devonshire', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Devonshire font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Devonshire + static TextTheme devonshireTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.devonshire(textStyle: textTheme.headline1), + headline2: GoogleFonts.devonshire(textStyle: textTheme.headline2), + headline3: GoogleFonts.devonshire(textStyle: textTheme.headline3), + headline4: GoogleFonts.devonshire(textStyle: textTheme.headline4), + headline5: GoogleFonts.devonshire(textStyle: textTheme.headline5), + headline6: GoogleFonts.devonshire(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.devonshire(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.devonshire(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.devonshire(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.devonshire(textStyle: textTheme.bodyText2), + caption: GoogleFonts.devonshire(textStyle: textTheme.caption), + button: GoogleFonts.devonshire(textStyle: textTheme.button), + overline: GoogleFonts.devonshire(textStyle: textTheme.overline), + ); + } + + /// Applies the Dhurjati font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dhurjati + static TextStyle dhurjati({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ee0b382be9acedd63b3e624d49e646e5951cb5e8d54c0724ad01128bd8690012', + 546952, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Dhurjati', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dhurjati font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dhurjati + static TextTheme dhurjatiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dhurjati(textStyle: textTheme.headline1), + headline2: GoogleFonts.dhurjati(textStyle: textTheme.headline2), + headline3: GoogleFonts.dhurjati(textStyle: textTheme.headline3), + headline4: GoogleFonts.dhurjati(textStyle: textTheme.headline4), + headline5: GoogleFonts.dhurjati(textStyle: textTheme.headline5), + headline6: GoogleFonts.dhurjati(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dhurjati(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dhurjati(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dhurjati(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dhurjati(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dhurjati(textStyle: textTheme.caption), + button: GoogleFonts.dhurjati(textStyle: textTheme.button), + overline: GoogleFonts.dhurjati(textStyle: textTheme.overline), + ); + } + + /// Applies the Didact Gothic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Didact+Gothic + static TextStyle didactGothic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c28f009d8ad88ab0414e29aabe1ad9f19a95836e772d9cb369f27a1ee0b23fa0', + 132548, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DidactGothic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Didact Gothic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Didact+Gothic + static TextTheme didactGothicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.didactGothic(textStyle: textTheme.headline1), + headline2: GoogleFonts.didactGothic(textStyle: textTheme.headline2), + headline3: GoogleFonts.didactGothic(textStyle: textTheme.headline3), + headline4: GoogleFonts.didactGothic(textStyle: textTheme.headline4), + headline5: GoogleFonts.didactGothic(textStyle: textTheme.headline5), + headline6: GoogleFonts.didactGothic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.didactGothic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.didactGothic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.didactGothic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.didactGothic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.didactGothic(textStyle: textTheme.caption), + button: GoogleFonts.didactGothic(textStyle: textTheme.button), + overline: GoogleFonts.didactGothic(textStyle: textTheme.overline), + ); + } + + /// Applies the Diplomata font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Diplomata + static TextStyle diplomata({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ff25ccc70ef0385bf72a71864293132375bd427ee6e3f974f22a732523948936', + 43060, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Diplomata', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Diplomata font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Diplomata + static TextTheme diplomataTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.diplomata(textStyle: textTheme.headline1), + headline2: GoogleFonts.diplomata(textStyle: textTheme.headline2), + headline3: GoogleFonts.diplomata(textStyle: textTheme.headline3), + headline4: GoogleFonts.diplomata(textStyle: textTheme.headline4), + headline5: GoogleFonts.diplomata(textStyle: textTheme.headline5), + headline6: GoogleFonts.diplomata(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.diplomata(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.diplomata(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.diplomata(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.diplomata(textStyle: textTheme.bodyText2), + caption: GoogleFonts.diplomata(textStyle: textTheme.caption), + button: GoogleFonts.diplomata(textStyle: textTheme.button), + overline: GoogleFonts.diplomata(textStyle: textTheme.overline), + ); + } + + /// Applies the Diplomata SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Diplomata+SC + static TextStyle diplomataSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '35ea29b9848142b1f5c17b6b53c1ee204e69fe31d85cd0d67ab75f358b968c33', + 42396, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DiplomataSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Diplomata SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Diplomata+SC + static TextTheme diplomataScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.diplomataSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.diplomataSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.diplomataSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.diplomataSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.diplomataSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.diplomataSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.diplomataSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.diplomataSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.diplomataSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.diplomataSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.diplomataSc(textStyle: textTheme.caption), + button: GoogleFonts.diplomataSc(textStyle: textTheme.button), + overline: GoogleFonts.diplomataSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Do Hyeon font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Do+Hyeon + static TextStyle doHyeon({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f24aa5cecd71141bf907f712b4e1a8d1ae20bfc48e6f4c397af431431965c7c3', + 408356, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DoHyeon', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Do Hyeon font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Do+Hyeon + static TextTheme doHyeonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.doHyeon(textStyle: textTheme.headline1), + headline2: GoogleFonts.doHyeon(textStyle: textTheme.headline2), + headline3: GoogleFonts.doHyeon(textStyle: textTheme.headline3), + headline4: GoogleFonts.doHyeon(textStyle: textTheme.headline4), + headline5: GoogleFonts.doHyeon(textStyle: textTheme.headline5), + headline6: GoogleFonts.doHyeon(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.doHyeon(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.doHyeon(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.doHyeon(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.doHyeon(textStyle: textTheme.bodyText2), + caption: GoogleFonts.doHyeon(textStyle: textTheme.caption), + button: GoogleFonts.doHyeon(textStyle: textTheme.button), + overline: GoogleFonts.doHyeon(textStyle: textTheme.overline), + ); + } + + /// Applies the Dokdo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dokdo + static TextStyle dokdo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b88083d5e2a376a3766403b0ff323016dd93814b3d540b48859e517dbcc28d08', + 1385696, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Dokdo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dokdo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dokdo + static TextTheme dokdoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dokdo(textStyle: textTheme.headline1), + headline2: GoogleFonts.dokdo(textStyle: textTheme.headline2), + headline3: GoogleFonts.dokdo(textStyle: textTheme.headline3), + headline4: GoogleFonts.dokdo(textStyle: textTheme.headline4), + headline5: GoogleFonts.dokdo(textStyle: textTheme.headline5), + headline6: GoogleFonts.dokdo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dokdo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dokdo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dokdo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dokdo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dokdo(textStyle: textTheme.caption), + button: GoogleFonts.dokdo(textStyle: textTheme.button), + overline: GoogleFonts.dokdo(textStyle: textTheme.overline), + ); + } + + /// Applies the Domine font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Domine + static TextStyle domine({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7b5d61cb478ce2e3fd32416939a39f3b9aa118d0eb76c107195e0857c44ada1c', + 89788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5865b0de838f6cabefc862631b06e8c7e86a0b8865e9ee530819d8590dd23e6f', + 91860, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Domine', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Domine font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Domine + static TextTheme domineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.domine(textStyle: textTheme.headline1), + headline2: GoogleFonts.domine(textStyle: textTheme.headline2), + headline3: GoogleFonts.domine(textStyle: textTheme.headline3), + headline4: GoogleFonts.domine(textStyle: textTheme.headline4), + headline5: GoogleFonts.domine(textStyle: textTheme.headline5), + headline6: GoogleFonts.domine(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.domine(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.domine(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.domine(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.domine(textStyle: textTheme.bodyText2), + caption: GoogleFonts.domine(textStyle: textTheme.caption), + button: GoogleFonts.domine(textStyle: textTheme.button), + overline: GoogleFonts.domine(textStyle: textTheme.overline), + ); + } + + /// Applies the Donegal One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Donegal+One + static TextStyle donegalOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '75cadf3ba9559e8ba497b68a3e7695d2c733b4ce2264119f7f181974902025ba', + 44828, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DonegalOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Donegal One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Donegal+One + static TextTheme donegalOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.donegalOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.donegalOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.donegalOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.donegalOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.donegalOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.donegalOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.donegalOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.donegalOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.donegalOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.donegalOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.donegalOne(textStyle: textTheme.caption), + button: GoogleFonts.donegalOne(textStyle: textTheme.button), + overline: GoogleFonts.donegalOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Doppio One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Doppio+One + static TextStyle doppioOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '72f56b16a716f87ccdb2d2fa52196eb1c365c8b142e58ef5bc106a01345cdc28', + 36952, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DoppioOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Doppio One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Doppio+One + static TextTheme doppioOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.doppioOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.doppioOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.doppioOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.doppioOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.doppioOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.doppioOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.doppioOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.doppioOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.doppioOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.doppioOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.doppioOne(textStyle: textTheme.caption), + button: GoogleFonts.doppioOne(textStyle: textTheme.button), + overline: GoogleFonts.doppioOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Dorsa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dorsa + static TextStyle dorsa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0126c6beb66497797a2fe86e3ceecbd95fadcc67cd7ba35e2b604acdda520730', + 20796, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Dorsa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dorsa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dorsa + static TextTheme dorsaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dorsa(textStyle: textTheme.headline1), + headline2: GoogleFonts.dorsa(textStyle: textTheme.headline2), + headline3: GoogleFonts.dorsa(textStyle: textTheme.headline3), + headline4: GoogleFonts.dorsa(textStyle: textTheme.headline4), + headline5: GoogleFonts.dorsa(textStyle: textTheme.headline5), + headline6: GoogleFonts.dorsa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dorsa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dorsa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dorsa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dorsa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dorsa(textStyle: textTheme.caption), + button: GoogleFonts.dorsa(textStyle: textTheme.button), + overline: GoogleFonts.dorsa(textStyle: textTheme.overline), + ); + } + + /// Applies the Dosis font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dosis + static TextStyle dosis({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3ae9ee353b3e8df71d17a46208649ec71c145848f8db69eb86b9cc1c129304b7', + 82420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'be02e69501081e964d549ca957d036bbb12e816c1d224d1ce145ca31499bdfa0', + 82544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '313cd3d73107761779313dba36f6ec6a100a5a4daf06f4b78f8f733538936cdf', + 83240, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b1bef4924c728f63829085fe2ca4995a6a41c495df45c5830d51bf649e273031', + 82808, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b8741fdb78479290fcd114044c58c9263670dd32db70b744dd56764a8d0b734', + 82668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4124ad4492dbb70075dd1bce8976da33cbad57f2fc10eeedc7da35592285605d', + 82876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a7b18554b3247dd3b1384afabd828043b9a9417221c7480c2bb78a99bc4190b', + 84236, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Dosis', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dosis font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dosis + static TextTheme dosisTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dosis(textStyle: textTheme.headline1), + headline2: GoogleFonts.dosis(textStyle: textTheme.headline2), + headline3: GoogleFonts.dosis(textStyle: textTheme.headline3), + headline4: GoogleFonts.dosis(textStyle: textTheme.headline4), + headline5: GoogleFonts.dosis(textStyle: textTheme.headline5), + headline6: GoogleFonts.dosis(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dosis(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dosis(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dosis(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dosis(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dosis(textStyle: textTheme.caption), + button: GoogleFonts.dosis(textStyle: textTheme.button), + overline: GoogleFonts.dosis(textStyle: textTheme.overline), + ); + } + + /// Applies the Dr Sugiyama font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dr+Sugiyama + static TextStyle drSugiyama({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '222640befef81fb644265039a2b7df8ab86103b0d4427b5a88b9fb9ebbbcd273', + 39880, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DrSugiyama', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dr Sugiyama font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dr+Sugiyama + static TextTheme drSugiyamaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.drSugiyama(textStyle: textTheme.headline1), + headline2: GoogleFonts.drSugiyama(textStyle: textTheme.headline2), + headline3: GoogleFonts.drSugiyama(textStyle: textTheme.headline3), + headline4: GoogleFonts.drSugiyama(textStyle: textTheme.headline4), + headline5: GoogleFonts.drSugiyama(textStyle: textTheme.headline5), + headline6: GoogleFonts.drSugiyama(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.drSugiyama(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.drSugiyama(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.drSugiyama(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.drSugiyama(textStyle: textTheme.bodyText2), + caption: GoogleFonts.drSugiyama(textStyle: textTheme.caption), + button: GoogleFonts.drSugiyama(textStyle: textTheme.button), + overline: GoogleFonts.drSugiyama(textStyle: textTheme.overline), + ); + } + + /// Applies the Droid Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Droid+Sans + static TextStyle droidSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b1efe4b6a8b73a7069e3a5ede472fb84130f7ffaaded682d112e93f0d0fa5a9f', + 25204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '32b87a290fa91f892687dcef391f2b06945d1be8f3dc243b55ffb118388368de', + 25328, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DroidSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Droid Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Droid+Sans + static TextTheme droidSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.droidSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.droidSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.droidSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.droidSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.droidSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.droidSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.droidSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.droidSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.droidSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.droidSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.droidSans(textStyle: textTheme.caption), + button: GoogleFonts.droidSans(textStyle: textTheme.button), + overline: GoogleFonts.droidSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Droid Sans Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Droid+Sans+Mono + static TextStyle droidSansMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9dedfe943434b0c1c69af3c64930ea43797584f7c25bfe1bafe167c5b9ed0909', + 65556, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DroidSansMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Droid Sans Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Droid+Sans+Mono + static TextTheme droidSansMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.droidSansMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.droidSansMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.droidSansMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.droidSansMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.droidSansMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.droidSansMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.droidSansMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.droidSansMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.droidSansMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.droidSansMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.droidSansMono(textStyle: textTheme.caption), + button: GoogleFonts.droidSansMono(textStyle: textTheme.button), + overline: GoogleFonts.droidSansMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Droid Serif font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Droid+Serif + static TextStyle droidSerif({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dcdbbe04f7d65d6dd062e948aad5cedf59b28322fcd555a4dbff9564ba77f032', + 28380, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f2412575e58a24ba7f60d09803924763e7420e8a18ef8535551454a69b0e2765', + 23792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '11fcb243238a8c4df11d23a99078e060b56b2f23e44efcdf3323fde6290297fb', + 28408, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5072734295fa76a5684706f1c6fab998057ea2dbd03ed74b92b6b105d694e505', + 29980, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DroidSerif', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Droid Serif font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Droid+Serif + static TextTheme droidSerifTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.droidSerif(textStyle: textTheme.headline1), + headline2: GoogleFonts.droidSerif(textStyle: textTheme.headline2), + headline3: GoogleFonts.droidSerif(textStyle: textTheme.headline3), + headline4: GoogleFonts.droidSerif(textStyle: textTheme.headline4), + headline5: GoogleFonts.droidSerif(textStyle: textTheme.headline5), + headline6: GoogleFonts.droidSerif(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.droidSerif(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.droidSerif(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.droidSerif(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.droidSerif(textStyle: textTheme.bodyText2), + caption: GoogleFonts.droidSerif(textStyle: textTheme.caption), + button: GoogleFonts.droidSerif(textStyle: textTheme.button), + overline: GoogleFonts.droidSerif(textStyle: textTheme.overline), + ); + } + + /// Applies the Duru Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Duru+Sans + static TextStyle duruSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '97e1b1a772ca2113d6a27390b0c7b2ce1a3b72cebf29a876a253b200136fd5b1', + 50832, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'DuruSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Duru Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Duru+Sans + static TextTheme duruSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.duruSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.duruSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.duruSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.duruSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.duruSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.duruSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.duruSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.duruSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.duruSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.duruSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.duruSans(textStyle: textTheme.caption), + button: GoogleFonts.duruSans(textStyle: textTheme.button), + overline: GoogleFonts.duruSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Dynalight font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dynalight + static TextStyle dynalight({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3380e0bde50ff63e8151f548155d2d265154e826a3fcd8e17eda92dd29d14064', + 52732, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Dynalight', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Dynalight font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Dynalight + static TextTheme dynalightTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.dynalight(textStyle: textTheme.headline1), + headline2: GoogleFonts.dynalight(textStyle: textTheme.headline2), + headline3: GoogleFonts.dynalight(textStyle: textTheme.headline3), + headline4: GoogleFonts.dynalight(textStyle: textTheme.headline4), + headline5: GoogleFonts.dynalight(textStyle: textTheme.headline5), + headline6: GoogleFonts.dynalight(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.dynalight(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.dynalight(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.dynalight(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.dynalight(textStyle: textTheme.bodyText2), + caption: GoogleFonts.dynalight(textStyle: textTheme.caption), + button: GoogleFonts.dynalight(textStyle: textTheme.button), + overline: GoogleFonts.dynalight(textStyle: textTheme.overline), + ); + } + + /// Applies the EB Garamond font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/EB+Garamond + static TextStyle ebGaramond({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '45b9fd8b021be544bd8edb0bce9007faafdc3029fdb0f19e4deb80b50e9c4adb', + 231176, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EBGaramond', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the EB Garamond font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/EB+Garamond + static TextTheme ebGaramondTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ebGaramond(textStyle: textTheme.headline1), + headline2: GoogleFonts.ebGaramond(textStyle: textTheme.headline2), + headline3: GoogleFonts.ebGaramond(textStyle: textTheme.headline3), + headline4: GoogleFonts.ebGaramond(textStyle: textTheme.headline4), + headline5: GoogleFonts.ebGaramond(textStyle: textTheme.headline5), + headline6: GoogleFonts.ebGaramond(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ebGaramond(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ebGaramond(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ebGaramond(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ebGaramond(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ebGaramond(textStyle: textTheme.caption), + button: GoogleFonts.ebGaramond(textStyle: textTheme.button), + overline: GoogleFonts.ebGaramond(textStyle: textTheme.overline), + ); + } + + /// Applies the Eagle Lake font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Eagle+Lake + static TextStyle eagleLake({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6a898ae440d1344e4a9d2174f6ee6479f00108b9baa6830fa6535a8cae6185fe', + 77584, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EagleLake', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Eagle Lake font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Eagle+Lake + static TextTheme eagleLakeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.eagleLake(textStyle: textTheme.headline1), + headline2: GoogleFonts.eagleLake(textStyle: textTheme.headline2), + headline3: GoogleFonts.eagleLake(textStyle: textTheme.headline3), + headline4: GoogleFonts.eagleLake(textStyle: textTheme.headline4), + headline5: GoogleFonts.eagleLake(textStyle: textTheme.headline5), + headline6: GoogleFonts.eagleLake(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.eagleLake(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.eagleLake(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.eagleLake(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.eagleLake(textStyle: textTheme.bodyText2), + caption: GoogleFonts.eagleLake(textStyle: textTheme.caption), + button: GoogleFonts.eagleLake(textStyle: textTheme.button), + overline: GoogleFonts.eagleLake(textStyle: textTheme.overline), + ); + } + + /// Applies the East Sea Dokdo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/East+Sea+Dokdo + static TextStyle eastSeaDokdo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '28e44e5875cc0c761d9fa6492d1a738977cb5a555b57aa3016e44e2a138df2f7', + 3175644, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EastSeaDokdo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the East Sea Dokdo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/East+Sea+Dokdo + static TextTheme eastSeaDokdoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.eastSeaDokdo(textStyle: textTheme.headline1), + headline2: GoogleFonts.eastSeaDokdo(textStyle: textTheme.headline2), + headline3: GoogleFonts.eastSeaDokdo(textStyle: textTheme.headline3), + headline4: GoogleFonts.eastSeaDokdo(textStyle: textTheme.headline4), + headline5: GoogleFonts.eastSeaDokdo(textStyle: textTheme.headline5), + headline6: GoogleFonts.eastSeaDokdo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.eastSeaDokdo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.eastSeaDokdo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.eastSeaDokdo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.eastSeaDokdo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.eastSeaDokdo(textStyle: textTheme.caption), + button: GoogleFonts.eastSeaDokdo(textStyle: textTheme.button), + overline: GoogleFonts.eastSeaDokdo(textStyle: textTheme.overline), + ); + } + + /// Applies the Eater font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Eater + static TextStyle eater({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c8bc103f8051b7be6a60a18aaf892d18014b8c4d925fdcea5d77a5830c3cbb47', + 83904, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Eater', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Eater font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Eater + static TextTheme eaterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.eater(textStyle: textTheme.headline1), + headline2: GoogleFonts.eater(textStyle: textTheme.headline2), + headline3: GoogleFonts.eater(textStyle: textTheme.headline3), + headline4: GoogleFonts.eater(textStyle: textTheme.headline4), + headline5: GoogleFonts.eater(textStyle: textTheme.headline5), + headline6: GoogleFonts.eater(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.eater(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.eater(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.eater(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.eater(textStyle: textTheme.bodyText2), + caption: GoogleFonts.eater(textStyle: textTheme.caption), + button: GoogleFonts.eater(textStyle: textTheme.button), + overline: GoogleFonts.eater(textStyle: textTheme.overline), + ); + } + + /// Applies the Economica font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Economica + static TextStyle economica({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '73b7c6770eb6ca35b71cc345a389203c788cc27aac43302793865dc33771dcd9', + 26708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ce63d04fe7b161c08efa83fba9b4d096be6f6390a294e904e16f2d7eecc90820', + 27644, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2886009c049eeeb1a75ea749115fbfece59efeb95fcaf29b5f8a82a8c680ab99', + 27148, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd8f54eb9ef53335c26d3f638df8a0bcbdd291dff65990970ea5cd5a2529dfd91', + 26976, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Economica', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Economica font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Economica + static TextTheme economicaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.economica(textStyle: textTheme.headline1), + headline2: GoogleFonts.economica(textStyle: textTheme.headline2), + headline3: GoogleFonts.economica(textStyle: textTheme.headline3), + headline4: GoogleFonts.economica(textStyle: textTheme.headline4), + headline5: GoogleFonts.economica(textStyle: textTheme.headline5), + headline6: GoogleFonts.economica(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.economica(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.economica(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.economica(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.economica(textStyle: textTheme.bodyText2), + caption: GoogleFonts.economica(textStyle: textTheme.caption), + button: GoogleFonts.economica(textStyle: textTheme.button), + overline: GoogleFonts.economica(textStyle: textTheme.overline), + ); + } + + /// Applies the Eczar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Eczar + static TextStyle eczar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c6e04a6ef288e1fca3e9420bfd9752bfdc230a20ce55a05855a8896bdb763a8e', + 196536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd91586e1decf2874b409ef01f87cf50e9725e5f419ea08e5158a6c0a06595fbe', + 196484, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba1eb42528b2001e261653b3e56b8566ae08e9a3a6709b57e20f58b84b82a76a', + 196224, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '254b1a9878dd1e9479e9aab40683ad5d17b35782b413a724f71d89952f460b39', + 195864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd9144eab6daf83585fcb44f4726902a8cbca81d5df060ed6f09787fd5192239f', + 192624, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Eczar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Eczar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Eczar + static TextTheme eczarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.eczar(textStyle: textTheme.headline1), + headline2: GoogleFonts.eczar(textStyle: textTheme.headline2), + headline3: GoogleFonts.eczar(textStyle: textTheme.headline3), + headline4: GoogleFonts.eczar(textStyle: textTheme.headline4), + headline5: GoogleFonts.eczar(textStyle: textTheme.headline5), + headline6: GoogleFonts.eczar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.eczar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.eczar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.eczar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.eczar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.eczar(textStyle: textTheme.caption), + button: GoogleFonts.eczar(textStyle: textTheme.button), + overline: GoogleFonts.eczar(textStyle: textTheme.overline), + ); + } + + /// Applies the El Messiri font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/El+Messiri + static TextStyle elMessiri({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '05a194beec1a2e2d57ac0ee1d517ad0b59142391481adbd18fee77752639ddda', + 81504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9da80f76bf936a3cccb71afc2d2a95fcb8eb5be79a494c0b44e5e75f61031a05', + 82784, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dc6415daf94f76a9dbea542ec17e7df4f5b01a18796c44448bd0c817cd2d433e', + 82764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a25eabeb2e7f6f2cbe92e832bf052cb0bd0930c95b6457ee6cb8469552b97c63', + 81596, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ElMessiri', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the El Messiri font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/El+Messiri + static TextTheme elMessiriTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.elMessiri(textStyle: textTheme.headline1), + headline2: GoogleFonts.elMessiri(textStyle: textTheme.headline2), + headline3: GoogleFonts.elMessiri(textStyle: textTheme.headline3), + headline4: GoogleFonts.elMessiri(textStyle: textTheme.headline4), + headline5: GoogleFonts.elMessiri(textStyle: textTheme.headline5), + headline6: GoogleFonts.elMessiri(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.elMessiri(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.elMessiri(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.elMessiri(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.elMessiri(textStyle: textTheme.bodyText2), + caption: GoogleFonts.elMessiri(textStyle: textTheme.caption), + button: GoogleFonts.elMessiri(textStyle: textTheme.button), + overline: GoogleFonts.elMessiri(textStyle: textTheme.overline), + ); + } + + /// Applies the Electrolize font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Electrolize + static TextStyle electrolize({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c68d85c8396ce2228f3bd601b3423d838c24c546404f25a38db6c05e64a4521b', + 34676, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Electrolize', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Electrolize font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Electrolize + static TextTheme electrolizeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.electrolize(textStyle: textTheme.headline1), + headline2: GoogleFonts.electrolize(textStyle: textTheme.headline2), + headline3: GoogleFonts.electrolize(textStyle: textTheme.headline3), + headline4: GoogleFonts.electrolize(textStyle: textTheme.headline4), + headline5: GoogleFonts.electrolize(textStyle: textTheme.headline5), + headline6: GoogleFonts.electrolize(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.electrolize(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.electrolize(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.electrolize(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.electrolize(textStyle: textTheme.bodyText2), + caption: GoogleFonts.electrolize(textStyle: textTheme.caption), + button: GoogleFonts.electrolize(textStyle: textTheme.button), + overline: GoogleFonts.electrolize(textStyle: textTheme.overline), + ); + } + + /// Applies the Elsie font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Elsie + static TextStyle elsie({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bc0b83b9cbe3b25809361a2f4e495bdc9f10756f669072da3bc89689a42c8845', + 40644, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9aca439d3b5c4abdf62ae59fb1a643c185345724ebdb002f388d25d7926f8f98', + 41932, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Elsie', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Elsie font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Elsie + static TextTheme elsieTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.elsie(textStyle: textTheme.headline1), + headline2: GoogleFonts.elsie(textStyle: textTheme.headline2), + headline3: GoogleFonts.elsie(textStyle: textTheme.headline3), + headline4: GoogleFonts.elsie(textStyle: textTheme.headline4), + headline5: GoogleFonts.elsie(textStyle: textTheme.headline5), + headline6: GoogleFonts.elsie(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.elsie(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.elsie(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.elsie(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.elsie(textStyle: textTheme.bodyText2), + caption: GoogleFonts.elsie(textStyle: textTheme.caption), + button: GoogleFonts.elsie(textStyle: textTheme.button), + overline: GoogleFonts.elsie(textStyle: textTheme.overline), + ); + } + + /// Applies the Elsie Swash Caps font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Elsie+Swash+Caps + static TextStyle elsieSwashCaps({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5073c3bee53b70fcf6b284c6882db47468b86bb95077b497007cfecf47b76bdb', + 37692, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b3610e846ce9868a9ba2c54980426523ef730f265ae56366cb7fa77fd9cdce35', + 38904, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ElsieSwashCaps', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Elsie Swash Caps font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Elsie+Swash+Caps + static TextTheme elsieSwashCapsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.elsieSwashCaps(textStyle: textTheme.headline1), + headline2: GoogleFonts.elsieSwashCaps(textStyle: textTheme.headline2), + headline3: GoogleFonts.elsieSwashCaps(textStyle: textTheme.headline3), + headline4: GoogleFonts.elsieSwashCaps(textStyle: textTheme.headline4), + headline5: GoogleFonts.elsieSwashCaps(textStyle: textTheme.headline5), + headline6: GoogleFonts.elsieSwashCaps(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.elsieSwashCaps(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.elsieSwashCaps(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.elsieSwashCaps(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.elsieSwashCaps(textStyle: textTheme.bodyText2), + caption: GoogleFonts.elsieSwashCaps(textStyle: textTheme.caption), + button: GoogleFonts.elsieSwashCaps(textStyle: textTheme.button), + overline: GoogleFonts.elsieSwashCaps(textStyle: textTheme.overline), + ); + } + + /// Applies the Emblema One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Emblema+One + static TextStyle emblemaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ae7300f04f026825b14eaefb3738782763992c203df0821debfdf47a5bd349ed', + 61832, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EmblemaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Emblema One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Emblema+One + static TextTheme emblemaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.emblemaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.emblemaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.emblemaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.emblemaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.emblemaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.emblemaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.emblemaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.emblemaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.emblemaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.emblemaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.emblemaOne(textStyle: textTheme.caption), + button: GoogleFonts.emblemaOne(textStyle: textTheme.button), + overline: GoogleFonts.emblemaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Emilys Candy font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Emilys+Candy + static TextStyle emilysCandy({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '333e01b7709d7ade3e2afa1ce5b5d193cbb59ce4909a4bd8a9061d7f12368e33', + 236800, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EmilysCandy', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Emilys Candy font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Emilys+Candy + static TextTheme emilysCandyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.emilysCandy(textStyle: textTheme.headline1), + headline2: GoogleFonts.emilysCandy(textStyle: textTheme.headline2), + headline3: GoogleFonts.emilysCandy(textStyle: textTheme.headline3), + headline4: GoogleFonts.emilysCandy(textStyle: textTheme.headline4), + headline5: GoogleFonts.emilysCandy(textStyle: textTheme.headline5), + headline6: GoogleFonts.emilysCandy(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.emilysCandy(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.emilysCandy(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.emilysCandy(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.emilysCandy(textStyle: textTheme.bodyText2), + caption: GoogleFonts.emilysCandy(textStyle: textTheme.caption), + button: GoogleFonts.emilysCandy(textStyle: textTheme.button), + overline: GoogleFonts.emilysCandy(textStyle: textTheme.overline), + ); + } + + /// Applies the Encode Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans + static TextStyle encodeSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8c0f6eafec00e65a8d851e33e6e7e658e34b858ffc9f2ee39ec4bf972891fdf0', + 123088, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3e78947fa53e3e3269b141c073de12ac5c7ad7767084452cf00d157c8c0a623b', + 126316, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd81973e76c4a72a0723f8d83671c01e6a763e4c108b05dcb921abfe786017850', + 126120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '726603f17d4dde111b9e7c3a3ceab5b48d4d9fa010f95c39308a05f7744918c7', + 126176, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1e6070ed7f7df855034f826d501716460f36b8d45f7920099539a66c5ccc44b5', + 125848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7ed81c5a76ba3b44f2c7b4faaee7440283325e7bbe8efbbd976893ed9798166c', + 126108, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f2bf7fce49ca2e3dd0d2fc1203ba30dea4e97ef171f1d693e9e21e23437dd8b8', + 126352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '474df7202478321bede629db8dd5a6720566e44763591e17dc881df6a0b50144', + 126980, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '276a8dae33896588063889970f61a2b2ace3957ebb2024662e9637dc144c0e1a', + 125896, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EncodeSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Encode Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans + static TextTheme encodeSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.encodeSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.encodeSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.encodeSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.encodeSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.encodeSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.encodeSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.encodeSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.encodeSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.encodeSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.encodeSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.encodeSans(textStyle: textTheme.caption), + button: GoogleFonts.encodeSans(textStyle: textTheme.button), + overline: GoogleFonts.encodeSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Encode Sans Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans+Condensed + static TextStyle encodeSansCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c2d65f9836891e7be8e4f366b0daa5300822ec7e50add6db5597d2947739ea20', + 123152, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '138b74330c8e0d86094f3164019df7594d74187b1d46294fc1be869488146eb5', + 126308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c2fbe98bd01eed6d6e9965149ece772f8df140fa27924151375ad388148a46a3', + 125988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '864d5dbdc88484d744c5f412429aee361f61759144cb2a09436e172e49cb0396', + 125864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd681997db3c7754ba70e3d8b22cbe560677787b73469a962a069f9e257235795', + 125816, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8c085d57fde1c82f5051fcdd197852a958132024196a3989c6ab00f550576534', + 125612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a9dde6d2d55aa492820fd930f6d9358fe60b27d9deb328384adca6f7efd4984d', + 126044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e295aa9a8ecab00ca9e9012a789c72ec620a1e03dabae570058ecf0b61ad43f0', + 126828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '65117e9c412bff42a1dd46d75a60d81bf0f70390e437c1d689525a2c422e4a71', + 125332, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EncodeSansCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Encode Sans Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans+Condensed + static TextTheme encodeSansCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.headline1), + headline2: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.headline2), + headline3: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.headline3), + headline4: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.headline4), + headline5: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.headline5), + headline6: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.encodeSansCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.encodeSansCondensed(textStyle: textTheme.caption), + button: GoogleFonts.encodeSansCondensed(textStyle: textTheme.button), + overline: GoogleFonts.encodeSansCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Encode Sans Expanded font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans+Expanded + static TextStyle encodeSansExpanded({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '380345d9f11a5d51121f04ec7692992b4393552df2a3a7d880f4fee2445141d0', + 123684, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a7de0181c2afd610c6c4f4cdd0c1b277e273ce075ebc1aeac436fad20e45419', + 125872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9b50fe9a059788e12206f492db451f122f3ae30e6b8aa5944b51f4fa9b128373', + 125664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f2fa9b86d419104b4b7ab7aa2d8507d9998032c843e7127317c103b55c3900c3', + 125524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ec9211a546cbefbb5fdbdca840aa8782bdbfdef2bc24a03e769b5676d869dd1', + 125672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '57adaf522bbff1044518d732d894dc3b9619455577129c3806e15c41ab7a0cf0', + 125848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ff65de1f2f27bec57c2af88329ff74b61c90a349cda06d054d87125aa4d4588', + 126108, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '93137f85c3ca94e2b0d5d2501170e4b955208bf20d99d3279a12420033315efe', + 126540, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bc58d2db7b8afc49e3bc54a2ffd46ce334497d9361768e992654a18428895228', + 125144, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EncodeSansExpanded', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Encode Sans Expanded font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans+Expanded + static TextTheme encodeSansExpandedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.encodeSansExpanded(textStyle: textTheme.headline1), + headline2: GoogleFonts.encodeSansExpanded(textStyle: textTheme.headline2), + headline3: GoogleFonts.encodeSansExpanded(textStyle: textTheme.headline3), + headline4: GoogleFonts.encodeSansExpanded(textStyle: textTheme.headline4), + headline5: GoogleFonts.encodeSansExpanded(textStyle: textTheme.headline5), + headline6: GoogleFonts.encodeSansExpanded(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.encodeSansExpanded(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.encodeSansExpanded(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.encodeSansExpanded(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.encodeSansExpanded(textStyle: textTheme.bodyText2), + caption: GoogleFonts.encodeSansExpanded(textStyle: textTheme.caption), + button: GoogleFonts.encodeSansExpanded(textStyle: textTheme.button), + overline: GoogleFonts.encodeSansExpanded(textStyle: textTheme.overline), + ); + } + + /// Applies the Encode Sans Semi Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans+Semi+Condensed + static TextStyle encodeSansSemiCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '05e33431ccd816003d590171a6110b72fc3f122c224c46c4f5339f4919b57873', + 123124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '06726656f1a2937a42770740e0772bbcd1187d2bdbe2f5bfd42bab081286b643', + 126604, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6ea764a1fca4cd3308fdc9f6284e890fe9ef8409ab991115bb08a4d0be1b544a', + 126332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ec67d15d3d449c0b0cf65c4fc57fbca88395b306ff4f30d409b4c8eb4d06abbf', + 126216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '972df21a043f38bbac81d476692cdd0ccea7537ceac026fe837daf17c4836aa4', + 126012, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '654f95bfaeb0563e8a7622832f25016d47e3f8e60e4dd59c2ef9cf3835f5e1b1', + 126148, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '99c6ae51b272d20f915f0c4b8454b27ac9400423ba0a207b770a7dc3201f9d5c', + 126476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7d33b1fd6f457c91d58d3287767a4f0089fa3fd5ee2c18539c597f8a895b3646', + 127116, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7075bb5ddbdaca47f1356022fa375630ca868fc11d6ac6e53026c8bac0888b1', + 126184, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EncodeSansSemiCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Encode Sans Semi Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans+Semi+Condensed + static TextTheme encodeSansSemiCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.headline1), + headline2: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.headline2), + headline3: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.headline3), + headline4: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.headline4), + headline5: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.headline5), + headline6: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.bodyText2), + caption: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.caption), + button: GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.button), + overline: + GoogleFonts.encodeSansSemiCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Encode Sans Semi Expanded font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans+Semi+Expanded + static TextStyle encodeSansSemiExpanded({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dac238a8febf393531eee30878adc66774dcd33b426136f91db2c3094cdbbc87', + 123324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a57cc45a15668d01ed3de253cf2cdf14b05212ccf8f5ed876ecdf23610598f7d', + 126728, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ce3f3d0f672e4bdcd7688f38c1ba9cb57ed89bab6f5028da4bb87ed3407edd2', + 126540, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7e3397e73831600b41c8b2381dae7b2f9fbaf91ad2dd7eda631a23dcfa4b9d95', + 126584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3fe7f827d5bc65690cf565f4e5a7662f8ae67d2871679b9cd6e8551a94ad4faa', + 126272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1ab6bbce3162ec2c3cdd343f0ff38a4d8988517afb002ad887736c6a2df3a9d1', + 126556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '35e2e50ea2e448f64fd31c6479eedc42e754710a0efb4e16fb6bc55724dc3b0c', + 126828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aff573a59e5988f277836dfe45250f8fb62d9289084f3798c5b8d3adef115da9', + 127356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f945eac695f316de1c89017007aef0369d2d9c13e4564a642da83224ea32e464', + 126324, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EncodeSansSemiExpanded', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Encode Sans Semi Expanded font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Encode+Sans+Semi+Expanded + static TextTheme encodeSansSemiExpandedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.headline1), + headline2: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.headline2), + headline3: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.headline3), + headline4: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.headline4), + headline5: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.headline5), + headline6: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.bodyText2), + caption: GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.caption), + button: GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.button), + overline: + GoogleFonts.encodeSansSemiExpanded(textStyle: textTheme.overline), + ); + } + + /// Applies the Engagement font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Engagement + static TextStyle engagement({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '14dc139d3b6796ff833b0eb8daf08b16fcc822ca78db05a4bb8c6e65c16507ce', + 75992, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Engagement', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Engagement font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Engagement + static TextTheme engagementTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.engagement(textStyle: textTheme.headline1), + headline2: GoogleFonts.engagement(textStyle: textTheme.headline2), + headline3: GoogleFonts.engagement(textStyle: textTheme.headline3), + headline4: GoogleFonts.engagement(textStyle: textTheme.headline4), + headline5: GoogleFonts.engagement(textStyle: textTheme.headline5), + headline6: GoogleFonts.engagement(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.engagement(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.engagement(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.engagement(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.engagement(textStyle: textTheme.bodyText2), + caption: GoogleFonts.engagement(textStyle: textTheme.caption), + button: GoogleFonts.engagement(textStyle: textTheme.button), + overline: GoogleFonts.engagement(textStyle: textTheme.overline), + ); + } + + /// Applies the Englebert font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Englebert + static TextStyle englebert({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5ceab7490f339b83c9f46a3baf7274203de3e060802b185fbd65c2aa9f5ec76c', + 52632, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Englebert', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Englebert font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Englebert + static TextTheme englebertTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.englebert(textStyle: textTheme.headline1), + headline2: GoogleFonts.englebert(textStyle: textTheme.headline2), + headline3: GoogleFonts.englebert(textStyle: textTheme.headline3), + headline4: GoogleFonts.englebert(textStyle: textTheme.headline4), + headline5: GoogleFonts.englebert(textStyle: textTheme.headline5), + headline6: GoogleFonts.englebert(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.englebert(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.englebert(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.englebert(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.englebert(textStyle: textTheme.bodyText2), + caption: GoogleFonts.englebert(textStyle: textTheme.caption), + button: GoogleFonts.englebert(textStyle: textTheme.button), + overline: GoogleFonts.englebert(textStyle: textTheme.overline), + ); + } + + /// Applies the Enriqueta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Enriqueta + static TextStyle enriqueta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8efdf359579cbd9731b621eb32ddd55b3311bb4f3efe2479e1b87a731deb2b3f', + 53432, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '75092b77ab687551bb7a93707771fa18a40ebfe0621befe7dbaca438b8a8c954', + 45192, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Enriqueta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Enriqueta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Enriqueta + static TextTheme enriquetaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.enriqueta(textStyle: textTheme.headline1), + headline2: GoogleFonts.enriqueta(textStyle: textTheme.headline2), + headline3: GoogleFonts.enriqueta(textStyle: textTheme.headline3), + headline4: GoogleFonts.enriqueta(textStyle: textTheme.headline4), + headline5: GoogleFonts.enriqueta(textStyle: textTheme.headline5), + headline6: GoogleFonts.enriqueta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.enriqueta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.enriqueta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.enriqueta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.enriqueta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.enriqueta(textStyle: textTheme.caption), + button: GoogleFonts.enriqueta(textStyle: textTheme.button), + overline: GoogleFonts.enriqueta(textStyle: textTheme.overline), + ); + } + + /// Applies the Epilogue font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Epilogue + static TextStyle epilogue({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '934ed8ab6e183975f80ad82892575488c2782a9615b1400a387aad7620523914', + 62672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '21e429f05987a7aca3a77bb0363f1173299780f5a8639421f5a907e75382dda2', + 62740, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aecc8fc018c4c0c01656e7b5b240e7ad991724dbc1632f587aa4fb25b9d3d347', + 62704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9bd3b9b33996414143458aa43a3493658b0e1de32e07ae92f79d99d74477ddc7', + 62724, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '09a4cc8f9ea019cc7dd32ef52c655e35bbfbbe2b638b7e220005770d755b4253', + 62724, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c2302ab2f5cea5ca2227c52a78bfb1781d26fc8d5c1aa195463a946e0e123d57', + 62932, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '37ffd49cdad9eab49dcef1051878acdaabb57eddfd7c18e399cc9c5bbf36f68d', + 62900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6c619d499262fb8366255790c916b2b1bd0ae203635a5b9d9394fe932f5b55ed', + 63064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bfd277d5255f4737808869f0e783828dac257c19970023681d7b096446212ad8', + 63112, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c0990ee09b7f5a5c312282656658441e1bb45f351d85817a8b51ae36e1812ae6', + 63172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1d5813f9f268cc0af9827b8a88a024d3fa4b4e427a11d14df7d2993de7de09e8', + 63228, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '44568c2c560d85bf1b8f39042351a0706e6136b3fe2313a772f775eff64b03f8', + 63112, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '27aed996948a7545acb378db00d78ffd89a2b2969ce69080c8dfcb53ba1a2827', + 63020, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2b19fa21b613f1c9097824173a63f396e8beb7b0b9b630989498ee837424cfb5', + 63132, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4348c0a36320d21529131aea11b56f9d7978ef1929efecb3bf4bd50b9b8cc514', + 63332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0bb89cdcf45aca9840f41ac7aff2f2e0a112faf5fa7f99e7467d9157d0e6425f', + 63236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f6a9879b4cda595ff7e74ad85300d0aeb3e496a2b4b24c1bc9538dd6d518392d', + 63468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7a714f90ed7246693aa0cdcabddb0af0cc70a78a591943311a735d4ba049c087', + 63432, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Epilogue', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Epilogue font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Epilogue + static TextTheme epilogueTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.epilogue(textStyle: textTheme.headline1), + headline2: GoogleFonts.epilogue(textStyle: textTheme.headline2), + headline3: GoogleFonts.epilogue(textStyle: textTheme.headline3), + headline4: GoogleFonts.epilogue(textStyle: textTheme.headline4), + headline5: GoogleFonts.epilogue(textStyle: textTheme.headline5), + headline6: GoogleFonts.epilogue(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.epilogue(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.epilogue(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.epilogue(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.epilogue(textStyle: textTheme.bodyText2), + caption: GoogleFonts.epilogue(textStyle: textTheme.caption), + button: GoogleFonts.epilogue(textStyle: textTheme.button), + overline: GoogleFonts.epilogue(textStyle: textTheme.overline), + ); + } + + /// Applies the Erica One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Erica+One + static TextStyle ericaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '718a969fb44854ce221ced461f15a49e4e53dea2478eb4fb6bac911b5dc5a99b', + 25996, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EricaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Erica One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Erica+One + static TextTheme ericaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ericaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.ericaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.ericaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.ericaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.ericaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.ericaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ericaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ericaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ericaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ericaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ericaOne(textStyle: textTheme.caption), + button: GoogleFonts.ericaOne(textStyle: textTheme.button), + overline: GoogleFonts.ericaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Esteban font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Esteban + static TextStyle esteban({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f0226acf9a0738f8dba187bbb11a569ea1e5329575144243525a23e543276b37', + 46456, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Esteban', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Esteban font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Esteban + static TextTheme estebanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.esteban(textStyle: textTheme.headline1), + headline2: GoogleFonts.esteban(textStyle: textTheme.headline2), + headline3: GoogleFonts.esteban(textStyle: textTheme.headline3), + headline4: GoogleFonts.esteban(textStyle: textTheme.headline4), + headline5: GoogleFonts.esteban(textStyle: textTheme.headline5), + headline6: GoogleFonts.esteban(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.esteban(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.esteban(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.esteban(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.esteban(textStyle: textTheme.bodyText2), + caption: GoogleFonts.esteban(textStyle: textTheme.caption), + button: GoogleFonts.esteban(textStyle: textTheme.button), + overline: GoogleFonts.esteban(textStyle: textTheme.overline), + ); + } + + /// Applies the Euphoria Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Euphoria+Script + static TextStyle euphoriaScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '49720d65299334ddc97b89311f78ec792b2862791a226a49f7bb5f8e19d709a5', + 38376, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'EuphoriaScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Euphoria Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Euphoria+Script + static TextTheme euphoriaScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.euphoriaScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.euphoriaScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.euphoriaScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.euphoriaScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.euphoriaScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.euphoriaScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.euphoriaScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.euphoriaScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.euphoriaScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.euphoriaScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.euphoriaScript(textStyle: textTheme.caption), + button: GoogleFonts.euphoriaScript(textStyle: textTheme.button), + overline: GoogleFonts.euphoriaScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Ewert font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ewert + static TextStyle ewert({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e2a4aed1fe4d33019eb7c6a9273a251e7f28ac19b2820f61ef61329d32cb89a8', + 70704, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ewert', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ewert font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ewert + static TextTheme ewertTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ewert(textStyle: textTheme.headline1), + headline2: GoogleFonts.ewert(textStyle: textTheme.headline2), + headline3: GoogleFonts.ewert(textStyle: textTheme.headline3), + headline4: GoogleFonts.ewert(textStyle: textTheme.headline4), + headline5: GoogleFonts.ewert(textStyle: textTheme.headline5), + headline6: GoogleFonts.ewert(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ewert(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ewert(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ewert(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ewert(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ewert(textStyle: textTheme.caption), + button: GoogleFonts.ewert(textStyle: textTheme.button), + overline: GoogleFonts.ewert(textStyle: textTheme.overline), + ); + } + + /// Applies the Exo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Exo + static TextStyle exo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2eda7d4b0bab32b1724ead985ca4ab23ba46b1647e60b50df836f3e142105e85', + 109668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5315edfaf9326a2112d609345e056a733da22ecf1c3aed8f0a78d51539300ec7', + 115720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b9271134900d316a8aa07b17a3850ad179e6c77b533419aad39926ab5fbbba5e', + 109812, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '58251d3b9daf7e91b2c9371c9800e0dbcd1374a54b0eee6b026a237c4d9fe63c', + 116352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bf846eb403540e7bfaae3e3975ff0577b88730403c02d4b2e57bb241e7294e1f', + 109416, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '278cc62e59aeca97f6e14f44ded0943df0201e7aa692faff1b40a9e6d7b22dc0', + 115868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ab24d45bd0887f54e98614ec395c5addfe82b0e8389b4721f5465954e1e2f060', + 109144, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b79a6db3b900824a3c9cbd804a328bc0bd070b648e0615e9a45f5a5c0eb8dd63', + 115404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cb038971b993fa7fa126ed43d4dc54e20af90eeb8213b0c2a9c735a2c82c0d4e', + 108848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '224493dbc8c8852c0a452618d375990f1383d43ba5f9f4726b4d87ec6c6f50c0', + 115204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '754632bf7096e73d05f2e15e3f52a82b34201bad1aa105d6e650de745d120eda', + 108772, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '397a2c49640d1470bf9df914dfbbfa914148dd86642d25e248193a1f649b27dc', + 114872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3b0e87021af2542173d6c39db5a95d9e18ba59c0c9aa7ad37b6df04523947309', + 108476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '75d249c747ae8332516fd6d2c3996d3f2c440f659339765dc8e13a97f942ad64', + 114360, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5e5a390588a0eb152906de109ebd9c65d662628da5f1afbb3d17bd4a237c873d', + 108380, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0c6ffd7e0358672dd7d40462c46a11562e062f1cab60d82d80b8a71737cb3141', + 114288, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d12eeaf10d56d2e39321c9d10253d25ccce5e188ab6684ec5eac5d7d9ac99be', + 108500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5a6cc3dfdcfe4e6990da4fa3f55a861ed2ae701a0ae1a30d30b23daafa215604', + 113996, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Exo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Exo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Exo + static TextTheme exoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.exo(textStyle: textTheme.headline1), + headline2: GoogleFonts.exo(textStyle: textTheme.headline2), + headline3: GoogleFonts.exo(textStyle: textTheme.headline3), + headline4: GoogleFonts.exo(textStyle: textTheme.headline4), + headline5: GoogleFonts.exo(textStyle: textTheme.headline5), + headline6: GoogleFonts.exo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.exo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.exo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.exo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.exo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.exo(textStyle: textTheme.caption), + button: GoogleFonts.exo(textStyle: textTheme.button), + overline: GoogleFonts.exo(textStyle: textTheme.overline), + ); + } + + /// Applies the Exo 2 font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Exo+2 + static TextStyle exo2({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f19c0e2523de9afe6da463f303aefcf3e38b416875d48ef6c98328379e1a61ce', + 73868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd39266e34642d4861ef777d4d3ae4150ae0b18b16d94713a78bb60cf03bf85b4', + 79980, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dbf766d9b363fe87cee0afda4c59bc8a59f1c8d0a0d245063c720108d85dd9d6', + 75360, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fb55978ca6abd55f49aab78def94b5c8b96bed1439a6dc4dae6dd1d0596ced50', + 81004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '64d41ba51bf8991e5322fbc8d80e400281604f70cd061562aad4bdf6aedd582e', + 75152, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '110c181389ab4ffd19a1212a2c7b53e86dd2deefa76fbd3208663e85b34cd46e', + 80724, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a0dfef91dddc6d2e9820c4faf4c31bfa1533f090efe935e91150ee1b4cc59f4f', + 75456, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd7c5bd167ace5154cd5e8806a913d620cb479062db24c06433f7f38b3e6811cf', + 80784, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f9b5326ebe6f800499e333e88b5d52d47d995cb1eb20ce541991deb5ae2792a4', + 75568, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6abd6d5f1ca760d693fe03958a2e85de8ffeeabb5e2794bc2725ce8775807924', + 81168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8999193c1336c6f666fba9f56ec1d12485be48c9f31a2e97e00056b311d2b79a', + 77592, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '73cdbc23b75cf90b91216670334c663046fe0b9d08f39991d5b9d26942b358a0', + 81332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2fa1bb398f33123661ab6d19927457c499ee32ba16819269d005ec1a4343aaf5', + 77316, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '656cda11a815f2f5c7ef493608481f3ea6da47880dbcc3b6be65059319597393', + 80652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '88f76cbd5e824b5c45fb8278750d69a37690ede91efd8901a27dc5f20c69de70', + 77484, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fa96b010fc061593439675e03f0f7b4f36bcf4ef79b2f68d5820122313c84ac9', + 80764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '78b737edc063f02e62ffc88e8b71820aa12f17972b3dc70d9cc6aa20cbf8bb81', + 76568, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9c49337689c4c8e998cdfc92575356ddef9b8d31b07c19c2e7d466c806b5de15', + 79492, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Exo2', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Exo 2 font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Exo+2 + static TextTheme exo2TextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.exo2(textStyle: textTheme.headline1), + headline2: GoogleFonts.exo2(textStyle: textTheme.headline2), + headline3: GoogleFonts.exo2(textStyle: textTheme.headline3), + headline4: GoogleFonts.exo2(textStyle: textTheme.headline4), + headline5: GoogleFonts.exo2(textStyle: textTheme.headline5), + headline6: GoogleFonts.exo2(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.exo2(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.exo2(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.exo2(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.exo2(textStyle: textTheme.bodyText2), + caption: GoogleFonts.exo2(textStyle: textTheme.caption), + button: GoogleFonts.exo2(textStyle: textTheme.button), + overline: GoogleFonts.exo2(textStyle: textTheme.overline), + ); + } + + /// Applies the Expletus Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Expletus+Sans + static TextStyle expletusSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8e8194fbcb2069328e5c506a10ab38e405a359ec0ab5c0d2379659cdff0830db', + 26352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '072928d584fe0a92e93d576c43798a1dc6d1bf065c7db59d28112cb4733cad2a', + 27304, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b5cd6f4acc507801fef499ca08c7da56ff9e5df77a4ba14eac1718e7ccfe49e5', + 26656, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b16455d3607896d0b779898db128a332df5ed111317da3f1341a85a07317b209', + 50592, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '732974a8456ad103e02e3ad28c0844e71113017aae30a88969af3ec454dc2043', + 26636, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '935e18b8d6f075d9b37b0017bde129fd0e68ee0800f60eac4c68f6534c528aa3', + 27828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1f5f64f05469211d27b24f1b1f39e57ec0ca9e4211a24b28c336f629254bd482', + 26620, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '77c1827497333ee775fc45b32a1c0c2da85ac489afa78e6ee3808130e850e355', + 29012, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ExpletusSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Expletus Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Expletus+Sans + static TextTheme expletusSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.expletusSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.expletusSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.expletusSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.expletusSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.expletusSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.expletusSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.expletusSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.expletusSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.expletusSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.expletusSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.expletusSans(textStyle: textTheme.caption), + button: GoogleFonts.expletusSans(textStyle: textTheme.button), + overline: GoogleFonts.expletusSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Fahkwang font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fahkwang + static TextStyle fahkwang({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '07a682d6bc044cbd486744e34dcb061077bac07d9501f34c8f50b67aa2c02b7f', + 79476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c9cba18dabd9762bcd5cd460bbc145d71a364a65255b3ff8514cb385997506c8', + 82060, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a4f936e2bce0a9dc318b8e50537d34ffd7475cd6199842a810f7b9ef9072cdae', + 79520, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a1ef09b096105c18faf5fadb52cbeb7979873ad7e9d50910b116ce244b4fe166', + 82128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e288aad85ecd44f0568c3d218d1478f896a2e9656dea8978a0462f0432102f7', + 79356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd39b9b3782631bd9e5ca85b327f2e86ade2f88ca6d30a9f85112209c08f703e5', + 82044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f7b5bd7dd6726ca8619156e571f3ab9429a229e110e87eb4807508a6e603b055', + 79100, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '99dff1eec80cee80e76e31de570b32a627c8b114c5f4a6edda2349c62ef7eb9e', + 82064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b415ad58dda4167eef2957ac799ec99e305a626797d3f015c814096dcab8244f', + 79136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a3cb35f606a6f504a703c26834f242e79e57064c9cc15b016acd7ead15c1c379', + 82048, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d4c87b61ab6b7a8c8fd345b20f1bdea3f0eaf90b1f3d014ba9a1aed4df71bc5', + 78988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '02444f0d64cab232aa85ca6646af07c761791397753194217bec25ee19e4107e', + 81940, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Fahkwang', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fahkwang font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fahkwang + static TextTheme fahkwangTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fahkwang(textStyle: textTheme.headline1), + headline2: GoogleFonts.fahkwang(textStyle: textTheme.headline2), + headline3: GoogleFonts.fahkwang(textStyle: textTheme.headline3), + headline4: GoogleFonts.fahkwang(textStyle: textTheme.headline4), + headline5: GoogleFonts.fahkwang(textStyle: textTheme.headline5), + headline6: GoogleFonts.fahkwang(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fahkwang(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fahkwang(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fahkwang(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fahkwang(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fahkwang(textStyle: textTheme.caption), + button: GoogleFonts.fahkwang(textStyle: textTheme.button), + overline: GoogleFonts.fahkwang(textStyle: textTheme.overline), + ); + } + + /// Applies the Fanwood Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fanwood+Text + static TextStyle fanwoodText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '37c7865d9942ebc3e421992f87faa2a1c1f686716fd40054035736abd0938f1d', + 119168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ebb9e6f0a9aad6a9a9a13de40ed43e94061e0aefeb1fc8ab3399b0a3307dfee8', + 96316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FanwoodText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fanwood Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fanwood+Text + static TextTheme fanwoodTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fanwoodText(textStyle: textTheme.headline1), + headline2: GoogleFonts.fanwoodText(textStyle: textTheme.headline2), + headline3: GoogleFonts.fanwoodText(textStyle: textTheme.headline3), + headline4: GoogleFonts.fanwoodText(textStyle: textTheme.headline4), + headline5: GoogleFonts.fanwoodText(textStyle: textTheme.headline5), + headline6: GoogleFonts.fanwoodText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fanwoodText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fanwoodText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fanwoodText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fanwoodText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fanwoodText(textStyle: textTheme.caption), + button: GoogleFonts.fanwoodText(textStyle: textTheme.button), + overline: GoogleFonts.fanwoodText(textStyle: textTheme.overline), + ); + } + + /// Applies the Farro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Farro + static TextStyle farro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ca8a2c854888fbeb59e572d229d903a5793ba08741fb5effc6484dad0baca84b', + 38668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '04c2276c71a6e273507190f49761498509d6b0b4dda77befd400b8b093ca1ad8', + 38536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '43a287bb29da4b09c5492c818eeb5cab21180fcead8c66a9340ba185728d5ab5', + 38584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f000197888095e4fccd58e6e7af75f410a611fe4292e359d52d9110505fb0373', + 38012, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Farro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Farro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Farro + static TextTheme farroTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.farro(textStyle: textTheme.headline1), + headline2: GoogleFonts.farro(textStyle: textTheme.headline2), + headline3: GoogleFonts.farro(textStyle: textTheme.headline3), + headline4: GoogleFonts.farro(textStyle: textTheme.headline4), + headline5: GoogleFonts.farro(textStyle: textTheme.headline5), + headline6: GoogleFonts.farro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.farro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.farro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.farro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.farro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.farro(textStyle: textTheme.caption), + button: GoogleFonts.farro(textStyle: textTheme.button), + overline: GoogleFonts.farro(textStyle: textTheme.overline), + ); + } + + /// Applies the Farsan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Farsan + static TextStyle farsan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '06d96e20a2d15a86aca97dc3632eec9628587c3c335c563af7181458c2e91c54', + 243680, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Farsan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Farsan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Farsan + static TextTheme farsanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.farsan(textStyle: textTheme.headline1), + headline2: GoogleFonts.farsan(textStyle: textTheme.headline2), + headline3: GoogleFonts.farsan(textStyle: textTheme.headline3), + headline4: GoogleFonts.farsan(textStyle: textTheme.headline4), + headline5: GoogleFonts.farsan(textStyle: textTheme.headline5), + headline6: GoogleFonts.farsan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.farsan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.farsan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.farsan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.farsan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.farsan(textStyle: textTheme.caption), + button: GoogleFonts.farsan(textStyle: textTheme.button), + overline: GoogleFonts.farsan(textStyle: textTheme.overline), + ); + } + + /// Applies the Fascinate font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fascinate + static TextStyle fascinate({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f23d154a851bb211f83de2d4f7dd5242620662579daa75f0a4ac8e4c692a1832', + 51484, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Fascinate', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fascinate font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fascinate + static TextTheme fascinateTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fascinate(textStyle: textTheme.headline1), + headline2: GoogleFonts.fascinate(textStyle: textTheme.headline2), + headline3: GoogleFonts.fascinate(textStyle: textTheme.headline3), + headline4: GoogleFonts.fascinate(textStyle: textTheme.headline4), + headline5: GoogleFonts.fascinate(textStyle: textTheme.headline5), + headline6: GoogleFonts.fascinate(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fascinate(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fascinate(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fascinate(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fascinate(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fascinate(textStyle: textTheme.caption), + button: GoogleFonts.fascinate(textStyle: textTheme.button), + overline: GoogleFonts.fascinate(textStyle: textTheme.overline), + ); + } + + /// Applies the Fascinate Inline font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fascinate+Inline + static TextStyle fascinateInline({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c052c5d8595ae4b44c8e2c92cd12be41381064837072f05fc6a3f4807f1d80e7', + 59188, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FascinateInline', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fascinate Inline font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fascinate+Inline + static TextTheme fascinateInlineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fascinateInline(textStyle: textTheme.headline1), + headline2: GoogleFonts.fascinateInline(textStyle: textTheme.headline2), + headline3: GoogleFonts.fascinateInline(textStyle: textTheme.headline3), + headline4: GoogleFonts.fascinateInline(textStyle: textTheme.headline4), + headline5: GoogleFonts.fascinateInline(textStyle: textTheme.headline5), + headline6: GoogleFonts.fascinateInline(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fascinateInline(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fascinateInline(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fascinateInline(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fascinateInline(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fascinateInline(textStyle: textTheme.caption), + button: GoogleFonts.fascinateInline(textStyle: textTheme.button), + overline: GoogleFonts.fascinateInline(textStyle: textTheme.overline), + ); + } + + /// Applies the Faster One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Faster+One + static TextStyle fasterOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fbde65e70c94e07f0152fa5b1506d0a77cf338a94d29423fec1aa0730891cd04', + 44372, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FasterOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Faster One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Faster+One + static TextTheme fasterOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fasterOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.fasterOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.fasterOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.fasterOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.fasterOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.fasterOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fasterOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fasterOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fasterOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fasterOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fasterOne(textStyle: textTheme.caption), + button: GoogleFonts.fasterOne(textStyle: textTheme.button), + overline: GoogleFonts.fasterOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Fauna One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fauna+One + static TextStyle faunaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'afbf7594d1feb78a9b5e6262887492adcf721a6e1d033b1c6d26aeba06bcc132', + 30196, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FaunaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fauna One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fauna+One + static TextTheme faunaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.faunaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.faunaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.faunaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.faunaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.faunaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.faunaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.faunaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.faunaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.faunaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.faunaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.faunaOne(textStyle: textTheme.caption), + button: GoogleFonts.faunaOne(textStyle: textTheme.button), + overline: GoogleFonts.faunaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Faustina font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Faustina + static TextStyle faustina({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b83e2bcd1f015e1e288c5870cf0301c94cff5d1d346b1c0b7d0e497ec7165a06', + 83308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a7f8c492e8ce7588c67e918c52ae5a4c9517a62c3057c9aaa9f2a2f8bcc1278d', + 84980, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ced47c330edb05d2c4dc0cfe0e0b69f9b23cfce448a95ab12a7179b3f3e7d8e9', + 88172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '02caa39209526de5d9a8cd33d2d06056bd7dd2c4f91748ddd6a5af7fb9abfa87', + 90276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '617c505971ec93fa27bd52270f4a605f1f9e8c04efa06181c1f9e6a684cb907a', + 88292, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5f2f74ee4758fad98604d34c6a8e8df131c924bfd4654546327cc02df81af527', + 90052, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e680d2565c4001336be567bd147c16b8d88d21b36f499cd98e689a429568ebcd', + 84148, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '32a38ed85ba3470cf4ff6929aae4fdb13233d68ba71b97ce606bc2ce782b0961', + 86792, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Faustina', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Faustina font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Faustina + static TextTheme faustinaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.faustina(textStyle: textTheme.headline1), + headline2: GoogleFonts.faustina(textStyle: textTheme.headline2), + headline3: GoogleFonts.faustina(textStyle: textTheme.headline3), + headline4: GoogleFonts.faustina(textStyle: textTheme.headline4), + headline5: GoogleFonts.faustina(textStyle: textTheme.headline5), + headline6: GoogleFonts.faustina(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.faustina(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.faustina(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.faustina(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.faustina(textStyle: textTheme.bodyText2), + caption: GoogleFonts.faustina(textStyle: textTheme.caption), + button: GoogleFonts.faustina(textStyle: textTheme.button), + overline: GoogleFonts.faustina(textStyle: textTheme.overline), + ); + } + + /// Applies the Federant font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Federant + static TextStyle federant({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '64e759e186856942cf96caca16925f320d145c552c214f61546d51aad8e02bbe', + 32556, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Federant', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Federant font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Federant + static TextTheme federantTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.federant(textStyle: textTheme.headline1), + headline2: GoogleFonts.federant(textStyle: textTheme.headline2), + headline3: GoogleFonts.federant(textStyle: textTheme.headline3), + headline4: GoogleFonts.federant(textStyle: textTheme.headline4), + headline5: GoogleFonts.federant(textStyle: textTheme.headline5), + headline6: GoogleFonts.federant(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.federant(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.federant(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.federant(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.federant(textStyle: textTheme.bodyText2), + caption: GoogleFonts.federant(textStyle: textTheme.caption), + button: GoogleFonts.federant(textStyle: textTheme.button), + overline: GoogleFonts.federant(textStyle: textTheme.overline), + ); + } + + /// Applies the Federo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Federo + static TextStyle federo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cefb7b8c896226fdb5493d3bd75dbb0baae167b10f60d892578bc75dc1acc5b5', + 116756, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Federo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Federo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Federo + static TextTheme federoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.federo(textStyle: textTheme.headline1), + headline2: GoogleFonts.federo(textStyle: textTheme.headline2), + headline3: GoogleFonts.federo(textStyle: textTheme.headline3), + headline4: GoogleFonts.federo(textStyle: textTheme.headline4), + headline5: GoogleFonts.federo(textStyle: textTheme.headline5), + headline6: GoogleFonts.federo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.federo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.federo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.federo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.federo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.federo(textStyle: textTheme.caption), + button: GoogleFonts.federo(textStyle: textTheme.button), + overline: GoogleFonts.federo(textStyle: textTheme.overline), + ); + } + + /// Applies the Felipa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Felipa + static TextStyle felipa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1636ce9582e69c11f567c7e8cbea02601d37fb40da1e6affdd5b71a01c7cd36b', + 39952, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Felipa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Felipa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Felipa + static TextTheme felipaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.felipa(textStyle: textTheme.headline1), + headline2: GoogleFonts.felipa(textStyle: textTheme.headline2), + headline3: GoogleFonts.felipa(textStyle: textTheme.headline3), + headline4: GoogleFonts.felipa(textStyle: textTheme.headline4), + headline5: GoogleFonts.felipa(textStyle: textTheme.headline5), + headline6: GoogleFonts.felipa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.felipa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.felipa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.felipa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.felipa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.felipa(textStyle: textTheme.caption), + button: GoogleFonts.felipa(textStyle: textTheme.button), + overline: GoogleFonts.felipa(textStyle: textTheme.overline), + ); + } + + /// Applies the Fenix font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fenix + static TextStyle fenix({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8601d9f9c9a93dcbc9a75b2e7e9e1f567e66ca628768e1567225078fee043e8f', + 45096, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Fenix', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fenix font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fenix + static TextTheme fenixTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fenix(textStyle: textTheme.headline1), + headline2: GoogleFonts.fenix(textStyle: textTheme.headline2), + headline3: GoogleFonts.fenix(textStyle: textTheme.headline3), + headline4: GoogleFonts.fenix(textStyle: textTheme.headline4), + headline5: GoogleFonts.fenix(textStyle: textTheme.headline5), + headline6: GoogleFonts.fenix(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fenix(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fenix(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fenix(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fenix(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fenix(textStyle: textTheme.caption), + button: GoogleFonts.fenix(textStyle: textTheme.button), + overline: GoogleFonts.fenix(textStyle: textTheme.overline), + ); + } + + /// Applies the Finger Paint font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Finger+Paint + static TextStyle fingerPaint({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6ab3ff7f8e0eaf096c590997201b069ff984623d2eae2b71d8712f4a94a504a9', + 101364, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FingerPaint', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Finger Paint font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Finger+Paint + static TextTheme fingerPaintTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fingerPaint(textStyle: textTheme.headline1), + headline2: GoogleFonts.fingerPaint(textStyle: textTheme.headline2), + headline3: GoogleFonts.fingerPaint(textStyle: textTheme.headline3), + headline4: GoogleFonts.fingerPaint(textStyle: textTheme.headline4), + headline5: GoogleFonts.fingerPaint(textStyle: textTheme.headline5), + headline6: GoogleFonts.fingerPaint(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fingerPaint(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fingerPaint(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fingerPaint(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fingerPaint(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fingerPaint(textStyle: textTheme.caption), + button: GoogleFonts.fingerPaint(textStyle: textTheme.button), + overline: GoogleFonts.fingerPaint(textStyle: textTheme.overline), + ); + } + + /// Applies the Fira Code font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Code + static TextStyle firaCode({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '53d9824e306c207a6de228abf02372c59c9b2166fc2a5b38d40d9f8b2cca4f53', + 140772, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '952b0d5a1d329fa4c8229aa97143ed9ff3f239f1b4bd84e4c14b6f4f1ccdd705', + 140656, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eeca9b497781ac45524ddd9ca6fdfa383130e3d2a613045bc288fbeaf3796ce6', + 140608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9272ceedc952a0945683c249045952038f3cd3c1cf0bd0bfda3a07417e44fd48', + 140904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e534947b075377251fa622cf2ae6881dd4073346a5fefda144b1406f45b9ade9', + 141148, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FiraCode', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fira Code font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Code + static TextTheme firaCodeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.firaCode(textStyle: textTheme.headline1), + headline2: GoogleFonts.firaCode(textStyle: textTheme.headline2), + headline3: GoogleFonts.firaCode(textStyle: textTheme.headline3), + headline4: GoogleFonts.firaCode(textStyle: textTheme.headline4), + headline5: GoogleFonts.firaCode(textStyle: textTheme.headline5), + headline6: GoogleFonts.firaCode(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.firaCode(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.firaCode(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.firaCode(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.firaCode(textStyle: textTheme.bodyText2), + caption: GoogleFonts.firaCode(textStyle: textTheme.caption), + button: GoogleFonts.firaCode(textStyle: textTheme.button), + overline: GoogleFonts.firaCode(textStyle: textTheme.overline), + ); + } + + /// Applies the Fira Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Mono + static TextStyle firaMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f17d60778f78f5928584a4f314a221b328dbce03da62fcc09caeebac82f76809', + 131780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '003aa1dc6866482549cf715d4075e470701e918eadd47a035568d8d254f63e02', + 131368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4dab36f8faa3f89e09e177a6ef40eaacd307b98b2a38a14426be96ce9ed67a3b', + 131392, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FiraMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fira Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Mono + static TextTheme firaMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.firaMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.firaMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.firaMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.firaMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.firaMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.firaMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.firaMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.firaMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.firaMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.firaMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.firaMono(textStyle: textTheme.caption), + button: GoogleFonts.firaMono(textStyle: textTheme.button), + overline: GoogleFonts.firaMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Fira Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Sans + static TextStyle firaSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8c710b8842ec687cf4d723fa7cf54656e4600a5fc0b35581c6c5db5811eb3648', + 363328, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c12ca8dc162546809677cd3a931692841e7d605b092be571767436772cbca571', + 377284, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0fdce9dc421c231fd5eb33b58fa54bfc22e73eb766fbf24c099102a3c9745a04', + 367616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6fc161a574855f456dd5f6aca03b07bd5fbbda95409eaaeea8d32b83efdd82d4', + 381668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0cf10b5f7c89c8b6cc74e27189f128a0632fcc969d1d71639d7df41a988241ea', + 366972, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ed16991f9880c1cdf370062abe98f041f9c4227d7b7533bf2f7915cd203d33a6', + 380468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25d5c70026b4ecf845ee6e70a5db8152c460c77457ee2c198f857b9dc194d2f3', + 366252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '68cee55e27446a07ee1a11f047f9ce975c099a77beb93636576f205f1f79e949', + 379696, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '92c4968351b66aa1751300d33479286d7efbba08a54f8e4ff3bf2f46a9cf39be', + 366356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '61820fb5cb8cddf45429ac27bd1b3ddc92f5fa8df2558b86f251a7d3b02eb896', + 379848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '63399ee49cc66340dce320237ad9177a3c4425f1e2e067f36fc16613bff0566e', + 366296, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5bb43f8686cc19df2202a071cae38722fe0cc2a3a3fe6e23a2cf6a96f7744782', + 380132, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '87babfdf164afa1f458032e5d4166b48f6e1fe8599501da30592a5f2fb2dd18a', + 366376, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3b86fe4a8430dc147fd75bedeb04f37cb3fc160fcb9b905263e11f945cf8de60', + 379804, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c11b26719603ed8ca563718737b415405dd2010a56408dc403bf6292e3c11561', + 366128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9c5bac7e128fa9013ef3cdc329d8f441aea8fdca1051acdb22814bfcf14f8aff', + 379332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a957f6ef941a2c07855a9f053c3f0c03091299a68530247f3bb1c3c6ab574c4', + 365756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd2813a992761a32da93a8230e2d86dbc1f4c430516ebc63b870d6865995d8233', + 379500, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FiraSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fira Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Sans + static TextTheme firaSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.firaSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.firaSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.firaSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.firaSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.firaSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.firaSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.firaSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.firaSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.firaSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.firaSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.firaSans(textStyle: textTheme.caption), + button: GoogleFonts.firaSans(textStyle: textTheme.button), + overline: GoogleFonts.firaSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Fira Sans Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Sans+Condensed + static TextStyle firaSansCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bf9b3d9811dd234f65f59b0d76d65a3e1e0c670aebac4deba38952c2a936f715', + 362440, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '90a6e0b1a1c39abb49b18aa5dbe06d7495f40394b01fab73b9e1e2bfec8a63f1', + 376612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a88fd0b03c58284d60144855004f6888c1b91eb5a7d21ac6060d56968934163e', + 366560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '07ba37d808679122d7388590ccc622b6f8f48bfad8116ba243f202818d5cd687', + 380672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '028eb7598bbb6f3a2bf5ea109d7df59dc6518811cde6bc25a6f865eca25b8cee', + 366388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c87c9cbd8b98469f1021dcdc5e28dc336195b600990e646a06cd9e832b747236', + 380244, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '169ee94c3194b600460cd09916275e7fb039fb87644ad57a8892658bba9306c3', + 365908, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a80c7a96e3707ecec8c736d84d84610e8872d361a22b5dbe0ebc3edd438d0d73', + 378688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '703cb9e1a6d80a19812381b5edceb1970b68ee76546ba8ae6ffed4c952fc475c', + 366208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9ad537677b67359092459fe782eab5dbddc81f5a162d5e5089e46dab0d6d3dd5', + 379868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c134a6d726ac821a9d923951743e3265e9f99a3853356396d759d0fb71cda42a', + 365892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '59ba972744bb1ef52a903a84b4b035e2086ee740963c12a11f352474b9aa841e', + 379376, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '29ce6255f4e521be2749f9557160ebbff60c5d160cd3a920e7bfc471c723dc3f', + 366196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '02a6c070347c5261fef75b88834e9b34ca51774d98830932ac9082d60713a416', + 379104, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a3fb82c69c6f36043219173b6f3137c43ead2f79f748d4a4a92ab045215eee54', + 366556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '22f5b83e1b510958faf311954f84c3a505ac7ca89aa279ee4e6a9274ec38e37f', + 379268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cbc26fda4428ab404d1e295ba3295da5cacf05e0851f8e4db99a4f65e1a0b382', + 366044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd732a2087e508d3999de6ed5f8c8834fe6eed4e270dabbce0bdc668087bace49', + 379108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FiraSansCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fira Sans Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Sans+Condensed + static TextTheme firaSansCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.firaSansCondensed(textStyle: textTheme.headline1), + headline2: GoogleFonts.firaSansCondensed(textStyle: textTheme.headline2), + headline3: GoogleFonts.firaSansCondensed(textStyle: textTheme.headline3), + headline4: GoogleFonts.firaSansCondensed(textStyle: textTheme.headline4), + headline5: GoogleFonts.firaSansCondensed(textStyle: textTheme.headline5), + headline6: GoogleFonts.firaSansCondensed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.firaSansCondensed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.firaSansCondensed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.firaSansCondensed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.firaSansCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.firaSansCondensed(textStyle: textTheme.caption), + button: GoogleFonts.firaSansCondensed(textStyle: textTheme.button), + overline: GoogleFonts.firaSansCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Fira Sans Extra Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Sans+Extra+Condensed + static TextStyle firaSansExtraCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aa0b73aa84c42a6d80d67e8301430b1553b52c7bd68fb79ebe8a2ff750ff58d7', + 361612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9f3e0c06798b24d5853a7192055d69133a9cbd73a9af9f24f62a00b0040d5776', + 376268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bbe50e8aab5ce91f02434c94791440b79cfbc9ee514967d9db84519325fb09bc', + 365232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1c79fb24ec14754ab4fcb134db375dcab006d976fab22d0b109e35fdfcd23366', + 380328, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '40d22d65e7e493b473980345c73d89b480fede26e26e656d2f209dca5e38c1ff', + 364864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'facbc467dbce58d849a1d881e13552a97aac95f1729e1fc2616bcbb139bc454e', + 379592, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '86b9aeff0987b7a36348174495862b0223a80ca3b251901d0ee4e171911f3313', + 364844, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a9b18a404b2171c7bd6f0b62b4a449ac30caaf7479ea04cf72848bf1e102975a', + 378808, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7fcaa10bd6c77effd3a995f07ef8dcc91c68362f20f82be9f906ba8cd66e3a36', + 365952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cf42464fc9f3e1569e0e1538e46fcc39fd02dba1db928aa594205dd74b6e7c72', + 379444, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0763b0bd415a608f8406877206fbac60d4785217a0983cf5569a0a2ed2922a87', + 365700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0f8d32c8579b66b9a1c5be889f3a3b21d4bd26f53af102bd2b4669b8407da059', + 379196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f844b8d0ff4049bc54bf6eeb2fadd15e2e910f98d0a77a3ca693111015e8a365', + 365784, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '07bfb33f5214d059269b95893bcb1220d50d72c1912c6b53f105a147900b7806', + 379176, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7a9cf07642c68b3200835e3a7e3688ed58ed76a3180a2e5cf9b94ce09e158671', + 365784, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '16f3dcda792af199394d486b422a6a669c52ee944c7bacd532337e88d9840501', + 379648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '99e363528f9256b35bd83f2a25a2e5f6739df4eeb724246bc87c5ab657192270', + 366184, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '53c97db75ae729e99796dc36bad33e04ea9d0036b759f49f202c3b403c3df3eb', + 380528, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FiraSansExtraCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fira Sans Extra Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fira+Sans+Extra+Condensed + static TextTheme firaSansExtraCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.headline1), + headline2: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.headline2), + headline3: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.headline3), + headline4: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.headline4), + headline5: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.headline5), + headline6: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.caption), + button: GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.button), + overline: + GoogleFonts.firaSansExtraCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Fjalla One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fjalla+One + static TextStyle fjallaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9bcbda294de33762d864eb998b9a19f1590afc95fe83a252472514751bd3ec21', + 26548, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FjallaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fjalla One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fjalla+One + static TextTheme fjallaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fjallaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.fjallaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.fjallaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.fjallaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.fjallaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.fjallaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fjallaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fjallaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fjallaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fjallaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fjallaOne(textStyle: textTheme.caption), + button: GoogleFonts.fjallaOne(textStyle: textTheme.button), + overline: GoogleFonts.fjallaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Fjord One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fjord+One + static TextStyle fjordOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d617688444b306b1af1ecd21190c110fcd2299e6164c66b9828f25bfaeeefa2', + 54132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FjordOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fjord One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fjord+One + static TextTheme fjordOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fjordOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.fjordOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.fjordOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.fjordOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.fjordOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.fjordOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fjordOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fjordOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fjordOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fjordOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fjordOne(textStyle: textTheme.caption), + button: GoogleFonts.fjordOne(textStyle: textTheme.button), + overline: GoogleFonts.fjordOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Flamenco font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Flamenco + static TextStyle flamenco({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5e1405fc92b58d9d35feb160e51edfaa54ace38f1e035d9fe2bfbf79a4087fe2', + 34360, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f5146448316dfb5f65a04e6a343c26f45f45587351d34559af1459a54eaa864c', + 36340, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Flamenco', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Flamenco font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Flamenco + static TextTheme flamencoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.flamenco(textStyle: textTheme.headline1), + headline2: GoogleFonts.flamenco(textStyle: textTheme.headline2), + headline3: GoogleFonts.flamenco(textStyle: textTheme.headline3), + headline4: GoogleFonts.flamenco(textStyle: textTheme.headline4), + headline5: GoogleFonts.flamenco(textStyle: textTheme.headline5), + headline6: GoogleFonts.flamenco(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.flamenco(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.flamenco(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.flamenco(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.flamenco(textStyle: textTheme.bodyText2), + caption: GoogleFonts.flamenco(textStyle: textTheme.caption), + button: GoogleFonts.flamenco(textStyle: textTheme.button), + overline: GoogleFonts.flamenco(textStyle: textTheme.overline), + ); + } + + /// Applies the Flavors font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Flavors + static TextStyle flavors({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f56d6a319c30faa62651b4a9fde87c7e4a496c678e7fb6642dccfa9c815d29dd', + 186224, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Flavors', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Flavors font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Flavors + static TextTheme flavorsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.flavors(textStyle: textTheme.headline1), + headline2: GoogleFonts.flavors(textStyle: textTheme.headline2), + headline3: GoogleFonts.flavors(textStyle: textTheme.headline3), + headline4: GoogleFonts.flavors(textStyle: textTheme.headline4), + headline5: GoogleFonts.flavors(textStyle: textTheme.headline5), + headline6: GoogleFonts.flavors(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.flavors(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.flavors(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.flavors(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.flavors(textStyle: textTheme.bodyText2), + caption: GoogleFonts.flavors(textStyle: textTheme.caption), + button: GoogleFonts.flavors(textStyle: textTheme.button), + overline: GoogleFonts.flavors(textStyle: textTheme.overline), + ); + } + + /// Applies the Fondamento font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fondamento + static TextStyle fondamento({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '75f9d66c336050a69b4366a5bd1cd8d8a0a5b7338dddd16b9af1f679ed3f6543', + 86560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '78976bc375126e59b80ff99b8d26195e4332d5cc86505149fc21d183b60e8340', + 78140, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Fondamento', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fondamento font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fondamento + static TextTheme fondamentoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fondamento(textStyle: textTheme.headline1), + headline2: GoogleFonts.fondamento(textStyle: textTheme.headline2), + headline3: GoogleFonts.fondamento(textStyle: textTheme.headline3), + headline4: GoogleFonts.fondamento(textStyle: textTheme.headline4), + headline5: GoogleFonts.fondamento(textStyle: textTheme.headline5), + headline6: GoogleFonts.fondamento(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fondamento(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fondamento(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fondamento(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fondamento(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fondamento(textStyle: textTheme.caption), + button: GoogleFonts.fondamento(textStyle: textTheme.button), + overline: GoogleFonts.fondamento(textStyle: textTheme.overline), + ); + } + + /// Applies the Fontdiner Swanky font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fontdiner+Swanky + static TextStyle fontdinerSwanky({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bf7bb77a0222af06961048f7335a7c3ced76ac59796882a14738b145a87f9b7a', + 45108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FontdinerSwanky', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fontdiner Swanky font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fontdiner+Swanky + static TextTheme fontdinerSwankyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fontdinerSwanky(textStyle: textTheme.headline1), + headline2: GoogleFonts.fontdinerSwanky(textStyle: textTheme.headline2), + headline3: GoogleFonts.fontdinerSwanky(textStyle: textTheme.headline3), + headline4: GoogleFonts.fontdinerSwanky(textStyle: textTheme.headline4), + headline5: GoogleFonts.fontdinerSwanky(textStyle: textTheme.headline5), + headline6: GoogleFonts.fontdinerSwanky(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fontdinerSwanky(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fontdinerSwanky(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fontdinerSwanky(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fontdinerSwanky(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fontdinerSwanky(textStyle: textTheme.caption), + button: GoogleFonts.fontdinerSwanky(textStyle: textTheme.button), + overline: GoogleFonts.fontdinerSwanky(textStyle: textTheme.overline), + ); + } + + /// Applies the Forum font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Forum + static TextStyle forum({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3dd2cb0744af0bc963b13a121b6194f8d271243f3973b40041c90b6113d168b2', + 204156, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Forum', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Forum font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Forum + static TextTheme forumTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.forum(textStyle: textTheme.headline1), + headline2: GoogleFonts.forum(textStyle: textTheme.headline2), + headline3: GoogleFonts.forum(textStyle: textTheme.headline3), + headline4: GoogleFonts.forum(textStyle: textTheme.headline4), + headline5: GoogleFonts.forum(textStyle: textTheme.headline5), + headline6: GoogleFonts.forum(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.forum(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.forum(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.forum(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.forum(textStyle: textTheme.bodyText2), + caption: GoogleFonts.forum(textStyle: textTheme.caption), + button: GoogleFonts.forum(textStyle: textTheme.button), + overline: GoogleFonts.forum(textStyle: textTheme.overline), + ); + } + + /// Applies the Francois One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Francois+One + static TextStyle francoisOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9732016aa4f374d99be54bb4dff92ffaa1133a4d293595c2bd7f621e01b38e85', + 57756, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FrancoisOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Francois One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Francois+One + static TextTheme francoisOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.francoisOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.francoisOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.francoisOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.francoisOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.francoisOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.francoisOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.francoisOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.francoisOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.francoisOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.francoisOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.francoisOne(textStyle: textTheme.caption), + button: GoogleFonts.francoisOne(textStyle: textTheme.button), + overline: GoogleFonts.francoisOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Frank Ruhl Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Frank+Ruhl+Libre + static TextStyle frankRuhlLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a5522476a201c815bdc0a30e19c5eb768edd4ddbe563647bf958a6326d7de351', + 62032, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9a33b30005cd2b612a70785a7205c43bf5f1a43c839b44d7ab7ddb581503e7ea', + 63180, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '009ea0ba06f79de2ac7a440b5f01b2aa767bbe10be39cfb151cef128d8c5c378', + 62764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bf711279089d27a7d3707704287cee15972baf963565dccb30e23486a65697cf', + 63068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1be4c921fb7b84259c4252c3caadda7f65b0ed5ad332ce0b680224f76e280363', + 63056, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FrankRuhlLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Frank Ruhl Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Frank+Ruhl+Libre + static TextTheme frankRuhlLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.frankRuhlLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.frankRuhlLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.frankRuhlLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.frankRuhlLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.frankRuhlLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.frankRuhlLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.frankRuhlLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.frankRuhlLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.frankRuhlLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.frankRuhlLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.frankRuhlLibre(textStyle: textTheme.caption), + button: GoogleFonts.frankRuhlLibre(textStyle: textTheme.button), + overline: GoogleFonts.frankRuhlLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Fraunces font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fraunces + static TextStyle fraunces({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd900c5e7c21d6a656061f76e8b35850081e6b5f4d1c79b3ccc810de326856264', + 64836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '44a19981fe2aa754aaeb06cf74c310df1b0a3f8b39480f0f062c91519630d135', + 65092, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ca9190aefdfe929bf1bf7d8427e0698deb0e431e1d227ab44422fd2f9e6ab0f', + 65156, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6614ff6a91390010260d3a667c5376fe821f8a42cb80b6aafd7cda6742f01bb8', + 65180, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bd1da6d4ca2fb801a00575fc9f126c39971a6bd892c8f0a6e618351a32bef3cd', + 65204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f2479851101e2899e533b00b37198a6d0651c0ec6d71f0ac394b00b9108905e1', + 65236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a93a3e6559a15ea27733c53e6e7502e5cf7293c46a26e9e1fa84705e65b10bc4', + 65192, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b03d8878b2e916deb87f3248147de1f5a362a78c9dcbd90d3aa4c4f092d75a7d', + 65248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '627caa3761664db664fc5696dca651dc39185ff859c73f0cf45c6fd5459f3a66', + 65284, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fe71fdadb7f0f3291a48c18ce4ea85c5d43311da4f1cf1beb3c9eb7fdae5578f', + 78464, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b026994e693313f3192474e6c97c7342f4bb901f76197c904f2db4716f14a9a3', + 78628, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f8ec75b94bf9bf34ce44fa022134ae5cb8f071ebc35e86da2ed1299daff3d784', + 78684, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '646ab5bcfa86872b15fc6ec5c75dc6aa5e71959ddd4dbbf7b1379791ad0cacba', + 78632, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '89f7a03ab5876ff35d51603bf66e41fc46a218b6990bae89e752844b6a7bd504', + 78712, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd58f242796551124a334dd48265d36ee828d367d78e377f599b6efde4325fb0a', + 78784, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4e842fa45d7770f0d2be7bae12e6694838b5e7f0cfc4185ebedcad05ccb0c86a', + 78688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9eb1f4be3bb43f44d63b98bfd7ed4ea85c24aeb9bc588b88bef34e42f8e45413', + 78720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'debe015577f85100a540d7110609c10a9ec1818cb48814478ff9401c34a4dfa9', + 78684, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Fraunces', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fraunces font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fraunces + static TextTheme frauncesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fraunces(textStyle: textTheme.headline1), + headline2: GoogleFonts.fraunces(textStyle: textTheme.headline2), + headline3: GoogleFonts.fraunces(textStyle: textTheme.headline3), + headline4: GoogleFonts.fraunces(textStyle: textTheme.headline4), + headline5: GoogleFonts.fraunces(textStyle: textTheme.headline5), + headline6: GoogleFonts.fraunces(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fraunces(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fraunces(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fraunces(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fraunces(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fraunces(textStyle: textTheme.caption), + button: GoogleFonts.fraunces(textStyle: textTheme.button), + overline: GoogleFonts.fraunces(textStyle: textTheme.overline), + ); + } + + /// Applies the Freckle Face font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Freckle+Face + static TextStyle freckleFace({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9c910c4a9c496679a818b2d0399b140f598d9f2f8b80bd1ad82b11b1aee3e93d', + 120676, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FreckleFace', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Freckle Face font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Freckle+Face + static TextTheme freckleFaceTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.freckleFace(textStyle: textTheme.headline1), + headline2: GoogleFonts.freckleFace(textStyle: textTheme.headline2), + headline3: GoogleFonts.freckleFace(textStyle: textTheme.headline3), + headline4: GoogleFonts.freckleFace(textStyle: textTheme.headline4), + headline5: GoogleFonts.freckleFace(textStyle: textTheme.headline5), + headline6: GoogleFonts.freckleFace(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.freckleFace(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.freckleFace(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.freckleFace(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.freckleFace(textStyle: textTheme.bodyText2), + caption: GoogleFonts.freckleFace(textStyle: textTheme.caption), + button: GoogleFonts.freckleFace(textStyle: textTheme.button), + overline: GoogleFonts.freckleFace(textStyle: textTheme.overline), + ); + } + + /// Applies the Fredericka the Great font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fredericka+the+Great + static TextStyle frederickaTheGreat({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '532a820c85a4591fdb49ad776bcc3950cb9e66fec68cb9263fc47c65406e575d', + 486172, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FrederickatheGreat', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fredericka the Great font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fredericka+the+Great + static TextTheme frederickaTheGreatTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.frederickaTheGreat(textStyle: textTheme.headline1), + headline2: GoogleFonts.frederickaTheGreat(textStyle: textTheme.headline2), + headline3: GoogleFonts.frederickaTheGreat(textStyle: textTheme.headline3), + headline4: GoogleFonts.frederickaTheGreat(textStyle: textTheme.headline4), + headline5: GoogleFonts.frederickaTheGreat(textStyle: textTheme.headline5), + headline6: GoogleFonts.frederickaTheGreat(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.frederickaTheGreat(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.frederickaTheGreat(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.frederickaTheGreat(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.frederickaTheGreat(textStyle: textTheme.bodyText2), + caption: GoogleFonts.frederickaTheGreat(textStyle: textTheme.caption), + button: GoogleFonts.frederickaTheGreat(textStyle: textTheme.button), + overline: GoogleFonts.frederickaTheGreat(textStyle: textTheme.overline), + ); + } + + /// Applies the Fredoka One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fredoka+One + static TextStyle fredokaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b002f69e5dfa418bb4943743c033c0ace0b62544c935797166842e3571c6e8c9', + 43452, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FredokaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fredoka One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fredoka+One + static TextTheme fredokaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fredokaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.fredokaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.fredokaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.fredokaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.fredokaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.fredokaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fredokaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fredokaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fredokaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fredokaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fredokaOne(textStyle: textTheme.caption), + button: GoogleFonts.fredokaOne(textStyle: textTheme.button), + overline: GoogleFonts.fredokaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Fresca font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fresca + static TextStyle fresca({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a2fb3bbb67399806b72a60bce8a66e5e8c7260a33a6ac9368b6130534242f340', + 32596, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Fresca', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fresca font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fresca + static TextTheme frescaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fresca(textStyle: textTheme.headline1), + headline2: GoogleFonts.fresca(textStyle: textTheme.headline2), + headline3: GoogleFonts.fresca(textStyle: textTheme.headline3), + headline4: GoogleFonts.fresca(textStyle: textTheme.headline4), + headline5: GoogleFonts.fresca(textStyle: textTheme.headline5), + headline6: GoogleFonts.fresca(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fresca(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fresca(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fresca(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fresca(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fresca(textStyle: textTheme.caption), + button: GoogleFonts.fresca(textStyle: textTheme.button), + overline: GoogleFonts.fresca(textStyle: textTheme.overline), + ); + } + + /// Applies the Frijole font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Frijole + static TextStyle frijole({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '82733a19e8b30ed4cd1325f58bf2631042b40495acd959d7dd5e38a7437ca7b1', + 227444, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Frijole', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Frijole font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Frijole + static TextTheme frijoleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.frijole(textStyle: textTheme.headline1), + headline2: GoogleFonts.frijole(textStyle: textTheme.headline2), + headline3: GoogleFonts.frijole(textStyle: textTheme.headline3), + headline4: GoogleFonts.frijole(textStyle: textTheme.headline4), + headline5: GoogleFonts.frijole(textStyle: textTheme.headline5), + headline6: GoogleFonts.frijole(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.frijole(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.frijole(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.frijole(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.frijole(textStyle: textTheme.bodyText2), + caption: GoogleFonts.frijole(textStyle: textTheme.caption), + button: GoogleFonts.frijole(textStyle: textTheme.button), + overline: GoogleFonts.frijole(textStyle: textTheme.overline), + ); + } + + /// Applies the Fruktur font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fruktur + static TextStyle fruktur({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '78b40ffd5e4efdcbad2cda23700072933938f41123f3149b98ceef2c1abdea2e', + 53120, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Fruktur', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fruktur font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fruktur + static TextTheme frukturTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fruktur(textStyle: textTheme.headline1), + headline2: GoogleFonts.fruktur(textStyle: textTheme.headline2), + headline3: GoogleFonts.fruktur(textStyle: textTheme.headline3), + headline4: GoogleFonts.fruktur(textStyle: textTheme.headline4), + headline5: GoogleFonts.fruktur(textStyle: textTheme.headline5), + headline6: GoogleFonts.fruktur(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fruktur(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fruktur(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fruktur(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fruktur(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fruktur(textStyle: textTheme.caption), + button: GoogleFonts.fruktur(textStyle: textTheme.button), + overline: GoogleFonts.fruktur(textStyle: textTheme.overline), + ); + } + + /// Applies the Fugaz One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fugaz+One + static TextStyle fugazOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bfd2016b130a197bdc3a7842cf6711aea8a2bc92fc2b0962ff9c9c266e680a07', + 27820, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'FugazOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Fugaz One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Fugaz+One + static TextTheme fugazOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.fugazOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.fugazOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.fugazOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.fugazOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.fugazOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.fugazOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.fugazOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.fugazOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.fugazOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.fugazOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.fugazOne(textStyle: textTheme.caption), + button: GoogleFonts.fugazOne(textStyle: textTheme.button), + overline: GoogleFonts.fugazOne(textStyle: textTheme.overline), + ); + } + + /// Applies the GFS Didot font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/GFS+Didot + static TextStyle gfsDidot({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f1953ca586ed73b65dd476de045e1f32b7446b71165bff9533f465ac46c73741', + 191144, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GFSDidot', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the GFS Didot font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/GFS+Didot + static TextTheme gfsDidotTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gfsDidot(textStyle: textTheme.headline1), + headline2: GoogleFonts.gfsDidot(textStyle: textTheme.headline2), + headline3: GoogleFonts.gfsDidot(textStyle: textTheme.headline3), + headline4: GoogleFonts.gfsDidot(textStyle: textTheme.headline4), + headline5: GoogleFonts.gfsDidot(textStyle: textTheme.headline5), + headline6: GoogleFonts.gfsDidot(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gfsDidot(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gfsDidot(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gfsDidot(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gfsDidot(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gfsDidot(textStyle: textTheme.caption), + button: GoogleFonts.gfsDidot(textStyle: textTheme.button), + overline: GoogleFonts.gfsDidot(textStyle: textTheme.overline), + ); + } + + /// Applies the GFS Neohellenic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/GFS+Neohellenic + static TextStyle gfsNeohellenic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bd8b39a679957cee00c5e50a23c2e6d3d6ba8d207873672a245c1de120f75028', + 189340, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '44d41c717d709e6a615d33a24a85f8bd9bb4eff83466d4fafb85844a41ac142b', + 164156, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '07ff63886ca5101d1a9bc31d7fb3f8dba0dfe2b725183cfb5349444e2ad8d4ad', + 148172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3317aac2c90d40a458f2817b4d514af6fa109becec2a0735a3415f2fda7a4603', + 161008, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GFSNeohellenic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the GFS Neohellenic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/GFS+Neohellenic + static TextTheme gfsNeohellenicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gfsNeohellenic(textStyle: textTheme.headline1), + headline2: GoogleFonts.gfsNeohellenic(textStyle: textTheme.headline2), + headline3: GoogleFonts.gfsNeohellenic(textStyle: textTheme.headline3), + headline4: GoogleFonts.gfsNeohellenic(textStyle: textTheme.headline4), + headline5: GoogleFonts.gfsNeohellenic(textStyle: textTheme.headline5), + headline6: GoogleFonts.gfsNeohellenic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gfsNeohellenic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gfsNeohellenic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gfsNeohellenic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gfsNeohellenic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gfsNeohellenic(textStyle: textTheme.caption), + button: GoogleFonts.gfsNeohellenic(textStyle: textTheme.button), + overline: GoogleFonts.gfsNeohellenic(textStyle: textTheme.overline), + ); + } + + /// Applies the Gabriela font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gabriela + static TextStyle gabriela({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2de2bbd02e6ea795828c6e6d6f6caf4fa1606b6a34d85e13e2700bba2b35e174', + 60904, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gabriela', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gabriela font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gabriela + static TextTheme gabrielaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gabriela(textStyle: textTheme.headline1), + headline2: GoogleFonts.gabriela(textStyle: textTheme.headline2), + headline3: GoogleFonts.gabriela(textStyle: textTheme.headline3), + headline4: GoogleFonts.gabriela(textStyle: textTheme.headline4), + headline5: GoogleFonts.gabriela(textStyle: textTheme.headline5), + headline6: GoogleFonts.gabriela(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gabriela(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gabriela(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gabriela(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gabriela(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gabriela(textStyle: textTheme.caption), + button: GoogleFonts.gabriela(textStyle: textTheme.button), + overline: GoogleFonts.gabriela(textStyle: textTheme.overline), + ); + } + + /// Applies the Gaegu font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gaegu + static TextStyle gaegu({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4b15c05b09479751067fd7c35435678b929504ea6e4a7e996ab5d09a77df6a9c', + 1665520, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aee336135ec347654a2f36421c05f5d68a6017eec18e264e58e7aeda0f702951', + 1687664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '047c721d06b371ebfb6f94beb758b1de181d8afc8c8e6eca6829405bd8a1cb91', + 1588560, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gaegu', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gaegu font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gaegu + static TextTheme gaeguTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gaegu(textStyle: textTheme.headline1), + headline2: GoogleFonts.gaegu(textStyle: textTheme.headline2), + headline3: GoogleFonts.gaegu(textStyle: textTheme.headline3), + headline4: GoogleFonts.gaegu(textStyle: textTheme.headline4), + headline5: GoogleFonts.gaegu(textStyle: textTheme.headline5), + headline6: GoogleFonts.gaegu(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gaegu(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gaegu(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gaegu(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gaegu(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gaegu(textStyle: textTheme.caption), + button: GoogleFonts.gaegu(textStyle: textTheme.button), + overline: GoogleFonts.gaegu(textStyle: textTheme.overline), + ); + } + + /// Applies the Gafata font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gafata + static TextStyle gafata({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd93ec736426526ff4d866b0522a300711a10168b8198ae7985029233601b84ac', + 37384, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gafata', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gafata font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gafata + static TextTheme gafataTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gafata(textStyle: textTheme.headline1), + headline2: GoogleFonts.gafata(textStyle: textTheme.headline2), + headline3: GoogleFonts.gafata(textStyle: textTheme.headline3), + headline4: GoogleFonts.gafata(textStyle: textTheme.headline4), + headline5: GoogleFonts.gafata(textStyle: textTheme.headline5), + headline6: GoogleFonts.gafata(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gafata(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gafata(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gafata(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gafata(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gafata(textStyle: textTheme.caption), + button: GoogleFonts.gafata(textStyle: textTheme.button), + overline: GoogleFonts.gafata(textStyle: textTheme.overline), + ); + } + + /// Applies the Galada font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Galada + static TextStyle galada({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '51eded8448fda4469fa2bddc7f049589ba69c75270cdf61adabbe4453abc8728', + 155660, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Galada', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Galada font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Galada + static TextTheme galadaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.galada(textStyle: textTheme.headline1), + headline2: GoogleFonts.galada(textStyle: textTheme.headline2), + headline3: GoogleFonts.galada(textStyle: textTheme.headline3), + headline4: GoogleFonts.galada(textStyle: textTheme.headline4), + headline5: GoogleFonts.galada(textStyle: textTheme.headline5), + headline6: GoogleFonts.galada(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.galada(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.galada(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.galada(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.galada(textStyle: textTheme.bodyText2), + caption: GoogleFonts.galada(textStyle: textTheme.caption), + button: GoogleFonts.galada(textStyle: textTheme.button), + overline: GoogleFonts.galada(textStyle: textTheme.overline), + ); + } + + /// Applies the Galdeano font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Galdeano + static TextStyle galdeano({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '854bd50aee5dea55f44b1b53ec61e1810043d0a16cdc4adaf2cd764a30bb3424', + 24820, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Galdeano', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Galdeano font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Galdeano + static TextTheme galdeanoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.galdeano(textStyle: textTheme.headline1), + headline2: GoogleFonts.galdeano(textStyle: textTheme.headline2), + headline3: GoogleFonts.galdeano(textStyle: textTheme.headline3), + headline4: GoogleFonts.galdeano(textStyle: textTheme.headline4), + headline5: GoogleFonts.galdeano(textStyle: textTheme.headline5), + headline6: GoogleFonts.galdeano(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.galdeano(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.galdeano(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.galdeano(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.galdeano(textStyle: textTheme.bodyText2), + caption: GoogleFonts.galdeano(textStyle: textTheme.caption), + button: GoogleFonts.galdeano(textStyle: textTheme.button), + overline: GoogleFonts.galdeano(textStyle: textTheme.overline), + ); + } + + /// Applies the Galindo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Galindo + static TextStyle galindo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c0d36dd1f81706dfcb698113c2682bb84feeffd515b1fa33d5c947ecc09e9719', + 57688, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Galindo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Galindo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Galindo + static TextTheme galindoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.galindo(textStyle: textTheme.headline1), + headline2: GoogleFonts.galindo(textStyle: textTheme.headline2), + headline3: GoogleFonts.galindo(textStyle: textTheme.headline3), + headline4: GoogleFonts.galindo(textStyle: textTheme.headline4), + headline5: GoogleFonts.galindo(textStyle: textTheme.headline5), + headline6: GoogleFonts.galindo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.galindo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.galindo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.galindo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.galindo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.galindo(textStyle: textTheme.caption), + button: GoogleFonts.galindo(textStyle: textTheme.button), + overline: GoogleFonts.galindo(textStyle: textTheme.overline), + ); + } + + /// Applies the Gamja Flower font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gamja+Flower + static TextStyle gamjaFlower({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e1315b2ce49da4d60b566f31827736a5b33670f46d95c26c4df7a7608f8634ea', + 6240108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GamjaFlower', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gamja Flower font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gamja+Flower + static TextTheme gamjaFlowerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gamjaFlower(textStyle: textTheme.headline1), + headline2: GoogleFonts.gamjaFlower(textStyle: textTheme.headline2), + headline3: GoogleFonts.gamjaFlower(textStyle: textTheme.headline3), + headline4: GoogleFonts.gamjaFlower(textStyle: textTheme.headline4), + headline5: GoogleFonts.gamjaFlower(textStyle: textTheme.headline5), + headline6: GoogleFonts.gamjaFlower(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gamjaFlower(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gamjaFlower(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gamjaFlower(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gamjaFlower(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gamjaFlower(textStyle: textTheme.caption), + button: GoogleFonts.gamjaFlower(textStyle: textTheme.button), + overline: GoogleFonts.gamjaFlower(textStyle: textTheme.overline), + ); + } + + /// Applies the Gayathri font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gayathri + static TextStyle gayathri({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6d8dba16325ef843155b024f792235ef54403fc4ce39f71ffe50c6a7cca110da', + 149780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd5538d385b6f28efddc8cc7d5e5cf0dcbe3243febfcb81ba4112a03ab5901d1e', + 148700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dac84e865cf4bf1f5f2bd54100f9b5ded81e0b2e3904ba8a3a6a992df1c13627', + 149624, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gayathri', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gayathri font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gayathri + static TextTheme gayathriTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gayathri(textStyle: textTheme.headline1), + headline2: GoogleFonts.gayathri(textStyle: textTheme.headline2), + headline3: GoogleFonts.gayathri(textStyle: textTheme.headline3), + headline4: GoogleFonts.gayathri(textStyle: textTheme.headline4), + headline5: GoogleFonts.gayathri(textStyle: textTheme.headline5), + headline6: GoogleFonts.gayathri(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gayathri(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gayathri(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gayathri(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gayathri(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gayathri(textStyle: textTheme.caption), + button: GoogleFonts.gayathri(textStyle: textTheme.button), + overline: GoogleFonts.gayathri(textStyle: textTheme.overline), + ); + } + + /// Applies the Gelasio font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gelasio + static TextStyle gelasio({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2c178f975cfe7fd1383143d870be6652cd515bc4ce08487980cc8a24cb7d6658', + 81660, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '89d39a153c70693460a8dfc8abc227627e98f02a750210cdf30eafeaa3c07eff', + 83204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '065abbe7b6a9053e634e391d0b4b626891e33a25a559b218467c09f92b7cbae7', + 82068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1f797bb1ec2839e88936d4386b44e04912d4d0dd8d71e154e831a3219ef0ccd2', + 83592, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b65a3501691d4bc3cf001ba7b5ce1b366cf394b48c365a5cdd65d100d824c21b', + 82096, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '60cd6e57a0fbd73db6d7c92723083486d34b20aaca29bd13abfcdd63d30a6965', + 83636, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f820053044147cdbb3843e05a662ec45de690ea2b00e3fa9d7b8ef154b1caa0c', + 82276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '14cfaa5707e104d5c01401d62d8b27006faa96f78acc2952512962cd9a5059b1', + 83448, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gelasio', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gelasio font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gelasio + static TextTheme gelasioTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gelasio(textStyle: textTheme.headline1), + headline2: GoogleFonts.gelasio(textStyle: textTheme.headline2), + headline3: GoogleFonts.gelasio(textStyle: textTheme.headline3), + headline4: GoogleFonts.gelasio(textStyle: textTheme.headline4), + headline5: GoogleFonts.gelasio(textStyle: textTheme.headline5), + headline6: GoogleFonts.gelasio(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gelasio(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gelasio(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gelasio(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gelasio(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gelasio(textStyle: textTheme.caption), + button: GoogleFonts.gelasio(textStyle: textTheme.button), + overline: GoogleFonts.gelasio(textStyle: textTheme.overline), + ); + } + + /// Applies the Gentium Basic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gentium+Basic + static TextStyle gentiumBasic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '86bcf47467c7c966ff4e8c216451273329982a4bbf3477b33615c1e5ff916fb2', + 204224, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd84eb1ad32e37c3f5e4a8eeaf077b66ec63a516eb0a631a71b3b17b0d6c43de1', + 211200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '33b22faef221568e2734ae86ee972b4499a967b00f6d6ae128b1649a904044d7', + 207812, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b1ea05dbd54b903a6206abbb48c0183924236546ddb457db2f97273aa1d47fcd', + 213608, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GentiumBasic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gentium Basic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gentium+Basic + static TextTheme gentiumBasicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gentiumBasic(textStyle: textTheme.headline1), + headline2: GoogleFonts.gentiumBasic(textStyle: textTheme.headline2), + headline3: GoogleFonts.gentiumBasic(textStyle: textTheme.headline3), + headline4: GoogleFonts.gentiumBasic(textStyle: textTheme.headline4), + headline5: GoogleFonts.gentiumBasic(textStyle: textTheme.headline5), + headline6: GoogleFonts.gentiumBasic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gentiumBasic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gentiumBasic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gentiumBasic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gentiumBasic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gentiumBasic(textStyle: textTheme.caption), + button: GoogleFonts.gentiumBasic(textStyle: textTheme.button), + overline: GoogleFonts.gentiumBasic(textStyle: textTheme.overline), + ); + } + + /// Applies the Gentium Book Basic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gentium+Book+Basic + static TextStyle gentiumBookBasic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0323cf4ee5a40f059eff7a114c130fd29fb414699c37336d6d305d42e3d30318', + 206468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '105db1c75307402ef0aaf8126c049e1910ec90f6a89c2745ac1fff1eb7525d03', + 212700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '743cd21e49c299921cf5cdf719c179e0adc85a19aa73a142726805c1cb607f82', + 207756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '73ca1eff2db69f993bfff34753f6f216404bceaeb657dbf84734a8bce6f279a5', + 214236, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GentiumBookBasic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gentium Book Basic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gentium+Book+Basic + static TextTheme gentiumBookBasicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gentiumBookBasic(textStyle: textTheme.headline1), + headline2: GoogleFonts.gentiumBookBasic(textStyle: textTheme.headline2), + headline3: GoogleFonts.gentiumBookBasic(textStyle: textTheme.headline3), + headline4: GoogleFonts.gentiumBookBasic(textStyle: textTheme.headline4), + headline5: GoogleFonts.gentiumBookBasic(textStyle: textTheme.headline5), + headline6: GoogleFonts.gentiumBookBasic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gentiumBookBasic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gentiumBookBasic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gentiumBookBasic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gentiumBookBasic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gentiumBookBasic(textStyle: textTheme.caption), + button: GoogleFonts.gentiumBookBasic(textStyle: textTheme.button), + overline: GoogleFonts.gentiumBookBasic(textStyle: textTheme.overline), + ); + } + + /// Applies the Geo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Geo + static TextStyle geo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1eea344681e2eab82088131eca8f88554cd2107b68a5bc70ac8e0eeb7877920e', + 27012, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6aff203bbf11c87ca0cbd331d3181277be2cc5f373a85fc6a0c898ed393d151b', + 27932, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Geo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Geo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Geo + static TextTheme geoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.geo(textStyle: textTheme.headline1), + headline2: GoogleFonts.geo(textStyle: textTheme.headline2), + headline3: GoogleFonts.geo(textStyle: textTheme.headline3), + headline4: GoogleFonts.geo(textStyle: textTheme.headline4), + headline5: GoogleFonts.geo(textStyle: textTheme.headline5), + headline6: GoogleFonts.geo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.geo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.geo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.geo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.geo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.geo(textStyle: textTheme.caption), + button: GoogleFonts.geo(textStyle: textTheme.button), + overline: GoogleFonts.geo(textStyle: textTheme.overline), + ); + } + + /// Applies the Geostar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Geostar + static TextStyle geostar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7b9967368c76fa8693221781a74e18323bde42a1df8fff30b1d5b2dd2e654dc5', + 41264, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Geostar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Geostar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Geostar + static TextTheme geostarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.geostar(textStyle: textTheme.headline1), + headline2: GoogleFonts.geostar(textStyle: textTheme.headline2), + headline3: GoogleFonts.geostar(textStyle: textTheme.headline3), + headline4: GoogleFonts.geostar(textStyle: textTheme.headline4), + headline5: GoogleFonts.geostar(textStyle: textTheme.headline5), + headline6: GoogleFonts.geostar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.geostar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.geostar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.geostar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.geostar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.geostar(textStyle: textTheme.caption), + button: GoogleFonts.geostar(textStyle: textTheme.button), + overline: GoogleFonts.geostar(textStyle: textTheme.overline), + ); + } + + /// Applies the Geostar Fill font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Geostar+Fill + static TextStyle geostarFill({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4be1af95d7c9c5f412f0bd7ca965a79a3691840d102dc4d542068f95fc8a04ac', + 38800, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GeostarFill', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Geostar Fill font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Geostar+Fill + static TextTheme geostarFillTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.geostarFill(textStyle: textTheme.headline1), + headline2: GoogleFonts.geostarFill(textStyle: textTheme.headline2), + headline3: GoogleFonts.geostarFill(textStyle: textTheme.headline3), + headline4: GoogleFonts.geostarFill(textStyle: textTheme.headline4), + headline5: GoogleFonts.geostarFill(textStyle: textTheme.headline5), + headline6: GoogleFonts.geostarFill(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.geostarFill(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.geostarFill(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.geostarFill(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.geostarFill(textStyle: textTheme.bodyText2), + caption: GoogleFonts.geostarFill(textStyle: textTheme.caption), + button: GoogleFonts.geostarFill(textStyle: textTheme.button), + overline: GoogleFonts.geostarFill(textStyle: textTheme.overline), + ); + } + + /// Applies the Germania One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Germania+One + static TextStyle germaniaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b7dd1af0258695612f37eb7db169c99f09801337d690f6880dc4a7c351f830d', + 33192, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GermaniaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Germania One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Germania+One + static TextTheme germaniaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.germaniaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.germaniaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.germaniaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.germaniaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.germaniaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.germaniaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.germaniaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.germaniaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.germaniaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.germaniaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.germaniaOne(textStyle: textTheme.caption), + button: GoogleFonts.germaniaOne(textStyle: textTheme.button), + overline: GoogleFonts.germaniaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Gidugu font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gidugu + static TextStyle gidugu({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8cbe8c40904c76d293cafa7611edff01d450f676f40d33e66863b5f7b10e7e1e', + 185544, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gidugu', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gidugu font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gidugu + static TextTheme giduguTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gidugu(textStyle: textTheme.headline1), + headline2: GoogleFonts.gidugu(textStyle: textTheme.headline2), + headline3: GoogleFonts.gidugu(textStyle: textTheme.headline3), + headline4: GoogleFonts.gidugu(textStyle: textTheme.headline4), + headline5: GoogleFonts.gidugu(textStyle: textTheme.headline5), + headline6: GoogleFonts.gidugu(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gidugu(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gidugu(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gidugu(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gidugu(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gidugu(textStyle: textTheme.caption), + button: GoogleFonts.gidugu(textStyle: textTheme.button), + overline: GoogleFonts.gidugu(textStyle: textTheme.overline), + ); + } + + /// Applies the Gilda Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gilda+Display + static TextStyle gildaDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd46a827dcf6e69348a898d71938544f7f63de075eaea97cb6cb797bd3c234904', + 36756, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GildaDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gilda Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gilda+Display + static TextTheme gildaDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gildaDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.gildaDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.gildaDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.gildaDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.gildaDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.gildaDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gildaDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gildaDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gildaDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gildaDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gildaDisplay(textStyle: textTheme.caption), + button: GoogleFonts.gildaDisplay(textStyle: textTheme.button), + overline: GoogleFonts.gildaDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Girassol font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Girassol + static TextStyle girassol({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ac0b37ea4560c8fe837a50cfdeb9b18f00c84d4fe2556fd1934257270c6c1a3', + 31140, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Girassol', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Girassol font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Girassol + static TextTheme girassolTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.girassol(textStyle: textTheme.headline1), + headline2: GoogleFonts.girassol(textStyle: textTheme.headline2), + headline3: GoogleFonts.girassol(textStyle: textTheme.headline3), + headline4: GoogleFonts.girassol(textStyle: textTheme.headline4), + headline5: GoogleFonts.girassol(textStyle: textTheme.headline5), + headline6: GoogleFonts.girassol(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.girassol(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.girassol(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.girassol(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.girassol(textStyle: textTheme.bodyText2), + caption: GoogleFonts.girassol(textStyle: textTheme.caption), + button: GoogleFonts.girassol(textStyle: textTheme.button), + overline: GoogleFonts.girassol(textStyle: textTheme.overline), + ); + } + + /// Applies the Give You Glory font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Give+You+Glory + static TextStyle giveYouGlory({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '309c5df7e1fe41874a8f14de3edeb9c32a42ec3e31d17e863696920deb848095', + 42564, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GiveYouGlory', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Give You Glory font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Give+You+Glory + static TextTheme giveYouGloryTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.giveYouGlory(textStyle: textTheme.headline1), + headline2: GoogleFonts.giveYouGlory(textStyle: textTheme.headline2), + headline3: GoogleFonts.giveYouGlory(textStyle: textTheme.headline3), + headline4: GoogleFonts.giveYouGlory(textStyle: textTheme.headline4), + headline5: GoogleFonts.giveYouGlory(textStyle: textTheme.headline5), + headline6: GoogleFonts.giveYouGlory(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.giveYouGlory(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.giveYouGlory(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.giveYouGlory(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.giveYouGlory(textStyle: textTheme.bodyText2), + caption: GoogleFonts.giveYouGlory(textStyle: textTheme.caption), + button: GoogleFonts.giveYouGlory(textStyle: textTheme.button), + overline: GoogleFonts.giveYouGlory(textStyle: textTheme.overline), + ); + } + + /// Applies the Glass Antiqua font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Glass+Antiqua + static TextStyle glassAntiqua({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e175bb6abcc9cd23e8e7fff60b5a13a870ecafeb7aab3af67614547c14354aad', + 62964, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GlassAntiqua', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Glass Antiqua font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Glass+Antiqua + static TextTheme glassAntiquaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.glassAntiqua(textStyle: textTheme.headline1), + headline2: GoogleFonts.glassAntiqua(textStyle: textTheme.headline2), + headline3: GoogleFonts.glassAntiqua(textStyle: textTheme.headline3), + headline4: GoogleFonts.glassAntiqua(textStyle: textTheme.headline4), + headline5: GoogleFonts.glassAntiqua(textStyle: textTheme.headline5), + headline6: GoogleFonts.glassAntiqua(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.glassAntiqua(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.glassAntiqua(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.glassAntiqua(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.glassAntiqua(textStyle: textTheme.bodyText2), + caption: GoogleFonts.glassAntiqua(textStyle: textTheme.caption), + button: GoogleFonts.glassAntiqua(textStyle: textTheme.button), + overline: GoogleFonts.glassAntiqua(textStyle: textTheme.overline), + ); + } + + /// Applies the Glegoo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Glegoo + static TextStyle glegoo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91a94e2b397503a978c0e061d4d1f39323e741fd649d6f743538a8d947cc1f13', + 226220, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '32ba529e1df310b4629e2a4b94b577e8d2b995647f1b0b02b97cbc401c43100c', + 221232, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Glegoo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Glegoo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Glegoo + static TextTheme glegooTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.glegoo(textStyle: textTheme.headline1), + headline2: GoogleFonts.glegoo(textStyle: textTheme.headline2), + headline3: GoogleFonts.glegoo(textStyle: textTheme.headline3), + headline4: GoogleFonts.glegoo(textStyle: textTheme.headline4), + headline5: GoogleFonts.glegoo(textStyle: textTheme.headline5), + headline6: GoogleFonts.glegoo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.glegoo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.glegoo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.glegoo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.glegoo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.glegoo(textStyle: textTheme.caption), + button: GoogleFonts.glegoo(textStyle: textTheme.button), + overline: GoogleFonts.glegoo(textStyle: textTheme.overline), + ); + } + + /// Applies the Gloria Hallelujah font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gloria+Hallelujah + static TextStyle gloriaHallelujah({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0ea0610b2d462be9ddfd55db487fd670e7b0855857d198cc6293f623adc66ff8', + 56248, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GloriaHallelujah', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gloria Hallelujah font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gloria+Hallelujah + static TextTheme gloriaHallelujahTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gloriaHallelujah(textStyle: textTheme.headline1), + headline2: GoogleFonts.gloriaHallelujah(textStyle: textTheme.headline2), + headline3: GoogleFonts.gloriaHallelujah(textStyle: textTheme.headline3), + headline4: GoogleFonts.gloriaHallelujah(textStyle: textTheme.headline4), + headline5: GoogleFonts.gloriaHallelujah(textStyle: textTheme.headline5), + headline6: GoogleFonts.gloriaHallelujah(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gloriaHallelujah(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gloriaHallelujah(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gloriaHallelujah(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gloriaHallelujah(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gloriaHallelujah(textStyle: textTheme.caption), + button: GoogleFonts.gloriaHallelujah(textStyle: textTheme.button), + overline: GoogleFonts.gloriaHallelujah(textStyle: textTheme.overline), + ); + } + + /// Applies the Goblin One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Goblin+One + static TextStyle goblinOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d2f4678ed209cc09bfe4cefb1df66ef95e21a1b2f6f71fdf1c8408b5135472f', + 36712, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GoblinOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Goblin One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Goblin+One + static TextTheme goblinOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.goblinOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.goblinOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.goblinOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.goblinOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.goblinOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.goblinOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.goblinOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.goblinOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.goblinOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.goblinOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.goblinOne(textStyle: textTheme.caption), + button: GoogleFonts.goblinOne(textStyle: textTheme.button), + overline: GoogleFonts.goblinOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Gochi Hand font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gochi+Hand + static TextStyle gochiHand({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e396d3d6d4147d9267b06c9619b938d34176559c67b48c046d971904edf8ce36', + 36908, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GochiHand', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gochi Hand font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gochi+Hand + static TextTheme gochiHandTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gochiHand(textStyle: textTheme.headline1), + headline2: GoogleFonts.gochiHand(textStyle: textTheme.headline2), + headline3: GoogleFonts.gochiHand(textStyle: textTheme.headline3), + headline4: GoogleFonts.gochiHand(textStyle: textTheme.headline4), + headline5: GoogleFonts.gochiHand(textStyle: textTheme.headline5), + headline6: GoogleFonts.gochiHand(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gochiHand(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gochiHand(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gochiHand(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gochiHand(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gochiHand(textStyle: textTheme.caption), + button: GoogleFonts.gochiHand(textStyle: textTheme.button), + overline: GoogleFonts.gochiHand(textStyle: textTheme.overline), + ); + } + + /// Applies the Goldman font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Goldman + static TextStyle goldman({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dcd1ae24891a07f6290dc08c898027cce4db97ed083aa2a36fc100e4b14afcb6', + 53460, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '22fe54c333c535b13743b02667f696f92fafb66605f4cc08de38154504789f8e', + 53248, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Goldman', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Goldman font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Goldman + static TextTheme goldmanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.goldman(textStyle: textTheme.headline1), + headline2: GoogleFonts.goldman(textStyle: textTheme.headline2), + headline3: GoogleFonts.goldman(textStyle: textTheme.headline3), + headline4: GoogleFonts.goldman(textStyle: textTheme.headline4), + headline5: GoogleFonts.goldman(textStyle: textTheme.headline5), + headline6: GoogleFonts.goldman(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.goldman(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.goldman(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.goldman(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.goldman(textStyle: textTheme.bodyText2), + caption: GoogleFonts.goldman(textStyle: textTheme.caption), + button: GoogleFonts.goldman(textStyle: textTheme.button), + overline: GoogleFonts.goldman(textStyle: textTheme.overline), + ); + } + + /// Applies the Gorditas font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gorditas + static TextStyle gorditas({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '987a5551dac8207ac89158c984bb117eac9569a4def85c67405a6f7ee656ca7b', + 76880, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a73ab190434815fb46d5c9f8095a8d40543c248bd203391f3e120aebb2c223e', + 78612, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gorditas', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gorditas font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gorditas + static TextTheme gorditasTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gorditas(textStyle: textTheme.headline1), + headline2: GoogleFonts.gorditas(textStyle: textTheme.headline2), + headline3: GoogleFonts.gorditas(textStyle: textTheme.headline3), + headline4: GoogleFonts.gorditas(textStyle: textTheme.headline4), + headline5: GoogleFonts.gorditas(textStyle: textTheme.headline5), + headline6: GoogleFonts.gorditas(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gorditas(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gorditas(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gorditas(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gorditas(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gorditas(textStyle: textTheme.caption), + button: GoogleFonts.gorditas(textStyle: textTheme.button), + overline: GoogleFonts.gorditas(textStyle: textTheme.overline), + ); + } + + /// Applies the Gothic A1 font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gothic+A1 + static TextStyle gothicA1({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1ae3fbdff726cb716a361659f8efd51296b280ce94f4582c7eea6a69905050e0', + 1315216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c2132aa2e6fae5ce3ac066aa23fc45e7a83571666c0b4cc9c4dd7bf734363f05', + 1313548, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91a462996301381a669ea6f51dc5030f155c0a85e896a575a5d80dfbd8471779', + 1314204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a9676e8d54fdeef2976f9c8fde17f39fec21956933f3ee203655c2655f350e08', + 1311208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d0781b8cc09648594a3bba783b1d463592a004fea48584b181b631e2bfc9956', + 1311800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '94fbbaaaa3c999db13176f3b5a8cc657f1e471472f8efc8fd47d298191d6ea56', + 1311192, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e689bf118e2ff1a2884e3170b3d1829ccfdd0147baf98523e7fe0494299969f1', + 1310932, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'db82d9a4e6dabe467f8879d6c23074f7bb1b8ea95857527aec64201e53126f6d', + 1310760, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ad367f71a0970215c6e16efbe180999b11228c398745e8021187b0aa608fdd2d', + 1312032, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GothicA1', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gothic A1 font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gothic+A1 + static TextTheme gothicA1TextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gothicA1(textStyle: textTheme.headline1), + headline2: GoogleFonts.gothicA1(textStyle: textTheme.headline2), + headline3: GoogleFonts.gothicA1(textStyle: textTheme.headline3), + headline4: GoogleFonts.gothicA1(textStyle: textTheme.headline4), + headline5: GoogleFonts.gothicA1(textStyle: textTheme.headline5), + headline6: GoogleFonts.gothicA1(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gothicA1(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gothicA1(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gothicA1(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gothicA1(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gothicA1(textStyle: textTheme.caption), + button: GoogleFonts.gothicA1(textStyle: textTheme.button), + overline: GoogleFonts.gothicA1(textStyle: textTheme.overline), + ); + } + + /// Applies the Gotu font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gotu + static TextStyle gotu({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a8a68ca0799b2cb999b3b4c9ed791251063ffa4c8d870256ebc31438c8e3c5f1', + 517000, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gotu', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gotu font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gotu + static TextTheme gotuTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gotu(textStyle: textTheme.headline1), + headline2: GoogleFonts.gotu(textStyle: textTheme.headline2), + headline3: GoogleFonts.gotu(textStyle: textTheme.headline3), + headline4: GoogleFonts.gotu(textStyle: textTheme.headline4), + headline5: GoogleFonts.gotu(textStyle: textTheme.headline5), + headline6: GoogleFonts.gotu(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gotu(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gotu(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gotu(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gotu(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gotu(textStyle: textTheme.caption), + button: GoogleFonts.gotu(textStyle: textTheme.button), + overline: GoogleFonts.gotu(textStyle: textTheme.overline), + ); + } + + /// Applies the Goudy Bookletter 1911 font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Goudy+Bookletter+1911 + static TextStyle goudyBookletter1911({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a4ea1fd345de7df9251d754f6ecc38147180ed991b78a0979f3ec409ee987e8b', + 53284, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GoudyBookletter1911', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Goudy Bookletter 1911 font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Goudy+Bookletter+1911 + static TextTheme goudyBookletter1911TextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.headline1), + headline2: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.headline2), + headline3: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.headline3), + headline4: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.headline4), + headline5: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.headline5), + headline6: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.goudyBookletter1911(textStyle: textTheme.bodyText2), + caption: GoogleFonts.goudyBookletter1911(textStyle: textTheme.caption), + button: GoogleFonts.goudyBookletter1911(textStyle: textTheme.button), + overline: GoogleFonts.goudyBookletter1911(textStyle: textTheme.overline), + ); + } + + /// Applies the Graduate font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Graduate + static TextStyle graduate({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '26483ff4a5a591dbbd59a7a59b4dfcfbc10b96f20b67a1b2af0da6fbc33dc2da', + 22684, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Graduate', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Graduate font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Graduate + static TextTheme graduateTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.graduate(textStyle: textTheme.headline1), + headline2: GoogleFonts.graduate(textStyle: textTheme.headline2), + headline3: GoogleFonts.graduate(textStyle: textTheme.headline3), + headline4: GoogleFonts.graduate(textStyle: textTheme.headline4), + headline5: GoogleFonts.graduate(textStyle: textTheme.headline5), + headline6: GoogleFonts.graduate(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.graduate(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.graduate(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.graduate(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.graduate(textStyle: textTheme.bodyText2), + caption: GoogleFonts.graduate(textStyle: textTheme.caption), + button: GoogleFonts.graduate(textStyle: textTheme.button), + overline: GoogleFonts.graduate(textStyle: textTheme.overline), + ); + } + + /// Applies the Grand Hotel font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Grand+Hotel + static TextStyle grandHotel({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0804e7944e677d28eec42a45ba39935faadd27b2b1a8aab2e96c1736b7bb4e2d', + 64596, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GrandHotel', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Grand Hotel font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Grand+Hotel + static TextTheme grandHotelTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.grandHotel(textStyle: textTheme.headline1), + headline2: GoogleFonts.grandHotel(textStyle: textTheme.headline2), + headline3: GoogleFonts.grandHotel(textStyle: textTheme.headline3), + headline4: GoogleFonts.grandHotel(textStyle: textTheme.headline4), + headline5: GoogleFonts.grandHotel(textStyle: textTheme.headline5), + headline6: GoogleFonts.grandHotel(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.grandHotel(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.grandHotel(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.grandHotel(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.grandHotel(textStyle: textTheme.bodyText2), + caption: GoogleFonts.grandHotel(textStyle: textTheme.caption), + button: GoogleFonts.grandHotel(textStyle: textTheme.button), + overline: GoogleFonts.grandHotel(textStyle: textTheme.overline), + ); + } + + /// Applies the Grandstander font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Grandstander + static TextStyle grandstander({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4728f0d725d8b6a76c16070768044b9e6b6236a1628bb1ad24e9f50d95e85322', + 77324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ae29f98ccf49de9457db8cb4d9146e1c4ba7e9d2a45b5075c9dedfec40abf67f', + 77436, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8193fdba834ec833e32ab815cdb1c7637a538abac0a55e2643d1a21920a7e0d9', + 77428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e2c1590aac3af3109a3f0f52084234f7d917d5446571816e7be76ef662aa05b1', + 77376, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '29dccd81bd511856971d9e11bcfb9c1e4b724f2c99d71ba4640765e0f74eddc7', + 77440, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'baff651d2552b4ff658decc4c24b9d1441f7e2f4edb2320302eba113473a3f4a', + 77524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a2168833f9cb80d9d3adcb7b1a9435f687a76914791e8a3419387728a9e232ac', + 77428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5d505c16c32b5d8c7d7cde0728a342d3a573f37e6a9ef881f0a0129aa3ab6f04', + 77524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cbb55db42cb6dfee25da8fcfbf0c4c3b46c6362b1f7b9c5f0164b1f473ea2b03', + 77388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5443451f9161dd49fcf0d8d005fa4c515212104a03ae55cc97aec53e9a7c2d2f', + 77988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ef9d72ee3df361c727f567bad43b474be4b602a25122af6ad4678a302f7dbf92', + 78116, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f51d56b5df52fe7659247f6bfa8ad45ba13e1476512b42c520eb1c9834080849', + 77952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd43f0a89cc73b807dd79cff8a129e8d307413088dbfd9aeb43dfc5afdb5818e1', + 77816, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '833f88d7d64e5f6e66783359b2e830e690548e64bed4b0222b3cac874860c653', + 77932, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5fb6a65ca4e9bd753f2a2d2996602407ced5748f0ab0c16492c700e2f5bfbfd4', + 77952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bdad650a656e4ee7285056730af9939c46c0137ab7e534126aa5b1b117354289', + 77876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cf38a0abf71444761ea9920e2bd481d20c2cb7ae9c54e42b481d98d5fb8f5be0', + 78012, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eb1dc21dffbf8e7edc9f5a5d7f465b65cd836849be40c3c234c976c668d5b2e2', + 77912, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Grandstander', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Grandstander font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Grandstander + static TextTheme grandstanderTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.grandstander(textStyle: textTheme.headline1), + headline2: GoogleFonts.grandstander(textStyle: textTheme.headline2), + headline3: GoogleFonts.grandstander(textStyle: textTheme.headline3), + headline4: GoogleFonts.grandstander(textStyle: textTheme.headline4), + headline5: GoogleFonts.grandstander(textStyle: textTheme.headline5), + headline6: GoogleFonts.grandstander(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.grandstander(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.grandstander(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.grandstander(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.grandstander(textStyle: textTheme.bodyText2), + caption: GoogleFonts.grandstander(textStyle: textTheme.caption), + button: GoogleFonts.grandstander(textStyle: textTheme.button), + overline: GoogleFonts.grandstander(textStyle: textTheme.overline), + ); + } + + /// Applies the Gravitas One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gravitas+One + static TextStyle gravitasOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8173c77c59dd22de492971f099b97bde163e13062c6df365ffe3f201cf4de551', + 41424, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GravitasOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gravitas One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gravitas+One + static TextTheme gravitasOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gravitasOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.gravitasOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.gravitasOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.gravitasOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.gravitasOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.gravitasOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gravitasOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gravitasOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gravitasOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gravitasOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gravitasOne(textStyle: textTheme.caption), + button: GoogleFonts.gravitasOne(textStyle: textTheme.button), + overline: GoogleFonts.gravitasOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Great Vibes font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Great+Vibes + static TextStyle greatVibes({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a4131255cb3cb73cefc120a8d68c6888fa33a5c24045934a0353f0c199fe254d', + 105956, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GreatVibes', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Great Vibes font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Great+Vibes + static TextTheme greatVibesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.greatVibes(textStyle: textTheme.headline1), + headline2: GoogleFonts.greatVibes(textStyle: textTheme.headline2), + headline3: GoogleFonts.greatVibes(textStyle: textTheme.headline3), + headline4: GoogleFonts.greatVibes(textStyle: textTheme.headline4), + headline5: GoogleFonts.greatVibes(textStyle: textTheme.headline5), + headline6: GoogleFonts.greatVibes(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.greatVibes(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.greatVibes(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.greatVibes(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.greatVibes(textStyle: textTheme.bodyText2), + caption: GoogleFonts.greatVibes(textStyle: textTheme.caption), + button: GoogleFonts.greatVibes(textStyle: textTheme.button), + overline: GoogleFonts.greatVibes(textStyle: textTheme.overline), + ); + } + + /// Applies the Grenze font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Grenze + static TextStyle grenze({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0990a8c493d15ce4bc040461ac83778fbd658ffb4e5470ded379c5d932c0ad64', + 62884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b76ab96616d0138d6376f8da6777f4dcd53174ecd6cc3d105f926d138412156a', + 65344, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ea5652640e0126eca9dd8ec9af72afd38c03f0608cf8066ba85e8d3cc84b72f5', + 63156, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '62177aecb9fc857767b77f93de0e28aaff0aa14d6743fcb2e074b3b17d10ed6a', + 65532, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '306db261f5db582fb834c4d4bd749cd7bbd220410f22c0f91e9da3906fea195a', + 62964, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8328aa2d7be6cb51506689c284e11d44e22a65cc87f444619d3e74029b3c6b4d', + 65500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c881a6bd46175e518a6059d0c5fd2fef4f0e1ad8433e903ab0df21ac113772f6', + 62924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '396353d483f4c64a4c320999b4a8ea7bd7d3fc2f3d1126d31dd62c2bd7474f60', + 64960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7685525db63573b7d2818041934dd2608e56fd7eaf5af7bcbb29f02b9cd5f948', + 62892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'da991020ed06646693057a5dfc4dae9bed270609081f0e2167ff1b6d6893483a', + 65556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c4b885545038f7f41fa22671f8e1d9becd9672ffe403f1267a77e244c2ebbe7f', + 62772, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e85fde935308bfd3bcdc33373ab0a7296b4c852c9689504d830dd8a2c722828c', + 65404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '59bbcbbac7dbc3b0875ff2e1f9b73917427553fe9494ce5072c9408e4805693c', + 62696, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b408bf29942d61415edcf80e8d329a6c9d54eedf1b2a0be057164e93cda0029a', + 65328, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '10f31373e1d786f62febeb25a546f803218359aefe0c2e9d0247008665f54a92', + 62844, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6c6bbecf82467b9cbc2bc5373b2132d2a72fc1ab1d19beab9247d96b9aeaf437', + 65244, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e99c2c3ccee2de60f0fa0836977cfb7f1f5db667eaba9c59b205a9860377cb15', + 62624, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '26ebaa2c75db3de90f21f701605ab5e085a7f4c1f23fcb5235a754a34ef4defa', + 65320, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Grenze', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Grenze font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Grenze + static TextTheme grenzeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.grenze(textStyle: textTheme.headline1), + headline2: GoogleFonts.grenze(textStyle: textTheme.headline2), + headline3: GoogleFonts.grenze(textStyle: textTheme.headline3), + headline4: GoogleFonts.grenze(textStyle: textTheme.headline4), + headline5: GoogleFonts.grenze(textStyle: textTheme.headline5), + headline6: GoogleFonts.grenze(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.grenze(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.grenze(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.grenze(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.grenze(textStyle: textTheme.bodyText2), + caption: GoogleFonts.grenze(textStyle: textTheme.caption), + button: GoogleFonts.grenze(textStyle: textTheme.button), + overline: GoogleFonts.grenze(textStyle: textTheme.overline), + ); + } + + /// Applies the Grenze Gotisch font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Grenze+Gotisch + static TextStyle grenzeGotisch({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '630eddc1a2f2cf8afebfc8fa0195e160fc518760531dc30f6db8bcac1438161f', + 61512, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b9839fe32fe46b5f6944aa5a606dbfce3b3d3b0bc0c0d754aa3ab8aac65ee400', + 61668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7045b9de777a2a5a10b243555575e0b557bb010d12e8a8130d2defb5c87dbb98', + 61716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '66e9cb492a660dcf2f6845561edcaccd7e3de7cb23b39d658ab0068c1cb2a86b', + 61580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5f87b69505d4746d8702cd79495b820385e7d8c381b94486ce7db3bbeca5cd05', + 61708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cd890da87927a99881c558f0cdd02ddc9fd27eb8fbe93dce51b3f45b78d0c6b9', + 61800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a3adffa3e98ccd30dc75f064ef660b6e0c25ac58975e3acc6600c1f4700421cd', + 61736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bbc64ccba2dd0be9a898ff22c2baf7e251f48d1fa437d46493bece1afebf6bf6', + 61820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '822b841e7c07f59217780cbbf7a49b3744dc75bb0e0644dfee1e3d4a7ff1ca43', + 61776, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'GrenzeGotisch', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Grenze Gotisch font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Grenze+Gotisch + static TextTheme grenzeGotischTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.grenzeGotisch(textStyle: textTheme.headline1), + headline2: GoogleFonts.grenzeGotisch(textStyle: textTheme.headline2), + headline3: GoogleFonts.grenzeGotisch(textStyle: textTheme.headline3), + headline4: GoogleFonts.grenzeGotisch(textStyle: textTheme.headline4), + headline5: GoogleFonts.grenzeGotisch(textStyle: textTheme.headline5), + headline6: GoogleFonts.grenzeGotisch(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.grenzeGotisch(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.grenzeGotisch(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.grenzeGotisch(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.grenzeGotisch(textStyle: textTheme.bodyText2), + caption: GoogleFonts.grenzeGotisch(textStyle: textTheme.caption), + button: GoogleFonts.grenzeGotisch(textStyle: textTheme.button), + overline: GoogleFonts.grenzeGotisch(textStyle: textTheme.overline), + ); + } + + /// Applies the Griffy font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Griffy + static TextStyle griffy({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9f37c4a3b39667330abe546b4133f6acfb3799da67a89997fb46b39dbc3fc6d8', + 208332, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Griffy', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Griffy font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Griffy + static TextTheme griffyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.griffy(textStyle: textTheme.headline1), + headline2: GoogleFonts.griffy(textStyle: textTheme.headline2), + headline3: GoogleFonts.griffy(textStyle: textTheme.headline3), + headline4: GoogleFonts.griffy(textStyle: textTheme.headline4), + headline5: GoogleFonts.griffy(textStyle: textTheme.headline5), + headline6: GoogleFonts.griffy(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.griffy(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.griffy(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.griffy(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.griffy(textStyle: textTheme.bodyText2), + caption: GoogleFonts.griffy(textStyle: textTheme.caption), + button: GoogleFonts.griffy(textStyle: textTheme.button), + overline: GoogleFonts.griffy(textStyle: textTheme.overline), + ); + } + + /// Applies the Gruppo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gruppo + static TextStyle gruppo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6cf289ec6fe4592706aa68de1f9711e3f1967db26053962cfbddd4e51a7ac65e', + 58988, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gruppo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gruppo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gruppo + static TextTheme gruppoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gruppo(textStyle: textTheme.headline1), + headline2: GoogleFonts.gruppo(textStyle: textTheme.headline2), + headline3: GoogleFonts.gruppo(textStyle: textTheme.headline3), + headline4: GoogleFonts.gruppo(textStyle: textTheme.headline4), + headline5: GoogleFonts.gruppo(textStyle: textTheme.headline5), + headline6: GoogleFonts.gruppo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gruppo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gruppo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gruppo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gruppo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gruppo(textStyle: textTheme.caption), + button: GoogleFonts.gruppo(textStyle: textTheme.button), + overline: GoogleFonts.gruppo(textStyle: textTheme.overline), + ); + } + + /// Applies the Gudea font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gudea + static TextStyle gudea({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4b41bce93d5a05ba71bb86e2be22eb03b270fa198be7df07c9c5a818a1724c0f', + 22884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ab00b4c571bb901b0d274550fab83154da5b8bb4529e382ae7d58962b0d05f80', + 26980, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b1c48f399971799fe09414206e205ea8a5f37a1e17adc5ed4329ee9ddb9d074e', + 22512, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gudea', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gudea font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gudea + static TextTheme gudeaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gudea(textStyle: textTheme.headline1), + headline2: GoogleFonts.gudea(textStyle: textTheme.headline2), + headline3: GoogleFonts.gudea(textStyle: textTheme.headline3), + headline4: GoogleFonts.gudea(textStyle: textTheme.headline4), + headline5: GoogleFonts.gudea(textStyle: textTheme.headline5), + headline6: GoogleFonts.gudea(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gudea(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gudea(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gudea(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gudea(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gudea(textStyle: textTheme.caption), + button: GoogleFonts.gudea(textStyle: textTheme.button), + overline: GoogleFonts.gudea(textStyle: textTheme.overline), + ); + } + + /// Applies the Gugi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gugi + static TextStyle gugi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4fbf616bf21ec330d026a7115b7224fe9baf30418cdbb19b26eed6ebcd6ce2cc', + 552880, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gugi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gugi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gugi + static TextTheme gugiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gugi(textStyle: textTheme.headline1), + headline2: GoogleFonts.gugi(textStyle: textTheme.headline2), + headline3: GoogleFonts.gugi(textStyle: textTheme.headline3), + headline4: GoogleFonts.gugi(textStyle: textTheme.headline4), + headline5: GoogleFonts.gugi(textStyle: textTheme.headline5), + headline6: GoogleFonts.gugi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gugi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gugi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gugi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gugi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gugi(textStyle: textTheme.caption), + button: GoogleFonts.gugi(textStyle: textTheme.button), + overline: GoogleFonts.gugi(textStyle: textTheme.overline), + ); + } + + /// Applies the Gupter font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gupter + static TextStyle gupter({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '98ef59cfa0eb83781f6573b4ad1964bf98369e70db38156479c353702557fa01', + 33868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '84381b04d635b2daeb369d9c0afa5ff2489d0cda8d9660ee7631bfdf82f2eaeb', + 33688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0e63fe340f8e61f9d4d9c5bbc638e79930af1125c534f656814a99d3909674b0', + 33692, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gupter', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gupter font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gupter + static TextTheme gupterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gupter(textStyle: textTheme.headline1), + headline2: GoogleFonts.gupter(textStyle: textTheme.headline2), + headline3: GoogleFonts.gupter(textStyle: textTheme.headline3), + headline4: GoogleFonts.gupter(textStyle: textTheme.headline4), + headline5: GoogleFonts.gupter(textStyle: textTheme.headline5), + headline6: GoogleFonts.gupter(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gupter(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gupter(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gupter(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gupter(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gupter(textStyle: textTheme.caption), + button: GoogleFonts.gupter(textStyle: textTheme.button), + overline: GoogleFonts.gupter(textStyle: textTheme.overline), + ); + } + + /// Applies the Gurajada font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gurajada + static TextStyle gurajada({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9647a956c03e34f58b38200ffb45cc56377e8ba1c333ce052b8e20c3216198c3', + 234900, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Gurajada', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Gurajada font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Gurajada + static TextTheme gurajadaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.gurajada(textStyle: textTheme.headline1), + headline2: GoogleFonts.gurajada(textStyle: textTheme.headline2), + headline3: GoogleFonts.gurajada(textStyle: textTheme.headline3), + headline4: GoogleFonts.gurajada(textStyle: textTheme.headline4), + headline5: GoogleFonts.gurajada(textStyle: textTheme.headline5), + headline6: GoogleFonts.gurajada(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.gurajada(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.gurajada(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.gurajada(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.gurajada(textStyle: textTheme.bodyText2), + caption: GoogleFonts.gurajada(textStyle: textTheme.caption), + button: GoogleFonts.gurajada(textStyle: textTheme.button), + overline: GoogleFonts.gurajada(textStyle: textTheme.overline), + ); + } + + /// Applies the Habibi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Habibi + static TextStyle habibi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9177d379d59937eb418704aa1a5f16ff6bfa046d3828ba6f495ffe7c2d040c5c', + 36236, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Habibi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Habibi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Habibi + static TextTheme habibiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.habibi(textStyle: textTheme.headline1), + headline2: GoogleFonts.habibi(textStyle: textTheme.headline2), + headline3: GoogleFonts.habibi(textStyle: textTheme.headline3), + headline4: GoogleFonts.habibi(textStyle: textTheme.headline4), + headline5: GoogleFonts.habibi(textStyle: textTheme.headline5), + headline6: GoogleFonts.habibi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.habibi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.habibi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.habibi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.habibi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.habibi(textStyle: textTheme.caption), + button: GoogleFonts.habibi(textStyle: textTheme.button), + overline: GoogleFonts.habibi(textStyle: textTheme.overline), + ); + } + + /// Applies the Hachi Maru Pop font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hachi+Maru+Pop + static TextStyle hachiMaruPop({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'decd9292c362ead9975bf878b925165ad643d3cb7e6b671962f6dfe790a07acb', + 4374692, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HachiMaruPop', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hachi Maru Pop font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hachi+Maru+Pop + static TextTheme hachiMaruPopTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hachiMaruPop(textStyle: textTheme.headline1), + headline2: GoogleFonts.hachiMaruPop(textStyle: textTheme.headline2), + headline3: GoogleFonts.hachiMaruPop(textStyle: textTheme.headline3), + headline4: GoogleFonts.hachiMaruPop(textStyle: textTheme.headline4), + headline5: GoogleFonts.hachiMaruPop(textStyle: textTheme.headline5), + headline6: GoogleFonts.hachiMaruPop(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hachiMaruPop(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hachiMaruPop(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hachiMaruPop(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hachiMaruPop(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hachiMaruPop(textStyle: textTheme.caption), + button: GoogleFonts.hachiMaruPop(textStyle: textTheme.button), + overline: GoogleFonts.hachiMaruPop(textStyle: textTheme.overline), + ); + } + + /// Applies the Halant font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Halant + static TextStyle halant({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'efbf1567d1ee285b609cc33198f6bf85b75ffc137871c0c74b770bda82fe5f96', + 163344, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd2becc2fc9d31bd06f7378b501b26b4eb057167cc3722297588a277f45b05fba', + 163064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e6e6c9b73832eb91900f4298ec5c6b73e8d537163220299fa6213b8d702b9f37', + 161020, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c38923af0ef17edd914dfb2737891b725cd1cc9dfc36bd72ba413213e99839a3', + 159016, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d09a5ce42fc23e8619b6c817a9bc5522bc64ede74b5a75d99fe2815244ca6a8', + 157804, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Halant', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Halant font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Halant + static TextTheme halantTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.halant(textStyle: textTheme.headline1), + headline2: GoogleFonts.halant(textStyle: textTheme.headline2), + headline3: GoogleFonts.halant(textStyle: textTheme.headline3), + headline4: GoogleFonts.halant(textStyle: textTheme.headline4), + headline5: GoogleFonts.halant(textStyle: textTheme.headline5), + headline6: GoogleFonts.halant(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.halant(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.halant(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.halant(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.halant(textStyle: textTheme.bodyText2), + caption: GoogleFonts.halant(textStyle: textTheme.caption), + button: GoogleFonts.halant(textStyle: textTheme.button), + overline: GoogleFonts.halant(textStyle: textTheme.overline), + ); + } + + /// Applies the Hammersmith One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hammersmith+One + static TextStyle hammersmithOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bbd2dab2dede4753a7b96c8c6c16d212a15b9feda00f0620edbe4cb62e1604fe', + 57584, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HammersmithOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hammersmith One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hammersmith+One + static TextTheme hammersmithOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hammersmithOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.hammersmithOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.hammersmithOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.hammersmithOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.hammersmithOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.hammersmithOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hammersmithOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hammersmithOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hammersmithOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hammersmithOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hammersmithOne(textStyle: textTheme.caption), + button: GoogleFonts.hammersmithOne(textStyle: textTheme.button), + overline: GoogleFonts.hammersmithOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Hanalei font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hanalei + static TextStyle hanalei({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a5f5db562e15a26c9d07e75a9375af4b46c68460a9dbaaf21847567dafcf8619', + 183760, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Hanalei', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hanalei font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hanalei + static TextTheme hanaleiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hanalei(textStyle: textTheme.headline1), + headline2: GoogleFonts.hanalei(textStyle: textTheme.headline2), + headline3: GoogleFonts.hanalei(textStyle: textTheme.headline3), + headline4: GoogleFonts.hanalei(textStyle: textTheme.headline4), + headline5: GoogleFonts.hanalei(textStyle: textTheme.headline5), + headline6: GoogleFonts.hanalei(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hanalei(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hanalei(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hanalei(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hanalei(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hanalei(textStyle: textTheme.caption), + button: GoogleFonts.hanalei(textStyle: textTheme.button), + overline: GoogleFonts.hanalei(textStyle: textTheme.overline), + ); + } + + /// Applies the Hanalei Fill font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hanalei+Fill + static TextStyle hanaleiFill({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8a762eb869da8deb93071d72d31cc3f5d6ab83cbeff8da397a582e507aa65465', + 91692, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HanaleiFill', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hanalei Fill font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hanalei+Fill + static TextTheme hanaleiFillTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hanaleiFill(textStyle: textTheme.headline1), + headline2: GoogleFonts.hanaleiFill(textStyle: textTheme.headline2), + headline3: GoogleFonts.hanaleiFill(textStyle: textTheme.headline3), + headline4: GoogleFonts.hanaleiFill(textStyle: textTheme.headline4), + headline5: GoogleFonts.hanaleiFill(textStyle: textTheme.headline5), + headline6: GoogleFonts.hanaleiFill(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hanaleiFill(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hanaleiFill(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hanaleiFill(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hanaleiFill(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hanaleiFill(textStyle: textTheme.caption), + button: GoogleFonts.hanaleiFill(textStyle: textTheme.button), + overline: GoogleFonts.hanaleiFill(textStyle: textTheme.overline), + ); + } + + /// Applies the Handlee font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Handlee + static TextStyle handlee({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '10f3e83c9fcbcd234b04cde9d1f8001a0255ea2bf3be48eb39ba87a44ff27fac', + 39084, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Handlee', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Handlee font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Handlee + static TextTheme handleeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.handlee(textStyle: textTheme.headline1), + headline2: GoogleFonts.handlee(textStyle: textTheme.headline2), + headline3: GoogleFonts.handlee(textStyle: textTheme.headline3), + headline4: GoogleFonts.handlee(textStyle: textTheme.headline4), + headline5: GoogleFonts.handlee(textStyle: textTheme.headline5), + headline6: GoogleFonts.handlee(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.handlee(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.handlee(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.handlee(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.handlee(textStyle: textTheme.bodyText2), + caption: GoogleFonts.handlee(textStyle: textTheme.caption), + button: GoogleFonts.handlee(textStyle: textTheme.button), + overline: GoogleFonts.handlee(textStyle: textTheme.overline), + ); + } + + /// Applies the Happy Monkey font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Happy+Monkey + static TextStyle happyMonkey({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'edf47e48fdc5ee842cf7de5d9333a50f1455140283974d5f0585583198b0b994', + 55964, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HappyMonkey', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Happy Monkey font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Happy+Monkey + static TextTheme happyMonkeyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.happyMonkey(textStyle: textTheme.headline1), + headline2: GoogleFonts.happyMonkey(textStyle: textTheme.headline2), + headline3: GoogleFonts.happyMonkey(textStyle: textTheme.headline3), + headline4: GoogleFonts.happyMonkey(textStyle: textTheme.headline4), + headline5: GoogleFonts.happyMonkey(textStyle: textTheme.headline5), + headline6: GoogleFonts.happyMonkey(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.happyMonkey(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.happyMonkey(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.happyMonkey(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.happyMonkey(textStyle: textTheme.bodyText2), + caption: GoogleFonts.happyMonkey(textStyle: textTheme.caption), + button: GoogleFonts.happyMonkey(textStyle: textTheme.button), + overline: GoogleFonts.happyMonkey(textStyle: textTheme.overline), + ); + } + + /// Applies the Harmattan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Harmattan + static TextStyle harmattan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '41320202de91ac539042bef1e0b4e68bb221cb422a2afcfd15a946a73ac99f64', + 528540, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Harmattan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Harmattan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Harmattan + static TextTheme harmattanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.harmattan(textStyle: textTheme.headline1), + headline2: GoogleFonts.harmattan(textStyle: textTheme.headline2), + headline3: GoogleFonts.harmattan(textStyle: textTheme.headline3), + headline4: GoogleFonts.harmattan(textStyle: textTheme.headline4), + headline5: GoogleFonts.harmattan(textStyle: textTheme.headline5), + headline6: GoogleFonts.harmattan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.harmattan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.harmattan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.harmattan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.harmattan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.harmattan(textStyle: textTheme.caption), + button: GoogleFonts.harmattan(textStyle: textTheme.button), + overline: GoogleFonts.harmattan(textStyle: textTheme.overline), + ); + } + + /// Applies the Headland One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Headland+One + static TextStyle headlandOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '09bc81418bd95b221c7661eb2081838c8bd80b6bcd38c45d2e560ff3983c9fde', + 75448, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HeadlandOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Headland One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Headland+One + static TextTheme headlandOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.headlandOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.headlandOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.headlandOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.headlandOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.headlandOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.headlandOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.headlandOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.headlandOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.headlandOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.headlandOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.headlandOne(textStyle: textTheme.caption), + button: GoogleFonts.headlandOne(textStyle: textTheme.button), + overline: GoogleFonts.headlandOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Heebo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Heebo + static TextStyle heebo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2f2d859884539805a307db5a1953174f56bbb1e6903e915be95fe2a03d9ccacf', + 45672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eca72d49e0e063205daeaedb86fcdfc0cc36c5aaeb2d564ace316302e6ae62d9', + 45524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'afb3fdd559b309c81c88a054148d94587299a397f1e8a3798cfb7cc2d485369c', + 44868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6655017f4c44bf09c5f66243feddb0c2cc8654284f24057da878243794d13286', + 44708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '61bb78902136df2bcd0ef85590cbe95a59a3d85b975e0778906df1211029bd34', + 44840, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c1324f3250d2f9405f19d63450423cd5a8a8cf6c6b7129e3afda9592f69c2df4', + 44964, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '500b1881e185310128c33157aa1484b2a52573bfe32f11d60065e0deffe8471c', + 45328, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Heebo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Heebo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Heebo + static TextTheme heeboTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.heebo(textStyle: textTheme.headline1), + headline2: GoogleFonts.heebo(textStyle: textTheme.headline2), + headline3: GoogleFonts.heebo(textStyle: textTheme.headline3), + headline4: GoogleFonts.heebo(textStyle: textTheme.headline4), + headline5: GoogleFonts.heebo(textStyle: textTheme.headline5), + headline6: GoogleFonts.heebo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.heebo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.heebo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.heebo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.heebo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.heebo(textStyle: textTheme.caption), + button: GoogleFonts.heebo(textStyle: textTheme.button), + overline: GoogleFonts.heebo(textStyle: textTheme.overline), + ); + } + + /// Applies the Henny Penny font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Henny+Penny + static TextStyle hennyPenny({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f0a1cf7a7ff413b8e4b7efebd74b65892f11e78dc663ec993b133ccfd9177864', + 78004, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HennyPenny', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Henny Penny font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Henny+Penny + static TextTheme hennyPennyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hennyPenny(textStyle: textTheme.headline1), + headline2: GoogleFonts.hennyPenny(textStyle: textTheme.headline2), + headline3: GoogleFonts.hennyPenny(textStyle: textTheme.headline3), + headline4: GoogleFonts.hennyPenny(textStyle: textTheme.headline4), + headline5: GoogleFonts.hennyPenny(textStyle: textTheme.headline5), + headline6: GoogleFonts.hennyPenny(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hennyPenny(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hennyPenny(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hennyPenny(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hennyPenny(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hennyPenny(textStyle: textTheme.caption), + button: GoogleFonts.hennyPenny(textStyle: textTheme.button), + overline: GoogleFonts.hennyPenny(textStyle: textTheme.overline), + ); + } + + /// Applies the Hepta Slab font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hepta+Slab + static TextStyle heptaSlab({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '534d777769f5477f07228b5576ec1d9e5f8524ebb5568ee0c7ead05433221d78', + 96352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'de95a9d08b1575d9f362c8b8fdd65bd2909ac29ad85189cbcc2d2bb7b79bae55', + 96348, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4cd4b89cf596ab747187626051fcb2da9f1ee5facedc163666b009c58d2e6a4a', + 96164, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fd8aa078be565bf9944c3c9a7158b16836fdcd409b6df1377b7ce805078acf7f', + 95980, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7d62a8746b071e53a6b32f2f3a0052555f9d40c47fecd5bd70697f632af7b585', + 95988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5b2cd08d92feb50e4548237182dede8320631fffad112e55ac8ffec9bd254dbc', + 96144, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c732dc9ed4d5762dd9391ce2ed11a31606c9ec3305bef745bce6d06bdb2403df', + 96504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd4ba935b82b68baaeb5bc719f5132fb28f94a27979e65e4ad25c5ff85d02303f', + 96856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bf562116fb32949fa7d908466470e1c6d03ae7bb83023d1428527ecec91d9201', + 96924, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HeptaSlab', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hepta Slab font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hepta+Slab + static TextTheme heptaSlabTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.heptaSlab(textStyle: textTheme.headline1), + headline2: GoogleFonts.heptaSlab(textStyle: textTheme.headline2), + headline3: GoogleFonts.heptaSlab(textStyle: textTheme.headline3), + headline4: GoogleFonts.heptaSlab(textStyle: textTheme.headline4), + headline5: GoogleFonts.heptaSlab(textStyle: textTheme.headline5), + headline6: GoogleFonts.heptaSlab(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.heptaSlab(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.heptaSlab(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.heptaSlab(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.heptaSlab(textStyle: textTheme.bodyText2), + caption: GoogleFonts.heptaSlab(textStyle: textTheme.caption), + button: GoogleFonts.heptaSlab(textStyle: textTheme.button), + overline: GoogleFonts.heptaSlab(textStyle: textTheme.overline), + ); + } + + /// Applies the Herr Von Muellerhoff font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Herr+Von+Muellerhoff + static TextStyle herrVonMuellerhoff({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8c993280c6ba0eaa30f678b4c9821389abad4632e23c3a1629655afe7f463395', + 46576, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HerrVonMuellerhoff', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Herr Von Muellerhoff font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Herr+Von+Muellerhoff + static TextTheme herrVonMuellerhoffTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.headline1), + headline2: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.headline2), + headline3: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.headline3), + headline4: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.headline4), + headline5: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.headline5), + headline6: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.bodyText2), + caption: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.caption), + button: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.button), + overline: GoogleFonts.herrVonMuellerhoff(textStyle: textTheme.overline), + ); + } + + /// Applies the Hi Melody font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hi+Melody + static TextStyle hiMelody({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '306d4c79415f43cc2f655c997e9edc971ad12227c39d46aef4fae766ba572d12', + 6090832, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HiMelody', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hi Melody font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hi+Melody + static TextTheme hiMelodyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hiMelody(textStyle: textTheme.headline1), + headline2: GoogleFonts.hiMelody(textStyle: textTheme.headline2), + headline3: GoogleFonts.hiMelody(textStyle: textTheme.headline3), + headline4: GoogleFonts.hiMelody(textStyle: textTheme.headline4), + headline5: GoogleFonts.hiMelody(textStyle: textTheme.headline5), + headline6: GoogleFonts.hiMelody(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hiMelody(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hiMelody(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hiMelody(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hiMelody(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hiMelody(textStyle: textTheme.caption), + button: GoogleFonts.hiMelody(textStyle: textTheme.button), + overline: GoogleFonts.hiMelody(textStyle: textTheme.overline), + ); + } + + /// Applies the Hind font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind + static TextStyle hind({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fa60918477db30de0e2a697db644a3ada9014744668b10708e487b2731a95e70', + 152472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c6c2ab346a94eb5613fbc0721b8b1b9062968050182abaa239ca636a32911d90', + 152124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd4fd25d01c80707a336cb4b040f3a52767f1cd612f042572d044e0b575c4d05b', + 151708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '98d33c7c6f79077dfb001ecff6aa383168fca5cebe664a277c74acff145e6685', + 151452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2e7dd62cde147432a10070b99d17f623f3c13f9c8796be3afa987f6e0707f030', + 149692, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Hind', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hind font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind + static TextTheme hindTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hind(textStyle: textTheme.headline1), + headline2: GoogleFonts.hind(textStyle: textTheme.headline2), + headline3: GoogleFonts.hind(textStyle: textTheme.headline3), + headline4: GoogleFonts.hind(textStyle: textTheme.headline4), + headline5: GoogleFonts.hind(textStyle: textTheme.headline5), + headline6: GoogleFonts.hind(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hind(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hind(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hind(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hind(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hind(textStyle: textTheme.caption), + button: GoogleFonts.hind(textStyle: textTheme.button), + overline: GoogleFonts.hind(textStyle: textTheme.overline), + ); + } + + /// Applies the Hind Guntur font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind+Guntur + static TextStyle hindGuntur({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '83f2591cf78a025ae8e85ebecda4a590c393eb80bf83f18bace7e5d144b57bc8', + 173452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '58962c61fd64e7df2aa4d0fbf8b7044df4531b4098533fd14348043d05fb8b42', + 172528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1548c29a01fac4cf5904cd44cf584eaec84e08ed0b15f96638c1cb9ff8995583', + 171468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '12aa908469a5d74ca315816664934ede78906a4593e2310e5ea1894cd964c2a1', + 170280, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '751c8dd12898b1caafe20c6458531dce8773242b36537ea2e341d9a4bd01bafe', + 169956, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HindGuntur', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hind Guntur font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind+Guntur + static TextTheme hindGunturTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hindGuntur(textStyle: textTheme.headline1), + headline2: GoogleFonts.hindGuntur(textStyle: textTheme.headline2), + headline3: GoogleFonts.hindGuntur(textStyle: textTheme.headline3), + headline4: GoogleFonts.hindGuntur(textStyle: textTheme.headline4), + headline5: GoogleFonts.hindGuntur(textStyle: textTheme.headline5), + headline6: GoogleFonts.hindGuntur(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hindGuntur(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hindGuntur(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hindGuntur(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hindGuntur(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hindGuntur(textStyle: textTheme.caption), + button: GoogleFonts.hindGuntur(textStyle: textTheme.button), + overline: GoogleFonts.hindGuntur(textStyle: textTheme.overline), + ); + } + + /// Applies the Hind Madurai font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind+Madurai + static TextStyle hindMadurai({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5d2a60f4ad6943bf7f1de4b16722cf8992b893d91bdb242860538507d4514dfa', + 71760, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fe0b759733d5d95da02f65af60da858c2e45e9fc35332036694fef1e4f2369aa', + 71136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '367a1897906f0dafe97990639330a1ad8058b45f8d8deae93db5e40a9ae90f44', + 71428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '559d4bdf4c6fc62a412864ae9323ea997294ef17fda3b84684d928c0e042c1a0', + 71476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '59964f77b9fded7f3b4030894b5bde3bf552e70132670a0108ec2218ae31fb9b', + 70344, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HindMadurai', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hind Madurai font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind+Madurai + static TextTheme hindMaduraiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hindMadurai(textStyle: textTheme.headline1), + headline2: GoogleFonts.hindMadurai(textStyle: textTheme.headline2), + headline3: GoogleFonts.hindMadurai(textStyle: textTheme.headline3), + headline4: GoogleFonts.hindMadurai(textStyle: textTheme.headline4), + headline5: GoogleFonts.hindMadurai(textStyle: textTheme.headline5), + headline6: GoogleFonts.hindMadurai(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hindMadurai(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hindMadurai(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hindMadurai(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hindMadurai(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hindMadurai(textStyle: textTheme.caption), + button: GoogleFonts.hindMadurai(textStyle: textTheme.button), + overline: GoogleFonts.hindMadurai(textStyle: textTheme.overline), + ); + } + + /// Applies the Hind Siliguri font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind+Siliguri + static TextStyle hindSiliguri({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ac4fb0e6616374786c8c79c069fb7ec555580917d9534053bbc5cfca7cc35a6b', + 135788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4f3c785b698527e53bc193bce4c13e1eedc1eadefe7c65720c5eb0ddafcc78c4', + 135144, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f112da1e6bbd4b1fbf998db772359e0812e0bf2acc7c60e21a0e99c24ec1e48f', + 134792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c80fdec935e6023f68b5a13e7bde8edff218450fe58f3ca7c3fe6e454b4cdd54', + 134828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3b363f06eb2b3264843731ba51fa467aba8cf06454281e9ceab83a3bc8c802ce', + 133192, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HindSiliguri', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hind Siliguri font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind+Siliguri + static TextTheme hindSiliguriTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hindSiliguri(textStyle: textTheme.headline1), + headline2: GoogleFonts.hindSiliguri(textStyle: textTheme.headline2), + headline3: GoogleFonts.hindSiliguri(textStyle: textTheme.headline3), + headline4: GoogleFonts.hindSiliguri(textStyle: textTheme.headline4), + headline5: GoogleFonts.hindSiliguri(textStyle: textTheme.headline5), + headline6: GoogleFonts.hindSiliguri(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hindSiliguri(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hindSiliguri(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hindSiliguri(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hindSiliguri(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hindSiliguri(textStyle: textTheme.caption), + button: GoogleFonts.hindSiliguri(textStyle: textTheme.button), + overline: GoogleFonts.hindSiliguri(textStyle: textTheme.overline), + ); + } + + /// Applies the Hind Vadodara font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind+Vadodara + static TextStyle hindVadodara({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '28ad92a17d66f3a0995bb68875c29dba3cdaf9fb43feb40a882e2eb2638b7d0e', + 132940, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ceba975d8428bc0815764806b013c8ab2629dd726f64eedc432d9089567ba31', + 132588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '99808cdfa62f14d0fb695cf7a37fd7987ec1f14b71dfd11d87f428432e5641c7', + 132420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '931dba7983e3c75f3bcfc57cbb486114347aa39bd48e261bf327bfc5d2b2f7cd', + 131916, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e717f555c38c3a3665cdb7fc053e8b12904225205d5eab82b472417208c7c483', + 130448, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HindVadodara', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Hind Vadodara font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Hind+Vadodara + static TextTheme hindVadodaraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.hindVadodara(textStyle: textTheme.headline1), + headline2: GoogleFonts.hindVadodara(textStyle: textTheme.headline2), + headline3: GoogleFonts.hindVadodara(textStyle: textTheme.headline3), + headline4: GoogleFonts.hindVadodara(textStyle: textTheme.headline4), + headline5: GoogleFonts.hindVadodara(textStyle: textTheme.headline5), + headline6: GoogleFonts.hindVadodara(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.hindVadodara(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.hindVadodara(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.hindVadodara(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.hindVadodara(textStyle: textTheme.bodyText2), + caption: GoogleFonts.hindVadodara(textStyle: textTheme.caption), + button: GoogleFonts.hindVadodara(textStyle: textTheme.button), + overline: GoogleFonts.hindVadodara(textStyle: textTheme.overline), + ); + } + + /// Applies the Holtwood One SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Holtwood+One+SC + static TextStyle holtwoodOneSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e13ec5f1ab20c1d4d3cd916510331011904e2d9a5083dff4b0bdfa42c86a4eac', + 36652, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HoltwoodOneSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Holtwood One SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Holtwood+One+SC + static TextTheme holtwoodOneScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.holtwoodOneSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.holtwoodOneSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.holtwoodOneSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.holtwoodOneSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.holtwoodOneSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.holtwoodOneSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.holtwoodOneSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.holtwoodOneSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.holtwoodOneSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.holtwoodOneSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.holtwoodOneSc(textStyle: textTheme.caption), + button: GoogleFonts.holtwoodOneSc(textStyle: textTheme.button), + overline: GoogleFonts.holtwoodOneSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Homemade Apple font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Homemade+Apple + static TextStyle homemadeApple({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '492f1c4f1d496ff595958cd8454693eccded599173fc699c93cb2df8a2561201', + 109592, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'HomemadeApple', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Homemade Apple font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Homemade+Apple + static TextTheme homemadeAppleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.homemadeApple(textStyle: textTheme.headline1), + headline2: GoogleFonts.homemadeApple(textStyle: textTheme.headline2), + headline3: GoogleFonts.homemadeApple(textStyle: textTheme.headline3), + headline4: GoogleFonts.homemadeApple(textStyle: textTheme.headline4), + headline5: GoogleFonts.homemadeApple(textStyle: textTheme.headline5), + headline6: GoogleFonts.homemadeApple(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.homemadeApple(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.homemadeApple(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.homemadeApple(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.homemadeApple(textStyle: textTheme.bodyText2), + caption: GoogleFonts.homemadeApple(textStyle: textTheme.caption), + button: GoogleFonts.homemadeApple(textStyle: textTheme.button), + overline: GoogleFonts.homemadeApple(textStyle: textTheme.overline), + ); + } + + /// Applies the Homenaje font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Homenaje + static TextStyle homenaje({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'efaa8006929ef2ce2bc82593647ea2be59dcb513e048e4cb4b105cc66119d343', + 21568, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Homenaje', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Homenaje font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Homenaje + static TextTheme homenajeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.homenaje(textStyle: textTheme.headline1), + headline2: GoogleFonts.homenaje(textStyle: textTheme.headline2), + headline3: GoogleFonts.homenaje(textStyle: textTheme.headline3), + headline4: GoogleFonts.homenaje(textStyle: textTheme.headline4), + headline5: GoogleFonts.homenaje(textStyle: textTheme.headline5), + headline6: GoogleFonts.homenaje(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.homenaje(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.homenaje(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.homenaje(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.homenaje(textStyle: textTheme.bodyText2), + caption: GoogleFonts.homenaje(textStyle: textTheme.caption), + button: GoogleFonts.homenaje(textStyle: textTheme.button), + overline: GoogleFonts.homenaje(textStyle: textTheme.overline), + ); + } + + /// Applies the IBM Plex Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IBM+Plex+Mono + static TextStyle ibmPlexMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0b176030119e3bf8008cc3a1ab395de2490609893cbf42c9ad93a1b97131c1ad', + 62804, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '49cc21b7b1c2e02aec83be236218fc1bf64c43ab6693d02e5f57dc5c4d580a42', + 69308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '84f407c2acc498e7797432543eba48500150e851182f2706d2a48e4fc61aef13', + 62428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '973e67e339972330580f84b47bc69af70b6ffb871605061a2c44830772432449', + 69268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7860eafcb749cd16c35f7d63a81d0d83919b82475eeb29338cd5eea961a4bbfd', + 62176, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ad14a6133399a3b691d1311e56718da47fe30d69f6f48d68f43c25f62084f4d0', + 68876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4e5360e6435ca0fda23ac8bde947e30a690395bedc6a0e0f9b360aceeb490851', + 62712, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8b7513201954154b316d56ba7185e0f58200a044e0150145e17d797a98dcbb52', + 69680, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8bea2481c75885bfb6d132add1b2ac6d4ccdbedfa94dda1d4dc34e7d00ca8ffd', + 62328, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eb363301d9364248dd094562021ed86fc2b1b9e2351f313c635e72b14d98179f', + 68924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b6f0266c5d40d72cd5d4051aaa3dc1836d7874fc40471cae205892e07fdd87ad', + 62288, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '48174c08a0c28ee87d255c8380c23b2beca649d5ed46c8287c5062304417209b', + 68600, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '089c2f087950891775cef79553f8c15f825bea671e0a1323f495354feb06d3b3', + 62324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3fdca15f4f471d5ef3f57c790ad9b09474ab6d24e75f300f10c9eb8219ddad39', + 68980, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IBMPlexMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IBM Plex Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IBM+Plex+Mono + static TextTheme ibmPlexMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ibmPlexMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.ibmPlexMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.ibmPlexMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.ibmPlexMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.ibmPlexMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.ibmPlexMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ibmPlexMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ibmPlexMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ibmPlexMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ibmPlexMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ibmPlexMono(textStyle: textTheme.caption), + button: GoogleFonts.ibmPlexMono(textStyle: textTheme.button), + overline: GoogleFonts.ibmPlexMono(textStyle: textTheme.overline), + ); + } + + /// Applies the IBM Plex Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IBM+Plex+Sans + static TextStyle ibmPlexSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '813b794a62b57fce9544b834ad183c1e5175f1825c2fa2067d3480518d81f446', + 97392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '550fbb9acc0447f5ddf482b1659912f8f4076179a59e288fd71dc1e7d86885c9', + 105688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f6209628705dc0331422f8e21345a1e1387a26fd07293496dbcc6a3551859177', + 99360, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '224494b659d44d626398ec8760d4b0e4ea459e0be556f8219de0ddf0f170cebb', + 107380, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '86b8f04cfeba166a0a6eed0b57970518f638c9745fea6212e6805b004579da75', + 99180, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '60e2fc65f3e87d1813c4a598c88cc21e21334a5b6b8e1d821dbb7b17edabbf21', + 107012, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8cd70b2671db7396694b0e2a1a3a9859018db199711237cdf67322e3d9060bbf', + 98888, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd7e4bb3b1d26be9695d85cfc1cdaef4376e22aca80f216e22c43c28ce7969ae0', + 106248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c8d348ccb6205cc4dd9833d972d8decd8b526df3d482aedc4aa47ae9f7bd46f1', + 99256, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c576912fcd0266aba72ffcf4b1b7d770bdf1353f90c2a0bdc8686e8dd740eac6', + 106664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '26aefb8b77b2efc1dd517b6c5baaca61435844c281e5a51125bd65213f2cc5e0', + 99140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1aeff1379a138b4aa07f5fd0066ca778f321b9a1c8f1b234d858812b684ebb66', + 106720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '13670a62ca981b5bc10df4425d93c3c41647b8934455c891e16f9384881606ef', + 98260, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '64d98b387f5233a7cbc684f09cd4b5c622058a02d63fe1af27e247ee88e4573e', + 105704, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IBMPlexSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IBM Plex Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IBM+Plex+Sans + static TextTheme ibmPlexSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ibmPlexSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.ibmPlexSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.ibmPlexSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.ibmPlexSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.ibmPlexSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.ibmPlexSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ibmPlexSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ibmPlexSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ibmPlexSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ibmPlexSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ibmPlexSans(textStyle: textTheme.caption), + button: GoogleFonts.ibmPlexSans(textStyle: textTheme.button), + overline: GoogleFonts.ibmPlexSans(textStyle: textTheme.overline), + ); + } + + /// Applies the IBM Plex Sans Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IBM+Plex+Sans+Condensed + static TextStyle ibmPlexSansCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '95cb5ef68ced474a2288be174bf62af93746ddbce9a8be785d59e05d46221cb9', + 64480, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ea2881ac7cbb7d0a0d0d89b3c81e0ccbd79e1dd040b84f4b28c7ea083a958926', + 68820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a51cec8648be38680ff0325b258659173e8d6cf8bf91ce3af4dfe72d96ad57bd', + 64844, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '459eb773994095169ba8f6f04dfad1a45c205782fd393d467e9c8d3a21701fa2', + 69132, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c8260d42c2195a564a8bc5b74144874ac850ad48b4c507271d5fe4151f4802b6', + 64424, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2b1c9ad90a1fb240d2e8ebb5f3a3d4a544c37662964daf7dc0941d047876b826', + 68452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6f14a51d14c32df9b6829dbd95e680ca603bb1f0e0c8a23f3d18f6e96f970eef', + 64056, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a2c2c799b5a7b8b957579016dedfd8bd110c064310c1a491a71ee84964ff0a56', + 68720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '17c6dabfa0ed7d9b258acae9bd3a20e61dbd27fa029bd3df75a0deadaa90e24e', + 63756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b605737f157c6f7c5977d9a151ff622fa93439d4b364d24f6431f52eb6a5affd', + 67728, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '368b327e4f44c9bf4ba628ecb081c53e0e3f087a4c0822435fe6ad6527dbe958', + 63804, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a4fd2820e497b76a6c413f52ce87fa7521d6ff5bd0fac82b9c53e48c5febf174', + 67920, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '58ace9c95662b3ff47b0a066336d863bcc0515df78f5a23e9e424c1fbd4f451a', + 63812, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '064ee4d57bfdc62832b848b5c300e9abaadd59d151ca0279ad569edceffcf029', + 68712, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IBMPlexSansCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IBM Plex Sans Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IBM+Plex+Sans+Condensed + static TextTheme ibmPlexSansCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.headline1), + headline2: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.headline2), + headline3: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.headline3), + headline4: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.headline4), + headline5: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.headline5), + headline6: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.caption), + button: GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.button), + overline: GoogleFonts.ibmPlexSansCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the IBM Plex Serif font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IBM+Plex+Serif + static TextStyle ibmPlexSerif({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7d42efee4f1a7ac97d078340d6652728fe15929c68ba6d23cb2bb12c08ade3c', + 104216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2d6348f0337897dfd4f35a24aeb41df7d2026b073c6e62091ba3d4be45deccef', + 114056, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '22d162d23ce0e5ad78699d3f15d64aee792adff19238b2d5fff9ed6e4e2aeaa6', + 106996, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eca320d0ebf030d252c42622bd633b638607e007a1106887d72c483f4ab3703b', + 117848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5b62452067d16ab5b1653fe5af7e516fd1d6a727050d37060d0f83941b25ff44', + 106800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '66bf94992c7ae7e495fcd422302ec2554955bf1ee81cc891a365b889836f3386', + 117812, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '69cbfef212c06c3e226a30329e377aa4501105e862a1d1c6cd3fde2b6c15507d', + 106692, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '454337a7189c7dcf2a8c37a8d69c51ece177de9ba36cb5133fc924e7bfd7042b', + 117816, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9700f2e4399528de12a7e7ec1551047d64261256a776bcdd963c55963568f4b9', + 107204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '92215eb3720b2d7e6181a7f1a7f330fc9668b05e48e1160a1d0bde3d1ebd34d9', + 117868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '85939ee252119c0a4249c1d780751347047ccdc1fe552595be038544c3792788', + 107392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4373c99de7c1eefefd7971019ac15ad2bc0db7cd3f62c3013925018d0586e38c', + 117840, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fe6766f5ba5906651095f3917fbfa426cf5904f0f0c7490a7b6d246dae8d60b9', + 106036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8728efc5271b4928172f32a8701ff0e2cde5210bd8277aa95cd936d723eecceb', + 116836, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IBMPlexSerif', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IBM Plex Serif font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IBM+Plex+Serif + static TextTheme ibmPlexSerifTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ibmPlexSerif(textStyle: textTheme.headline1), + headline2: GoogleFonts.ibmPlexSerif(textStyle: textTheme.headline2), + headline3: GoogleFonts.ibmPlexSerif(textStyle: textTheme.headline3), + headline4: GoogleFonts.ibmPlexSerif(textStyle: textTheme.headline4), + headline5: GoogleFonts.ibmPlexSerif(textStyle: textTheme.headline5), + headline6: GoogleFonts.ibmPlexSerif(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ibmPlexSerif(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ibmPlexSerif(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ibmPlexSerif(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ibmPlexSerif(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ibmPlexSerif(textStyle: textTheme.caption), + button: GoogleFonts.ibmPlexSerif(textStyle: textTheme.button), + overline: GoogleFonts.ibmPlexSerif(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell DW Pica font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+DW+Pica + static TextStyle imFellDwPica({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '04268ecc548fa2dfe787958a051a8e1b42b355a945f5a4d47f003e70886debc3', + 216968, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd2109f0f97280a92b37673b7bf664eee72f3b3874097dcbf1906740841b17fb0', + 244584, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellDWPica', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell DW Pica font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+DW+Pica + static TextTheme imFellDwPicaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imFellDwPica(textStyle: textTheme.headline1), + headline2: GoogleFonts.imFellDwPica(textStyle: textTheme.headline2), + headline3: GoogleFonts.imFellDwPica(textStyle: textTheme.headline3), + headline4: GoogleFonts.imFellDwPica(textStyle: textTheme.headline4), + headline5: GoogleFonts.imFellDwPica(textStyle: textTheme.headline5), + headline6: GoogleFonts.imFellDwPica(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imFellDwPica(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imFellDwPica(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imFellDwPica(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imFellDwPica(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellDwPica(textStyle: textTheme.caption), + button: GoogleFonts.imFellDwPica(textStyle: textTheme.button), + overline: GoogleFonts.imFellDwPica(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell DW Pica SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+DW+Pica+SC + static TextStyle imFellDwPicaSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6fb16b0108016bc27dd4f279a9d1e8247d0028f492cfca827753ea01a8423c83', + 198012, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellDWPicaSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell DW Pica SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+DW+Pica+SC + static TextTheme imFellDwPicaScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.caption), + button: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.button), + overline: GoogleFonts.imFellDwPicaSc(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell Double Pica font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+Double+Pica + static TextStyle imFellDoublePica({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '450b7878b03e1b88b59cd3c88d5a9dab68e698f5e89d49f6bd99bd40514f1eff', + 210916, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '63f80b5f83de7edd9b6a5674a903289d1c0f0679fefe1835d013e2c6910afacd', + 255092, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellDoublePica', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell Double Pica font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+Double+Pica + static TextTheme imFellDoublePicaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imFellDoublePica(textStyle: textTheme.headline1), + headline2: GoogleFonts.imFellDoublePica(textStyle: textTheme.headline2), + headline3: GoogleFonts.imFellDoublePica(textStyle: textTheme.headline3), + headline4: GoogleFonts.imFellDoublePica(textStyle: textTheme.headline4), + headline5: GoogleFonts.imFellDoublePica(textStyle: textTheme.headline5), + headline6: GoogleFonts.imFellDoublePica(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imFellDoublePica(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imFellDoublePica(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imFellDoublePica(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imFellDoublePica(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellDoublePica(textStyle: textTheme.caption), + button: GoogleFonts.imFellDoublePica(textStyle: textTheme.button), + overline: GoogleFonts.imFellDoublePica(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell Double Pica SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+Double+Pica+SC + static TextStyle imFellDoublePicaSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f63ae624a66cf32943ef34cf81b7d800305ce516f8396bd0b01895abf588d8d6', + 197012, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellDoublePicaSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell Double Pica SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+Double+Pica+SC + static TextTheme imFellDoublePicaScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.caption), + button: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.button), + overline: GoogleFonts.imFellDoublePicaSc(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell English font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+English + static TextStyle imFellEnglish({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1f559be93fb1947f0551b021260410225bbafe0586dd5236d734d852bf0769f1', + 194992, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '67701b098b491cf87633fd626de486662128571e48aee106245d472750bcd7c4', + 202368, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellEnglish', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell English font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+English + static TextTheme imFellEnglishTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imFellEnglish(textStyle: textTheme.headline1), + headline2: GoogleFonts.imFellEnglish(textStyle: textTheme.headline2), + headline3: GoogleFonts.imFellEnglish(textStyle: textTheme.headline3), + headline4: GoogleFonts.imFellEnglish(textStyle: textTheme.headline4), + headline5: GoogleFonts.imFellEnglish(textStyle: textTheme.headline5), + headline6: GoogleFonts.imFellEnglish(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imFellEnglish(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imFellEnglish(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imFellEnglish(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imFellEnglish(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellEnglish(textStyle: textTheme.caption), + button: GoogleFonts.imFellEnglish(textStyle: textTheme.button), + overline: GoogleFonts.imFellEnglish(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell English SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+English+SC + static TextStyle imFellEnglishSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b52b93a50244bb83984cf1b52863db1a14baf8f683fe002dd71199783477502a', + 183932, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellEnglishSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell English SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+English+SC + static TextTheme imFellEnglishScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imFellEnglishSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.imFellEnglishSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.imFellEnglishSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.imFellEnglishSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.imFellEnglishSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.imFellEnglishSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imFellEnglishSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imFellEnglishSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imFellEnglishSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imFellEnglishSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellEnglishSc(textStyle: textTheme.caption), + button: GoogleFonts.imFellEnglishSc(textStyle: textTheme.button), + overline: GoogleFonts.imFellEnglishSc(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell French Canon font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+French+Canon + static TextStyle imFellFrenchCanon({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a31b3ab35a73617ff634ad3017bc55e23ceb3daa2bf23c00c25afa3331aade8', + 145832, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '54332a8adf4fa4b9bd5ba4553b7f66a4e8c5ffb07d61701dbfee60bfac4394a4', + 158184, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellFrenchCanon', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell French Canon font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+French+Canon + static TextTheme imFellFrenchCanonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.headline1), + headline2: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.headline2), + headline3: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.headline3), + headline4: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.headline4), + headline5: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.headline5), + headline6: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.caption), + button: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.button), + overline: GoogleFonts.imFellFrenchCanon(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell French Canon SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+French+Canon+SC + static TextStyle imFellFrenchCanonSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '618df3e2380b8d244fa861a295bcae3cb41ac4f0cea67f01a815355fcd198ce8', + 136188, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellFrenchCanonSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell French Canon SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+French+Canon+SC + static TextTheme imFellFrenchCanonScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.headline1), + headline2: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.headline2), + headline3: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.headline3), + headline4: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.headline4), + headline5: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.headline5), + headline6: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.caption), + button: GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.button), + overline: GoogleFonts.imFellFrenchCanonSc(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell Great Primer font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+Great+Primer + static TextStyle imFellGreatPrimer({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fede2a25cf42680231c7bfb90da7306e0962092c8e1074fbfc44ef59289257ec', + 216552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '020c8f65ef327b827d6e28ca2e4be8f019b4a81075f1c7c00a53993664b41b93', + 249324, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellGreatPrimer', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell Great Primer font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+Great+Primer + static TextTheme imFellGreatPrimerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.headline1), + headline2: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.headline2), + headline3: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.headline3), + headline4: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.headline4), + headline5: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.headline5), + headline6: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.caption), + button: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.button), + overline: GoogleFonts.imFellGreatPrimer(textStyle: textTheme.overline), + ); + } + + /// Applies the IM Fell Great Primer SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+Great+Primer+SC + static TextStyle imFellGreatPrimerSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8894f603e127ce2093a63d487149eb1cf10f58b20ea4abbae6ac6635472dcc85', + 203776, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IMFellGreatPrimerSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the IM Fell Great Primer SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/IM+Fell+Great+Primer+SC + static TextTheme imFellGreatPrimerScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.headline1), + headline2: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.headline2), + headline3: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.headline3), + headline4: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.headline4), + headline5: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.headline5), + headline6: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.caption), + button: GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.button), + overline: GoogleFonts.imFellGreatPrimerSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Ibarra Real Nova font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ibarra+Real+Nova + static TextStyle ibarraRealNova({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fa62d319d71f5e7580a79ee36ecae3548c35a0e2d7892f8695afa7e237a3b660', + 58948, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0f9205ed765c8774cf31fd539aee83f11aec36439f0fd12bfab29a491352b9f7', + 62160, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91c844d08ae013b372d204d91e5dd37e879057e12a50150929228512c78eec5d', + 58676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '77e539a16bef74671e0c9ea382e533233bfa3f2b0219d2bd7d2d11db7502dc23', + 62244, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a2ae8b1765ec3d56c893888f27607c49f613d48918f01ed3034e7c5119269948', + 58544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'be0a49f8da3aff4a325e615fb9bd69330b92f562ff4c805471e29bca7ec57e72', + 62316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IbarraRealNova', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ibarra Real Nova font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ibarra+Real+Nova + static TextTheme ibarraRealNovaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ibarraRealNova(textStyle: textTheme.headline1), + headline2: GoogleFonts.ibarraRealNova(textStyle: textTheme.headline2), + headline3: GoogleFonts.ibarraRealNova(textStyle: textTheme.headline3), + headline4: GoogleFonts.ibarraRealNova(textStyle: textTheme.headline4), + headline5: GoogleFonts.ibarraRealNova(textStyle: textTheme.headline5), + headline6: GoogleFonts.ibarraRealNova(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ibarraRealNova(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ibarraRealNova(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ibarraRealNova(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ibarraRealNova(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ibarraRealNova(textStyle: textTheme.caption), + button: GoogleFonts.ibarraRealNova(textStyle: textTheme.button), + overline: GoogleFonts.ibarraRealNova(textStyle: textTheme.overline), + ); + } + + /// Applies the Iceberg font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Iceberg + static TextStyle iceberg({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4863f9363951873a52e866b2ad79c760da5a5c1c076692511a8fae46789aedae', + 16680, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Iceberg', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Iceberg font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Iceberg + static TextTheme icebergTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.iceberg(textStyle: textTheme.headline1), + headline2: GoogleFonts.iceberg(textStyle: textTheme.headline2), + headline3: GoogleFonts.iceberg(textStyle: textTheme.headline3), + headline4: GoogleFonts.iceberg(textStyle: textTheme.headline4), + headline5: GoogleFonts.iceberg(textStyle: textTheme.headline5), + headline6: GoogleFonts.iceberg(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.iceberg(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.iceberg(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.iceberg(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.iceberg(textStyle: textTheme.bodyText2), + caption: GoogleFonts.iceberg(textStyle: textTheme.caption), + button: GoogleFonts.iceberg(textStyle: textTheme.button), + overline: GoogleFonts.iceberg(textStyle: textTheme.overline), + ); + } + + /// Applies the Iceland font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Iceland + static TextStyle iceland({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd15cc78dabadb60a047db08291c49cb8c2d05c29de29c7505de00383b8f447cf', + 17548, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Iceland', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Iceland font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Iceland + static TextTheme icelandTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.iceland(textStyle: textTheme.headline1), + headline2: GoogleFonts.iceland(textStyle: textTheme.headline2), + headline3: GoogleFonts.iceland(textStyle: textTheme.headline3), + headline4: GoogleFonts.iceland(textStyle: textTheme.headline4), + headline5: GoogleFonts.iceland(textStyle: textTheme.headline5), + headline6: GoogleFonts.iceland(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.iceland(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.iceland(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.iceland(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.iceland(textStyle: textTheme.bodyText2), + caption: GoogleFonts.iceland(textStyle: textTheme.caption), + button: GoogleFonts.iceland(textStyle: textTheme.button), + overline: GoogleFonts.iceland(textStyle: textTheme.overline), + ); + } + + /// Applies the Imprima font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Imprima + static TextStyle imprima({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '40a584db206f3a44197d5245155bcca66a72cf6c2dd346e78ca4b30b36af92b4', + 24864, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Imprima', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Imprima font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Imprima + static TextTheme imprimaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.imprima(textStyle: textTheme.headline1), + headline2: GoogleFonts.imprima(textStyle: textTheme.headline2), + headline3: GoogleFonts.imprima(textStyle: textTheme.headline3), + headline4: GoogleFonts.imprima(textStyle: textTheme.headline4), + headline5: GoogleFonts.imprima(textStyle: textTheme.headline5), + headline6: GoogleFonts.imprima(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.imprima(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.imprima(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.imprima(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.imprima(textStyle: textTheme.bodyText2), + caption: GoogleFonts.imprima(textStyle: textTheme.caption), + button: GoogleFonts.imprima(textStyle: textTheme.button), + overline: GoogleFonts.imprima(textStyle: textTheme.overline), + ); + } + + /// Applies the Inconsolata font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inconsolata + static TextStyle inconsolata({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7b710cb16b36b86fd08be8de67824345433e776ff152ce4d819f8dac26b76bb2', + 70528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '499bfec42f5525e40e1acc5d044cce315e80cc9c1205db693cf68fd5a7b724d3', + 74916, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Inconsolata', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Inconsolata font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inconsolata + static TextTheme inconsolataTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.inconsolata(textStyle: textTheme.headline1), + headline2: GoogleFonts.inconsolata(textStyle: textTheme.headline2), + headline3: GoogleFonts.inconsolata(textStyle: textTheme.headline3), + headline4: GoogleFonts.inconsolata(textStyle: textTheme.headline4), + headline5: GoogleFonts.inconsolata(textStyle: textTheme.headline5), + headline6: GoogleFonts.inconsolata(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.inconsolata(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.inconsolata(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.inconsolata(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.inconsolata(textStyle: textTheme.bodyText2), + caption: GoogleFonts.inconsolata(textStyle: textTheme.caption), + button: GoogleFonts.inconsolata(textStyle: textTheme.button), + overline: GoogleFonts.inconsolata(textStyle: textTheme.overline), + ); + } + + /// Applies the Inder font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inder + static TextStyle inder({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eb41a206e08e82f74d76415f5d8d2feeaf53587676b8ed6c2ea15bb2e88ccf8d', + 31008, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Inder', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Inder font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inder + static TextTheme inderTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.inder(textStyle: textTheme.headline1), + headline2: GoogleFonts.inder(textStyle: textTheme.headline2), + headline3: GoogleFonts.inder(textStyle: textTheme.headline3), + headline4: GoogleFonts.inder(textStyle: textTheme.headline4), + headline5: GoogleFonts.inder(textStyle: textTheme.headline5), + headline6: GoogleFonts.inder(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.inder(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.inder(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.inder(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.inder(textStyle: textTheme.bodyText2), + caption: GoogleFonts.inder(textStyle: textTheme.caption), + button: GoogleFonts.inder(textStyle: textTheme.button), + overline: GoogleFonts.inder(textStyle: textTheme.overline), + ); + } + + /// Applies the Indie Flower font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Indie+Flower + static TextStyle indieFlower({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '61c24604992861512306296260abd7382a4e89dbe2d6e0d5ba3dbd1a15b95ff4', + 60484, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IndieFlower', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Indie Flower font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Indie+Flower + static TextTheme indieFlowerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.indieFlower(textStyle: textTheme.headline1), + headline2: GoogleFonts.indieFlower(textStyle: textTheme.headline2), + headline3: GoogleFonts.indieFlower(textStyle: textTheme.headline3), + headline4: GoogleFonts.indieFlower(textStyle: textTheme.headline4), + headline5: GoogleFonts.indieFlower(textStyle: textTheme.headline5), + headline6: GoogleFonts.indieFlower(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.indieFlower(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.indieFlower(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.indieFlower(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.indieFlower(textStyle: textTheme.bodyText2), + caption: GoogleFonts.indieFlower(textStyle: textTheme.caption), + button: GoogleFonts.indieFlower(textStyle: textTheme.button), + overline: GoogleFonts.indieFlower(textStyle: textTheme.overline), + ); + } + + /// Applies the Inika font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inika + static TextStyle inika({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b4a85642ea25e8b6a0657684af8ab67401b31b1f39ef952616d46f1ee711107e', + 39652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e831ff700e7e5ee39b33fb1ae47d7f98ce526a136e1d90c4aaf1cbfbba0d4336', + 38688, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Inika', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Inika font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inika + static TextTheme inikaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.inika(textStyle: textTheme.headline1), + headline2: GoogleFonts.inika(textStyle: textTheme.headline2), + headline3: GoogleFonts.inika(textStyle: textTheme.headline3), + headline4: GoogleFonts.inika(textStyle: textTheme.headline4), + headline5: GoogleFonts.inika(textStyle: textTheme.headline5), + headline6: GoogleFonts.inika(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.inika(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.inika(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.inika(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.inika(textStyle: textTheme.bodyText2), + caption: GoogleFonts.inika(textStyle: textTheme.caption), + button: GoogleFonts.inika(textStyle: textTheme.button), + overline: GoogleFonts.inika(textStyle: textTheme.overline), + ); + } + + /// Applies the Inknut Antiqua font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inknut+Antiqua + static TextStyle inknutAntiqua({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8fae03035a8fb6772fc7bcac683c4a01747a3902ede69b6897be980d35cd3c42', + 279252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bad6e7b6f2580d3870d5242c04a7edbb0712500e639570759d1b76b16ad225af', + 274980, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f7bad3658649b817553e3c3a1e3b75b8b1c2f93af24d3ee0c2f491f13695cee4', + 277544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4249a7edc9acfbbb46d50638be038427a109d75df9478fd696a6d61ac2c6262b', + 277284, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ed4800a911bc4a319bbb68949167b0e0c9149ae4542444b3643b0949f21dbebb', + 275168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '58f6a2abd44b4a7ba81f42611ec481c40e08bed9129fec6f638b2dca583bf20d', + 274600, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '068486e18282d9c5300c186834bd1a055d1d4d2697ac3498756bc41e999b676b', + 269264, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'InknutAntiqua', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Inknut Antiqua font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inknut+Antiqua + static TextTheme inknutAntiquaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.inknutAntiqua(textStyle: textTheme.headline1), + headline2: GoogleFonts.inknutAntiqua(textStyle: textTheme.headline2), + headline3: GoogleFonts.inknutAntiqua(textStyle: textTheme.headline3), + headline4: GoogleFonts.inknutAntiqua(textStyle: textTheme.headline4), + headline5: GoogleFonts.inknutAntiqua(textStyle: textTheme.headline5), + headline6: GoogleFonts.inknutAntiqua(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.inknutAntiqua(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.inknutAntiqua(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.inknutAntiqua(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.inknutAntiqua(textStyle: textTheme.bodyText2), + caption: GoogleFonts.inknutAntiqua(textStyle: textTheme.caption), + button: GoogleFonts.inknutAntiqua(textStyle: textTheme.button), + overline: GoogleFonts.inknutAntiqua(textStyle: textTheme.overline), + ); + } + + /// Applies the Inria Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inria+Sans + static TextStyle inriaSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3bde5e08b5ec7274f1c28704b62bd581c28724f8cf4412d56a9e24435e927789', + 45140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e33d8e62a895c0402146425676e4254906218e07c6adde8532ae0f436aff96ae', + 46472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '78a5989461a98cf7daa6612f5b9240f06cf592fcaeb0684a49a73d5616085753', + 45356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dea0c172e0ec1669869a55587b188534d474341d049a62012e316cdd79e82f22', + 46704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7747b367f8106ba29552aff3126864e3d6b20c008e33d214252ca30fff47f65c', + 44708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '70544f369add81b1bf7a0b8f3d4108c7bdca0f1426f9251c47d8d54ae6820b90', + 46364, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'InriaSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Inria Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inria+Sans + static TextTheme inriaSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.inriaSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.inriaSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.inriaSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.inriaSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.inriaSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.inriaSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.inriaSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.inriaSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.inriaSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.inriaSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.inriaSans(textStyle: textTheme.caption), + button: GoogleFonts.inriaSans(textStyle: textTheme.button), + overline: GoogleFonts.inriaSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Inria Serif font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inria+Serif + static TextStyle inriaSerif({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '843b3e9e758e66cd88535ad2c67fba727e83e342a871227e9d6dd1640acbd496', + 55144, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f4537cff635316910c2b9f1449b29caaa2d9aaf852dc13bd2d82adc9070e861d', + 54868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3e86dfe8f6fc1e2431b0a39040b2dc845fe91b448d1a75733f8a2e1d8dd54586', + 55368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '911f907aefd837c9e50f383f376f437fef8b69dee712ca4f5513ffc70769cc5a', + 55020, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ee42dcf7120d640f7b28930c80818aaec0e114784ea1935fbf0721429519d6c5', + 55188, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '503bdc8982bd9fc8af24dadb68f8e5304ddeb3d2aa5f9135811977c9b4c4eb80', + 54952, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'InriaSerif', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Inria Serif font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inria+Serif + static TextTheme inriaSerifTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.inriaSerif(textStyle: textTheme.headline1), + headline2: GoogleFonts.inriaSerif(textStyle: textTheme.headline2), + headline3: GoogleFonts.inriaSerif(textStyle: textTheme.headline3), + headline4: GoogleFonts.inriaSerif(textStyle: textTheme.headline4), + headline5: GoogleFonts.inriaSerif(textStyle: textTheme.headline5), + headline6: GoogleFonts.inriaSerif(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.inriaSerif(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.inriaSerif(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.inriaSerif(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.inriaSerif(textStyle: textTheme.bodyText2), + caption: GoogleFonts.inriaSerif(textStyle: textTheme.caption), + button: GoogleFonts.inriaSerif(textStyle: textTheme.button), + overline: GoogleFonts.inriaSerif(textStyle: textTheme.overline), + ); + } + + /// Applies the Inter font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inter + static TextStyle inter({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '897d64cd0dfbeb56e7867aff5fb59519c0a18eaa535b4d4f9d636ac43028afb5', + 257128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a8c528f80a6ad8d07eb0a822ff9763e3286ce1463b1cd881cafbc2d3d9018512', + 256936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7cedc5ced62f88258ed3781a814ff426d7c63e5ef822bc77e66b393b3316ce86', + 256628, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '74b0b48ce5240039e1a17c62f24f5abc322d3d77d4bf96efcdad6d637123cc9d', + 256476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '177913939a2c83016eaf35b8dcf5b863fcb5d8e86fcb78a14ad753d055d06436', + 257944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f0a9e5b2bc1eef6c3241a779a62cea7c34b88535d7e586390fdcdf28ab01d673', + 258828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '94c9d9a14fc9ae26fd08041b634823238718b745b8a34986ddfb57cf3db367da', + 259260, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e5493c1e805b48142688a216308108352fd538721635d7f990c47996dcf8e2c4', + 259864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a2a712f761390199ddad75da5123d6f97f529f5d6dab247f94ceb954a8fe381e', + 260212, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Inter', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Inter font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Inter + static TextTheme interTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.inter(textStyle: textTheme.headline1), + headline2: GoogleFonts.inter(textStyle: textTheme.headline2), + headline3: GoogleFonts.inter(textStyle: textTheme.headline3), + headline4: GoogleFonts.inter(textStyle: textTheme.headline4), + headline5: GoogleFonts.inter(textStyle: textTheme.headline5), + headline6: GoogleFonts.inter(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.inter(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.inter(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.inter(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.inter(textStyle: textTheme.bodyText2), + caption: GoogleFonts.inter(textStyle: textTheme.caption), + button: GoogleFonts.inter(textStyle: textTheme.button), + overline: GoogleFonts.inter(textStyle: textTheme.overline), + ); + } + + /// Applies the Irish Grover font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Irish+Grover + static TextStyle irishGrover({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '871e6c825a4e60667eb8131be9f23ace65f65e3f15a9c08c3a798797c9e361b2', + 52272, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IrishGrover', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Irish Grover font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Irish+Grover + static TextTheme irishGroverTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.irishGrover(textStyle: textTheme.headline1), + headline2: GoogleFonts.irishGrover(textStyle: textTheme.headline2), + headline3: GoogleFonts.irishGrover(textStyle: textTheme.headline3), + headline4: GoogleFonts.irishGrover(textStyle: textTheme.headline4), + headline5: GoogleFonts.irishGrover(textStyle: textTheme.headline5), + headline6: GoogleFonts.irishGrover(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.irishGrover(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.irishGrover(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.irishGrover(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.irishGrover(textStyle: textTheme.bodyText2), + caption: GoogleFonts.irishGrover(textStyle: textTheme.caption), + button: GoogleFonts.irishGrover(textStyle: textTheme.button), + overline: GoogleFonts.irishGrover(textStyle: textTheme.overline), + ); + } + + /// Applies the Istok Web font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Istok+Web + static TextStyle istokWeb({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '69f0e211d11c1acf74b2c9076af79b8c4437700758d0282acf48674ef128953a', + 137024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '05eee5ff9d276f82970504c5e15e6097ae58262e043f86c6620a18611cdcf94e', + 89568, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '000e33f7e7a72f87087ee83ef75edf7993294fc065f5f8e52ae6ca1c90c7517f', + 92660, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c19d7189ef0fb5066351d3851d3a386722d97b98c62fc344ffce8f4f1889512a', + 89608, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'IstokWeb', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Istok Web font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Istok+Web + static TextTheme istokWebTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.istokWeb(textStyle: textTheme.headline1), + headline2: GoogleFonts.istokWeb(textStyle: textTheme.headline2), + headline3: GoogleFonts.istokWeb(textStyle: textTheme.headline3), + headline4: GoogleFonts.istokWeb(textStyle: textTheme.headline4), + headline5: GoogleFonts.istokWeb(textStyle: textTheme.headline5), + headline6: GoogleFonts.istokWeb(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.istokWeb(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.istokWeb(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.istokWeb(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.istokWeb(textStyle: textTheme.bodyText2), + caption: GoogleFonts.istokWeb(textStyle: textTheme.caption), + button: GoogleFonts.istokWeb(textStyle: textTheme.button), + overline: GoogleFonts.istokWeb(textStyle: textTheme.overline), + ); + } + + /// Applies the Italiana font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Italiana + static TextStyle italiana({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b1324621b4067c2f4664c85776eaa7a358556c72c41adc3672d1e85e255b715a', + 31560, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Italiana', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Italiana font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Italiana + static TextTheme italianaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.italiana(textStyle: textTheme.headline1), + headline2: GoogleFonts.italiana(textStyle: textTheme.headline2), + headline3: GoogleFonts.italiana(textStyle: textTheme.headline3), + headline4: GoogleFonts.italiana(textStyle: textTheme.headline4), + headline5: GoogleFonts.italiana(textStyle: textTheme.headline5), + headline6: GoogleFonts.italiana(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.italiana(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.italiana(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.italiana(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.italiana(textStyle: textTheme.bodyText2), + caption: GoogleFonts.italiana(textStyle: textTheme.caption), + button: GoogleFonts.italiana(textStyle: textTheme.button), + overline: GoogleFonts.italiana(textStyle: textTheme.overline), + ); + } + + /// Applies the Italianno font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Italianno + static TextStyle italianno({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bfbaa565dcb115e0d8e8af969814850e25a50df02022afefd5b2ba3174c386e3', + 137316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Italianno', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Italianno font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Italianno + static TextTheme italiannoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.italianno(textStyle: textTheme.headline1), + headline2: GoogleFonts.italianno(textStyle: textTheme.headline2), + headline3: GoogleFonts.italianno(textStyle: textTheme.headline3), + headline4: GoogleFonts.italianno(textStyle: textTheme.headline4), + headline5: GoogleFonts.italianno(textStyle: textTheme.headline5), + headline6: GoogleFonts.italianno(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.italianno(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.italianno(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.italianno(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.italianno(textStyle: textTheme.bodyText2), + caption: GoogleFonts.italianno(textStyle: textTheme.caption), + button: GoogleFonts.italianno(textStyle: textTheme.button), + overline: GoogleFonts.italianno(textStyle: textTheme.overline), + ); + } + + /// Applies the Itim font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Itim + static TextStyle itim({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd649b08c03fa8e37e169c6e7fc22372fe2c6f97d639fbcbe67f8702afb9ef1bc', + 249260, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Itim', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Itim font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Itim + static TextTheme itimTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.itim(textStyle: textTheme.headline1), + headline2: GoogleFonts.itim(textStyle: textTheme.headline2), + headline3: GoogleFonts.itim(textStyle: textTheme.headline3), + headline4: GoogleFonts.itim(textStyle: textTheme.headline4), + headline5: GoogleFonts.itim(textStyle: textTheme.headline5), + headline6: GoogleFonts.itim(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.itim(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.itim(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.itim(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.itim(textStyle: textTheme.bodyText2), + caption: GoogleFonts.itim(textStyle: textTheme.caption), + button: GoogleFonts.itim(textStyle: textTheme.button), + overline: GoogleFonts.itim(textStyle: textTheme.overline), + ); + } + + /// Applies the Jacques Francois font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jacques+Francois + static TextStyle jacquesFrancois({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd263121e53613f81bea06459cb1ac924693f48b654d9943d34776a3efa1fc52e', + 42580, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JacquesFrancois', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jacques Francois font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jacques+Francois + static TextTheme jacquesFrancoisTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jacquesFrancois(textStyle: textTheme.headline1), + headline2: GoogleFonts.jacquesFrancois(textStyle: textTheme.headline2), + headline3: GoogleFonts.jacquesFrancois(textStyle: textTheme.headline3), + headline4: GoogleFonts.jacquesFrancois(textStyle: textTheme.headline4), + headline5: GoogleFonts.jacquesFrancois(textStyle: textTheme.headline5), + headline6: GoogleFonts.jacquesFrancois(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jacquesFrancois(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jacquesFrancois(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jacquesFrancois(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jacquesFrancois(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jacquesFrancois(textStyle: textTheme.caption), + button: GoogleFonts.jacquesFrancois(textStyle: textTheme.button), + overline: GoogleFonts.jacquesFrancois(textStyle: textTheme.overline), + ); + } + + /// Applies the Jacques Francois Shadow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jacques+Francois+Shadow + static TextStyle jacquesFrancoisShadow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e4664490f27116a48b79a15fc06c1817e3669ac1d3ee0e65f80b093997b5e935', + 56088, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JacquesFrancoisShadow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jacques Francois Shadow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jacques+Francois+Shadow + static TextTheme jacquesFrancoisShadowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.headline1), + headline2: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.headline2), + headline3: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.headline3), + headline4: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.headline4), + headline5: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.headline5), + headline6: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.caption), + button: GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.button), + overline: + GoogleFonts.jacquesFrancoisShadow(textStyle: textTheme.overline), + ); + } + + /// Applies the Jaldi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jaldi + static TextStyle jaldi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2fd0aecfd94af32615e102201a3d6b70dd7b98a317a4b6457f9d5683435f2680', + 273184, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1eb9040b249dbbf98470eca20e05d667c64d16570d20f4f3b5c8082472d03566', + 272924, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Jaldi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jaldi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jaldi + static TextTheme jaldiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jaldi(textStyle: textTheme.headline1), + headline2: GoogleFonts.jaldi(textStyle: textTheme.headline2), + headline3: GoogleFonts.jaldi(textStyle: textTheme.headline3), + headline4: GoogleFonts.jaldi(textStyle: textTheme.headline4), + headline5: GoogleFonts.jaldi(textStyle: textTheme.headline5), + headline6: GoogleFonts.jaldi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jaldi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jaldi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jaldi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jaldi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jaldi(textStyle: textTheme.caption), + button: GoogleFonts.jaldi(textStyle: textTheme.button), + overline: GoogleFonts.jaldi(textStyle: textTheme.overline), + ); + } + + /// Applies the JetBrains Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/JetBrains+Mono + static TextStyle jetBrainsMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2d9c45ef613517fe16ef9b98e22bf42c9cde2e64c3b5dec28eccf19ef951214f', + 100036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd8b7b6fd7549d056bacd72fc5a44509b6dd60e79e23ca39138266fef6eec1d99', + 100112, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8bbf6f151ea26ab4020ab3909444b7c480cd0bdd14f3c9bf990940802430a691', + 100048, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bcad6628b88dabe2c7128a8d8da7517d30d291d2196c242d6bd064803b6bc81b', + 99952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '72df06f080fd2a3a7de54b16f2f4fe430ea07ac88edb13547f226cf40fad1359', + 99964, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1c883998d81a7f0fc7d29b754d6d4c760f78c2c2754cd83d4be49deacfde3eea', + 99920, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '62eedf885d199e8fd5996d76b7d0b957d51de06048b818877cb45dd5e6cc886a', + 99860, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5a90822ddce5280355142856207a3cdb8ceff10d064bad9984be6d4f9538ca54', + 99880, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '17cd635d99cdf2bc587f7edfa12afb833fe73442f6c24bb75416096abf343c4c', + 102952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '082c46dba74facd18763c2f8b46464050249389890cc0525442bfe5b9dcb696f', + 103036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8019ed5d2dbb8b331bbe43d8b629a7ba5e60ce45a97c73b9aaa909f92cd68a82', + 102924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '06f5559c182b0ee9933f08da76d9029034d0acf76dd368b61b0f804d5dffe847', + 102740, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3b8cba00588c1b76e016aed0322ec1115b1911eb617aa0c3d8d964ba93172f33', + 102848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ac952bea8f76559fa60e09cbf07cd2e30763530ee53b62399a6057ed8e503b2b', + 102796, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f5e1d2fb4b360d37a9a0dd3b54218280d0c71852e56d046d3a1ec88b61457eae', + 102732, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dcc9bc14c86097e41cd2ff409e2bfd72f92ab8c5a6e1d3f0f55ae8078b37c79f', + 102808, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JetBrainsMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the JetBrains Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/JetBrains+Mono + static TextTheme jetBrainsMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jetBrainsMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.jetBrainsMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.jetBrainsMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.jetBrainsMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.jetBrainsMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.jetBrainsMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jetBrainsMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jetBrainsMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jetBrainsMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jetBrainsMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jetBrainsMono(textStyle: textTheme.caption), + button: GoogleFonts.jetBrainsMono(textStyle: textTheme.button), + overline: GoogleFonts.jetBrainsMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Jim Nightshade font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jim+Nightshade + static TextStyle jimNightshade({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '69667733e323bd8537cd7e8ab6c0cde0b0d48e1f336695228e8a9de962feec29', + 153264, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JimNightshade', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jim Nightshade font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jim+Nightshade + static TextTheme jimNightshadeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jimNightshade(textStyle: textTheme.headline1), + headline2: GoogleFonts.jimNightshade(textStyle: textTheme.headline2), + headline3: GoogleFonts.jimNightshade(textStyle: textTheme.headline3), + headline4: GoogleFonts.jimNightshade(textStyle: textTheme.headline4), + headline5: GoogleFonts.jimNightshade(textStyle: textTheme.headline5), + headline6: GoogleFonts.jimNightshade(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jimNightshade(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jimNightshade(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jimNightshade(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jimNightshade(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jimNightshade(textStyle: textTheme.caption), + button: GoogleFonts.jimNightshade(textStyle: textTheme.button), + overline: GoogleFonts.jimNightshade(textStyle: textTheme.overline), + ); + } + + /// Applies the Jockey One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jockey+One + static TextStyle jockeyOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cbdbfa4fff4214a6685ff84262303ce8f4c9a4b6e563f149a8cc5322417aae81', + 48560, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JockeyOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jockey One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jockey+One + static TextTheme jockeyOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jockeyOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.jockeyOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.jockeyOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.jockeyOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.jockeyOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.jockeyOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jockeyOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jockeyOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jockeyOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jockeyOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jockeyOne(textStyle: textTheme.caption), + button: GoogleFonts.jockeyOne(textStyle: textTheme.button), + overline: GoogleFonts.jockeyOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Jolly Lodger font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jolly+Lodger + static TextStyle jollyLodger({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '816f864e770d0e20f949a3c6064291765734593637efde29ea2295a773c7afa2', + 39384, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JollyLodger', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jolly Lodger font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jolly+Lodger + static TextTheme jollyLodgerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jollyLodger(textStyle: textTheme.headline1), + headline2: GoogleFonts.jollyLodger(textStyle: textTheme.headline2), + headline3: GoogleFonts.jollyLodger(textStyle: textTheme.headline3), + headline4: GoogleFonts.jollyLodger(textStyle: textTheme.headline4), + headline5: GoogleFonts.jollyLodger(textStyle: textTheme.headline5), + headline6: GoogleFonts.jollyLodger(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jollyLodger(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jollyLodger(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jollyLodger(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jollyLodger(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jollyLodger(textStyle: textTheme.caption), + button: GoogleFonts.jollyLodger(textStyle: textTheme.button), + overline: GoogleFonts.jollyLodger(textStyle: textTheme.overline), + ); + } + + /// Applies the Jomhuria font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jomhuria + static TextStyle jomhuria({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6dce267ed457cc6f5511cd60d4fbbc941e2c0cf029959a91effbd93815f66d47', + 170560, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Jomhuria', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jomhuria font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jomhuria + static TextTheme jomhuriaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jomhuria(textStyle: textTheme.headline1), + headline2: GoogleFonts.jomhuria(textStyle: textTheme.headline2), + headline3: GoogleFonts.jomhuria(textStyle: textTheme.headline3), + headline4: GoogleFonts.jomhuria(textStyle: textTheme.headline4), + headline5: GoogleFonts.jomhuria(textStyle: textTheme.headline5), + headline6: GoogleFonts.jomhuria(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jomhuria(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jomhuria(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jomhuria(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jomhuria(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jomhuria(textStyle: textTheme.caption), + button: GoogleFonts.jomhuria(textStyle: textTheme.button), + overline: GoogleFonts.jomhuria(textStyle: textTheme.overline), + ); + } + + /// Applies the Jomolhari font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jomolhari + static TextStyle jomolhari({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3ee25009d9daf59851273c5b12d4656fbdfd943f715735eda3c58bbf19ebd677', + 1002648, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Jomolhari', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jomolhari font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jomolhari + static TextTheme jomolhariTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jomolhari(textStyle: textTheme.headline1), + headline2: GoogleFonts.jomolhari(textStyle: textTheme.headline2), + headline3: GoogleFonts.jomolhari(textStyle: textTheme.headline3), + headline4: GoogleFonts.jomolhari(textStyle: textTheme.headline4), + headline5: GoogleFonts.jomolhari(textStyle: textTheme.headline5), + headline6: GoogleFonts.jomolhari(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jomolhari(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jomolhari(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jomolhari(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jomolhari(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jomolhari(textStyle: textTheme.caption), + button: GoogleFonts.jomolhari(textStyle: textTheme.button), + overline: GoogleFonts.jomolhari(textStyle: textTheme.overline), + ); + } + + /// Applies the Josefin Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Josefin+Sans + static TextStyle josefinSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd9274027036e4bec6eeac49709c56529144d0714f2d42cfefabb8f29aa669110', + 71844, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fe583724f6b3b6ff7f2a65b872c7a8be86957b1f03d8efb03b7c3a83271d22f0', + 71124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2bfd7038e00c3bcb80df604697efc092891a519557503aab5b119fad6fb79d41', + 70504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7ab4a22bc24c0da9b9abeae23dcabe78ebe9cb10010845ffc5b916764b87f63a', + 70336, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ad0ce8b3f694b796a43e60893235246f404c728782ef2719a3122b54b6aee1d6', + 71316, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e240205c12a00fd8fec9a99ee4ce68015307c91c1dc38586775ff103177bbf6b', + 70608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1af031215debaf6e64b6373e58d995de8763c248952fcf2a5f2b03b1cff3e26f', + 73004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd8d67f5eb2f1bd5f94c9574d8aee64e7e1706e25d0e4715e73d236bf12efeca0', + 71876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dd252f6382ade7107cb7955cfb5062f3b8b8546376fd9bdb6774fc830292db75', + 70672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'de8609adb9deaf3cd40532c56050226a1aa22c9f100b56fd248fd4b77fd8fd88', + 72656, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JosefinSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Josefin Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Josefin+Sans + static TextTheme josefinSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.josefinSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.josefinSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.josefinSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.josefinSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.josefinSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.josefinSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.josefinSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.josefinSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.josefinSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.josefinSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.josefinSans(textStyle: textTheme.caption), + button: GoogleFonts.josefinSans(textStyle: textTheme.button), + overline: GoogleFonts.josefinSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Josefin Slab font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Josefin+Slab + static TextStyle josefinSlab({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '447b30a4f09ce882924bc14b5cb2d46ed8a09e31fbd138c82200fce2411f2612', + 20404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9e521fdac6770840a2382fe98c7220bc471558f801d8965edf8573e7f30b69b5', + 21704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ed15a28fd4c2b8d4813431c543e1e1d9293d3054ccc2ba5ef342f99ce5a44c08', + 20896, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5e1991a7b37703dc6b6e746ddc357b7310c82534d6438bdb6f7ae3748790800e', + 22096, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a95bda8e2687087242a1a437c00ed9c693590a2280a21d2a4734a3ad6dfce08b', + 20448, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '61d7f09bf0f42191d6840eb606f9898b7faf7fe6493a630405fe91aac97327f4', + 21468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a3215f9937cb8a3b66779e1b69158645771177c7433046a9d0929ddc30e126e', + 20744, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'efaff26fee494b1b09da8456684d5c03d3bb898803d186aa6a88154f10bfdfee', + 22096, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '00f4364ef7f981110c8e894aa31ef2195629999eeb5bc8689c21745ec03cf534', + 19936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '999b995ee79a2865d9ed663bd3b3d65fcd10a6c15198afb228ca225b210eac8c', + 21064, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JosefinSlab', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Josefin Slab font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Josefin+Slab + static TextTheme josefinSlabTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.josefinSlab(textStyle: textTheme.headline1), + headline2: GoogleFonts.josefinSlab(textStyle: textTheme.headline2), + headline3: GoogleFonts.josefinSlab(textStyle: textTheme.headline3), + headline4: GoogleFonts.josefinSlab(textStyle: textTheme.headline4), + headline5: GoogleFonts.josefinSlab(textStyle: textTheme.headline5), + headline6: GoogleFonts.josefinSlab(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.josefinSlab(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.josefinSlab(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.josefinSlab(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.josefinSlab(textStyle: textTheme.bodyText2), + caption: GoogleFonts.josefinSlab(textStyle: textTheme.caption), + button: GoogleFonts.josefinSlab(textStyle: textTheme.button), + overline: GoogleFonts.josefinSlab(textStyle: textTheme.overline), + ); + } + + /// Applies the Jost font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jost + static TextStyle jost({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '31432208500b7e66df8a5d57e07a15f8e19d393d52c66c1235b6f96cd67fb8a8', + 55268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '35fe1d6bba11d22fcc08d886caff10018f9ba95aeafb027b41d7b2586de1df73', + 55380, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a6599583e03ffc84b1c01cc9fcbc561a5622de236557a41ab56be41974d74d0', + 55308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '36eb9b6e0e94dfd1365f08c9c8e37814033cae517e950ebf055cc379799c0858', + 55196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a5a78c6e6cf8e5f36debdb534e39fc078da16f3fc6ef10929f3d0b168b5f84e', + 55332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ab8278b6cf97aa444c220fd6090733690620c191570e0f61470346cd536ba134', + 55332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7cfbb2aadaea6d6c0696ee82db2dee3dfd9bd89628bc1c14b861f1da86d60e02', + 55276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c8e684e803f32dbae5ad9b45ae980c40c898972641a78d441469b89432707dc3', + 55396, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '65f8b5baa6c4889d4ad2f68ae989147de8186bc7ef87cfcf256ea9a78e04a841', + 55368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e6ac5ab9629d57d9df4d798a1453231439e40641633bac30b2e3852f5e284b7d', + 58936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '257071dd21f3821a5d7a2c380126160b553eb24154ecdaa9f5649c558fc2ea41', + 59140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '683edc2f30f8d2164e6553ebe92f11f02f5316ef0505b9536cdebbddf7260b03', + 59112, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd1d09478db8be26fb7b6479bdc340c9186f450a6eaf59730c13bedba7c7a48a4', + 59052, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e444b83bcb702db1b08395ed4749d541cfef5445bc9dc75b152365dda25f0527', + 59232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '61bb2ccedeb641b230a6dcc2c035e4206bba308fc1cb8cbc61a0646b73ee44cc', + 59168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '60e2bcbc06ff7e44cf657267af33dec235628900a555eeb3578039d5f0fb2f4a', + 59024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '76bad08c8165c8029d667758703fb5d17e464c5abafb306c7650148c9337f263', + 59036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c8ba2e060d6c68ce19e625780c780a90009416e4ed1a69c272fc70ebcc33f3db', + 59008, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Jost', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jost font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jost + static TextTheme jostTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jost(textStyle: textTheme.headline1), + headline2: GoogleFonts.jost(textStyle: textTheme.headline2), + headline3: GoogleFonts.jost(textStyle: textTheme.headline3), + headline4: GoogleFonts.jost(textStyle: textTheme.headline4), + headline5: GoogleFonts.jost(textStyle: textTheme.headline5), + headline6: GoogleFonts.jost(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jost(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jost(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jost(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jost(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jost(textStyle: textTheme.caption), + button: GoogleFonts.jost(textStyle: textTheme.button), + overline: GoogleFonts.jost(textStyle: textTheme.overline), + ); + } + + /// Applies the Joti One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Joti+One + static TextStyle jotiOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8f5feca23a0920be0f78e1eb58c62cdb9ef32b1c4142f6b1ebc3cf13e172683d', + 45536, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JotiOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Joti One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Joti+One + static TextTheme jotiOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jotiOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.jotiOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.jotiOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.jotiOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.jotiOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.jotiOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jotiOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jotiOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jotiOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jotiOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jotiOne(textStyle: textTheme.caption), + button: GoogleFonts.jotiOne(textStyle: textTheme.button), + overline: GoogleFonts.jotiOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Jua font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jua + static TextStyle jua({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6e140114334d538cd7aba3f5c53621623e62b941efa1a0fd2aa8d5dbea4c61e1', + 1366212, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Jua', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jua font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jua + static TextTheme juaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jua(textStyle: textTheme.headline1), + headline2: GoogleFonts.jua(textStyle: textTheme.headline2), + headline3: GoogleFonts.jua(textStyle: textTheme.headline3), + headline4: GoogleFonts.jua(textStyle: textTheme.headline4), + headline5: GoogleFonts.jua(textStyle: textTheme.headline5), + headline6: GoogleFonts.jua(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jua(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jua(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jua(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jua(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jua(textStyle: textTheme.caption), + button: GoogleFonts.jua(textStyle: textTheme.button), + overline: GoogleFonts.jua(textStyle: textTheme.overline), + ); + } + + /// Applies the Judson font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Judson + static TextStyle judson({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a0e44f8bee5db23549c40c2bdd46ee689a1d4427410df98883638059880eb73b', + 120496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '434a445b96fb17f89c47a66f76abe63757bb6c0997d49bc83a86e2b0cca56b58', + 111732, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b39af14b252a5cb398202d4738e995ef23ad94afe48fbd78fac58759d298f49e', + 107400, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Judson', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Judson font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Judson + static TextTheme judsonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.judson(textStyle: textTheme.headline1), + headline2: GoogleFonts.judson(textStyle: textTheme.headline2), + headline3: GoogleFonts.judson(textStyle: textTheme.headline3), + headline4: GoogleFonts.judson(textStyle: textTheme.headline4), + headline5: GoogleFonts.judson(textStyle: textTheme.headline5), + headline6: GoogleFonts.judson(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.judson(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.judson(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.judson(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.judson(textStyle: textTheme.bodyText2), + caption: GoogleFonts.judson(textStyle: textTheme.caption), + button: GoogleFonts.judson(textStyle: textTheme.button), + overline: GoogleFonts.judson(textStyle: textTheme.overline), + ); + } + + /// Applies the Julee font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Julee + static TextStyle julee({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3f334d6179a0a109566471f8a12eb16eb9b7ce8b2fb4ae975450fc8a2dd71358', + 30828, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Julee', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Julee font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Julee + static TextTheme juleeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.julee(textStyle: textTheme.headline1), + headline2: GoogleFonts.julee(textStyle: textTheme.headline2), + headline3: GoogleFonts.julee(textStyle: textTheme.headline3), + headline4: GoogleFonts.julee(textStyle: textTheme.headline4), + headline5: GoogleFonts.julee(textStyle: textTheme.headline5), + headline6: GoogleFonts.julee(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.julee(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.julee(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.julee(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.julee(textStyle: textTheme.bodyText2), + caption: GoogleFonts.julee(textStyle: textTheme.caption), + button: GoogleFonts.julee(textStyle: textTheme.button), + overline: GoogleFonts.julee(textStyle: textTheme.overline), + ); + } + + /// Applies the Julius Sans One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Julius+Sans+One + static TextStyle juliusSansOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2453dedd8ffddbabbe0e7b6822b7cf607757d98524241a40596bb7ae18212156', + 27868, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JuliusSansOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Julius Sans One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Julius+Sans+One + static TextTheme juliusSansOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.juliusSansOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.juliusSansOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.juliusSansOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.juliusSansOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.juliusSansOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.juliusSansOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.juliusSansOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.juliusSansOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.juliusSansOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.juliusSansOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.juliusSansOne(textStyle: textTheme.caption), + button: GoogleFonts.juliusSansOne(textStyle: textTheme.button), + overline: GoogleFonts.juliusSansOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Junge font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Junge + static TextStyle junge({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '573f4ddfb30769905cf4446b3fc01243dd50c8d9ad1f810c91f3b009b109d031', + 38872, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Junge', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Junge font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Junge + static TextTheme jungeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.junge(textStyle: textTheme.headline1), + headline2: GoogleFonts.junge(textStyle: textTheme.headline2), + headline3: GoogleFonts.junge(textStyle: textTheme.headline3), + headline4: GoogleFonts.junge(textStyle: textTheme.headline4), + headline5: GoogleFonts.junge(textStyle: textTheme.headline5), + headline6: GoogleFonts.junge(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.junge(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.junge(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.junge(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.junge(textStyle: textTheme.bodyText2), + caption: GoogleFonts.junge(textStyle: textTheme.caption), + button: GoogleFonts.junge(textStyle: textTheme.button), + overline: GoogleFonts.junge(textStyle: textTheme.overline), + ); + } + + /// Applies the Jura font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jura + static TextStyle jura({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '77bf0cc35f4472e54d1b2daf9d1bfc5f02b062280d8dccd089869c247b4787ee', + 130688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '33eb5cfd183074e05fa8299bd75531ec22a6a6d5f8778170d27310d95b1bbbb6', + 131592, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '77d5a89082924bbe692443c95c536a679eef0891bfbe46d7e30f206f8486631f', + 132540, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '85ee38dc27e08fef91f43a628bfb4a044e79102b07af8ea7d859b249c169aada', + 134512, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8215e86097df83eb3473c6f3ee4d3c63cd00dce9d02b9cd816d27f4e13616183', + 136056, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Jura', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Jura font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Jura + static TextTheme juraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.jura(textStyle: textTheme.headline1), + headline2: GoogleFonts.jura(textStyle: textTheme.headline2), + headline3: GoogleFonts.jura(textStyle: textTheme.headline3), + headline4: GoogleFonts.jura(textStyle: textTheme.headline4), + headline5: GoogleFonts.jura(textStyle: textTheme.headline5), + headline6: GoogleFonts.jura(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.jura(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.jura(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.jura(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.jura(textStyle: textTheme.bodyText2), + caption: GoogleFonts.jura(textStyle: textTheme.caption), + button: GoogleFonts.jura(textStyle: textTheme.button), + overline: GoogleFonts.jura(textStyle: textTheme.overline), + ); + } + + /// Applies the Just Another Hand font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Just+Another+Hand + static TextStyle justAnotherHand({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a03840122f7580fc7dfc0c3371d5450fd3b1c04f891bcc1e86780354e7c53d4', + 164136, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JustAnotherHand', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Just Another Hand font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Just+Another+Hand + static TextTheme justAnotherHandTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.justAnotherHand(textStyle: textTheme.headline1), + headline2: GoogleFonts.justAnotherHand(textStyle: textTheme.headline2), + headline3: GoogleFonts.justAnotherHand(textStyle: textTheme.headline3), + headline4: GoogleFonts.justAnotherHand(textStyle: textTheme.headline4), + headline5: GoogleFonts.justAnotherHand(textStyle: textTheme.headline5), + headline6: GoogleFonts.justAnotherHand(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.justAnotherHand(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.justAnotherHand(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.justAnotherHand(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.justAnotherHand(textStyle: textTheme.bodyText2), + caption: GoogleFonts.justAnotherHand(textStyle: textTheme.caption), + button: GoogleFonts.justAnotherHand(textStyle: textTheme.button), + overline: GoogleFonts.justAnotherHand(textStyle: textTheme.overline), + ); + } + + /// Applies the Just Me Again Down Here font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Just+Me+Again+Down+Here + static TextStyle justMeAgainDownHere({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fc0ac5f253850191002f529e5fd66829627682a2f9740fe0345a4bb339da7438', + 52984, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'JustMeAgainDownHere', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Just Me Again Down Here font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Just+Me+Again+Down+Here + static TextTheme justMeAgainDownHereTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.headline1), + headline2: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.headline2), + headline3: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.headline3), + headline4: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.headline4), + headline5: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.headline5), + headline6: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.justMeAgainDownHere(textStyle: textTheme.bodyText2), + caption: GoogleFonts.justMeAgainDownHere(textStyle: textTheme.caption), + button: GoogleFonts.justMeAgainDownHere(textStyle: textTheme.button), + overline: GoogleFonts.justMeAgainDownHere(textStyle: textTheme.overline), + ); + } + + /// Applies the K2D font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/K2D + static TextStyle k2d({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd221fa3a362d33d180e193b479bfddbf9e8ab02b545540d3a80121af669090de', + 90864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2ee77370590db6101099fae848e5f0e4fad425bcb6a8bb711390100587eacf49', + 94760, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '84c5594915b66f9cd68b4acb3820acdf5be79979f881f4edbece711c1a63d0cd', + 90688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '989bf534f4958d0d4655079703f5c6788e8cd7b1add81d08a1de93c354d69c1c', + 94820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bad065e1eeca31036e60587a4472530b8db84eb93149d94f2b687a28c8b0af39', + 90728, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1696fa34076cad6a8c919ffbe3247882c29a281086a573ddb8abc0c175794aed', + 94808, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ebd6d32612d7badd90f78a25b0a45e1573bcbd0b93954b702d17188d178d9e87', + 90976, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd7dc126127f8fcfeda097e5da4a1097f60e396ed7c4696060eaa0da6f1727366', + 95068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '57c28cc8eae5e455cd2000ea358ed6be014ff9f0e69866e18a1e7b9c6345bce0', + 91356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '00dc6e342b171a8e55a277d83326c4612d8f176cd576ee5f666636b13fc4ca18', + 95456, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8ceb3795ff3e683d9c70a4d12f431d94434b2527d61dcc11d59f840bfd644a8a', + 91488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3bff6acc9a59d6af0e9d2b3170d55987d1c96e9bb88ff5c20be84053cdb0dd81', + 95596, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '42e6c8a5b79abf6121af3fc8777219f39b88045a96a42dfe628d28c2112a4e12', + 91500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3d449eedd3718213cee306d0dd007fccf31827c55aa2d25b3d14ca933471e53b', + 95704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8f35ce22ce957eeee7bffef62f142fb7bf751169767ad5ab73cd78ba6c135821', + 91496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2141bd5b98bac331831e687a2131f46a8d23093831953a533451e0081a54f6aa', + 95800, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'K2D', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the K2D font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/K2D + static TextTheme k2dTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.k2d(textStyle: textTheme.headline1), + headline2: GoogleFonts.k2d(textStyle: textTheme.headline2), + headline3: GoogleFonts.k2d(textStyle: textTheme.headline3), + headline4: GoogleFonts.k2d(textStyle: textTheme.headline4), + headline5: GoogleFonts.k2d(textStyle: textTheme.headline5), + headline6: GoogleFonts.k2d(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.k2d(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.k2d(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.k2d(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.k2d(textStyle: textTheme.bodyText2), + caption: GoogleFonts.k2d(textStyle: textTheme.caption), + button: GoogleFonts.k2d(textStyle: textTheme.button), + overline: GoogleFonts.k2d(textStyle: textTheme.overline), + ); + } + + /// Applies the Kadwa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kadwa + static TextStyle kadwa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5b5f18ab4eefeddcf41f6246b7bdc63d6971c57ff6d628b86fc955f8eacc2e01', + 216352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2355f2b7cea1ab51a7388a8586f175dbb411a58e530e26b1f86b5a62ca80faa2', + 208480, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kadwa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kadwa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kadwa + static TextTheme kadwaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kadwa(textStyle: textTheme.headline1), + headline2: GoogleFonts.kadwa(textStyle: textTheme.headline2), + headline3: GoogleFonts.kadwa(textStyle: textTheme.headline3), + headline4: GoogleFonts.kadwa(textStyle: textTheme.headline4), + headline5: GoogleFonts.kadwa(textStyle: textTheme.headline5), + headline6: GoogleFonts.kadwa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kadwa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kadwa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kadwa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kadwa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kadwa(textStyle: textTheme.caption), + button: GoogleFonts.kadwa(textStyle: textTheme.button), + overline: GoogleFonts.kadwa(textStyle: textTheme.overline), + ); + } + + /// Applies the Kalam font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kalam + static TextStyle kalam({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'acc410247649f3164d61952a81b88737fb56977ac409e4d5f35d960e3b13747a', + 220496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '546c956074b4cd1c7d9936a82b03a712ec46df693b5a0faa80d4233f6bc17d2c', + 220796, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd48470c951c546b15999abb42141211e85484cffff16ce7612d07676efb9d0d8', + 223060, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kalam', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kalam font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kalam + static TextTheme kalamTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kalam(textStyle: textTheme.headline1), + headline2: GoogleFonts.kalam(textStyle: textTheme.headline2), + headline3: GoogleFonts.kalam(textStyle: textTheme.headline3), + headline4: GoogleFonts.kalam(textStyle: textTheme.headline4), + headline5: GoogleFonts.kalam(textStyle: textTheme.headline5), + headline6: GoogleFonts.kalam(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kalam(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kalam(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kalam(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kalam(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kalam(textStyle: textTheme.caption), + button: GoogleFonts.kalam(textStyle: textTheme.button), + overline: GoogleFonts.kalam(textStyle: textTheme.overline), + ); + } + + /// Applies the Kameron font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kameron + static TextStyle kameron({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '31d4c66237b8a2353dcb28cc0c0fcf347f10cb20582071c7db1e3d2820bc9d29', + 39420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba1c38d9290bf8209d9ff96941f976a43f44f9bd3eee9b066349fe39d6a0eef6', + 40328, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kameron', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kameron font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kameron + static TextTheme kameronTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kameron(textStyle: textTheme.headline1), + headline2: GoogleFonts.kameron(textStyle: textTheme.headline2), + headline3: GoogleFonts.kameron(textStyle: textTheme.headline3), + headline4: GoogleFonts.kameron(textStyle: textTheme.headline4), + headline5: GoogleFonts.kameron(textStyle: textTheme.headline5), + headline6: GoogleFonts.kameron(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kameron(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kameron(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kameron(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kameron(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kameron(textStyle: textTheme.caption), + button: GoogleFonts.kameron(textStyle: textTheme.button), + overline: GoogleFonts.kameron(textStyle: textTheme.overline), + ); + } + + /// Applies the Kanit font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kanit + static TextStyle kanit({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ae2534d6b4ec69c677d8c2cf336e1ba3c802e9e316c028c99a8db43ebb63f70', + 91856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '07d136289c506d3788ccbfcdf9e764427270b557b1b601d925bf997d002827ff', + 101028, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5a7bd784e91a9a006ec021a5f891a29ac3d867878f998bb1c2d7cdeac7dcb6b2', + 91724, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4171f0d7fdb919ffe44d9fb9fcccb08610ca5646f6e1f258e62ebe1b237d40b7', + 101072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'af3df5dc97d26cade1367d07a411e2ce209ab130f0d0f22c73594f2f9488f231', + 91856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '684fbd0330c7997a7aa6d6b72454ed7dbcaab91d2c54be50157988c9669ff845', + 100884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7996f53043acf5b6c782024a9c21ccd0bbab714f137cba3f64a2108709df989b', + 91176, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9367b66fe82713a777016d80d74986e22f272688d4fa1a7aaa2e8d999d31b0d4', + 100492, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '696301b8ecd45c7227d2c5ff3a308bbf701b05428b121fa43523622416c87e12', + 90588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6dd4b995a1dde18512697195090fb6bee9d0f44b124e8deb55d8619204637957', + 99036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ccc6cb20ad4fe61a7cd12f4124476933985e5e8c105008bf5549dee46d671fcb', + 90688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5f81f4c0eae984a4ba6dec488b4b74c2b72db9871111ee3b595473a73be34d5b', + 99316, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9844297d29f6a9c9d97cfa435750cc2933cc8d47b30e9c380e080d665310aaad', + 89616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '84a74264e2a1b11040aa80b859501eb498938736938cc12e1838be482ca1681f', + 99564, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ac86afa00dd8b070dc0325ff6ee63daee98cd4004aacce60aab9a9f147d3151e', + 90344, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0d3cf6f6f9f8952c9fbffa0fba60279f3b0fee229b846a4ff1d127732642c3c8', + 99912, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '593120b5c1292664ccee5994d9936265b8372449097d70ce0cdc3737408f0c1f', + 89780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '887e5a2586587398cc15672b3f3fef3e35836150f74ff4c8f80a34895effe69a', + 119368, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kanit', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kanit font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kanit + static TextTheme kanitTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kanit(textStyle: textTheme.headline1), + headline2: GoogleFonts.kanit(textStyle: textTheme.headline2), + headline3: GoogleFonts.kanit(textStyle: textTheme.headline3), + headline4: GoogleFonts.kanit(textStyle: textTheme.headline4), + headline5: GoogleFonts.kanit(textStyle: textTheme.headline5), + headline6: GoogleFonts.kanit(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kanit(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kanit(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kanit(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kanit(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kanit(textStyle: textTheme.caption), + button: GoogleFonts.kanit(textStyle: textTheme.button), + overline: GoogleFonts.kanit(textStyle: textTheme.overline), + ); + } + + /// Applies the Kantumruy font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kantumruy + static TextStyle kantumruy({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b1d181333c6beb8df855376481f36dcaa1e27f9c6fe7ba0c990035a73aca6686', + 43484, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9b0483d5bc7f567f83bda10131a033929865349c666f585d4feaa69600a60802', + 42468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6e6b33a5b9d03c7ed3f4e94d9704262ca70dc513ac1f129964f79ccddba04e06', + 41952, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kantumruy', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kantumruy font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kantumruy + static TextTheme kantumruyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kantumruy(textStyle: textTheme.headline1), + headline2: GoogleFonts.kantumruy(textStyle: textTheme.headline2), + headline3: GoogleFonts.kantumruy(textStyle: textTheme.headline3), + headline4: GoogleFonts.kantumruy(textStyle: textTheme.headline4), + headline5: GoogleFonts.kantumruy(textStyle: textTheme.headline5), + headline6: GoogleFonts.kantumruy(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kantumruy(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kantumruy(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kantumruy(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kantumruy(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kantumruy(textStyle: textTheme.caption), + button: GoogleFonts.kantumruy(textStyle: textTheme.button), + overline: GoogleFonts.kantumruy(textStyle: textTheme.overline), + ); + } + + /// Applies the Karla font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Karla + static TextStyle karla({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6f59c39b7fe5470c4c19a0bd67174cb94cdbe2053382046ea00b00fbfd5008a7', + 16768, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8dfdedc9371e4b6c128ba66b488cc38a94142de7a6aec5633026651dbbe7fd50', + 18500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '60f1379da84423da4c84a9d3ad1a1293ce82daf3c8337c5f3d027e5e0aa892c3', + 17820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '11cdf8ae7a17fbd7e9d7e2b43ced2e092b6d3a77cd2846dbf42cf3d82ffcb5e8', + 18624, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Karla', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Karla font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Karla + static TextTheme karlaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.karla(textStyle: textTheme.headline1), + headline2: GoogleFonts.karla(textStyle: textTheme.headline2), + headline3: GoogleFonts.karla(textStyle: textTheme.headline3), + headline4: GoogleFonts.karla(textStyle: textTheme.headline4), + headline5: GoogleFonts.karla(textStyle: textTheme.headline5), + headline6: GoogleFonts.karla(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.karla(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.karla(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.karla(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.karla(textStyle: textTheme.bodyText2), + caption: GoogleFonts.karla(textStyle: textTheme.caption), + button: GoogleFonts.karla(textStyle: textTheme.button), + overline: GoogleFonts.karla(textStyle: textTheme.overline), + ); + } + + /// Applies the Karma font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Karma + static TextStyle karma({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3efd1dc089cbb099173fc03a8bfc22d406db0671888af830ca7137e548369989', + 213140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8852b0f721a3603b10be618c6a5ad02f581025568b8db801a75130da5f0c8d48', + 213320, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2701feff031a171c4d982c100c27cf15d52d5051c49481762f43eeecc4bd54bd', + 212556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '932cd064de412606a66f2a06a29ed0003de9669fe26d7f1f9f3e76bfc74dbb78', + 213564, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '132e41c0f90df6a2646b59a685af793e0ce62b2b64245d2db081d1ab1f6889e8', + 214132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Karma', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Karma font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Karma + static TextTheme karmaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.karma(textStyle: textTheme.headline1), + headline2: GoogleFonts.karma(textStyle: textTheme.headline2), + headline3: GoogleFonts.karma(textStyle: textTheme.headline3), + headline4: GoogleFonts.karma(textStyle: textTheme.headline4), + headline5: GoogleFonts.karma(textStyle: textTheme.headline5), + headline6: GoogleFonts.karma(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.karma(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.karma(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.karma(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.karma(textStyle: textTheme.bodyText2), + caption: GoogleFonts.karma(textStyle: textTheme.caption), + button: GoogleFonts.karma(textStyle: textTheme.button), + overline: GoogleFonts.karma(textStyle: textTheme.overline), + ); + } + + /// Applies the Katibeh font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Katibeh + static TextStyle katibeh({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '16765d8ec4094a1fc5253399ebcf655c81c391de1a03f36d75059b0118e154a0', + 188360, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Katibeh', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Katibeh font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Katibeh + static TextTheme katibehTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.katibeh(textStyle: textTheme.headline1), + headline2: GoogleFonts.katibeh(textStyle: textTheme.headline2), + headline3: GoogleFonts.katibeh(textStyle: textTheme.headline3), + headline4: GoogleFonts.katibeh(textStyle: textTheme.headline4), + headline5: GoogleFonts.katibeh(textStyle: textTheme.headline5), + headline6: GoogleFonts.katibeh(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.katibeh(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.katibeh(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.katibeh(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.katibeh(textStyle: textTheme.bodyText2), + caption: GoogleFonts.katibeh(textStyle: textTheme.caption), + button: GoogleFonts.katibeh(textStyle: textTheme.button), + overline: GoogleFonts.katibeh(textStyle: textTheme.overline), + ); + } + + /// Applies the Kaushan Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kaushan+Script + static TextStyle kaushanScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a873f20587d6d9f0fc829b52f62b3d79665f806ca3062b6d5c14e6450e10c623', + 138340, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KaushanScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kaushan Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kaushan+Script + static TextTheme kaushanScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kaushanScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.kaushanScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.kaushanScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.kaushanScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.kaushanScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.kaushanScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kaushanScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kaushanScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kaushanScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kaushanScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kaushanScript(textStyle: textTheme.caption), + button: GoogleFonts.kaushanScript(textStyle: textTheme.button), + overline: GoogleFonts.kaushanScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Kavivanar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kavivanar + static TextStyle kavivanar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '18f829fa1d200c2774144c3fcc8eb4f393a7bf7e2c8e3d95ecf831dd96e498ae', + 66336, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kavivanar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kavivanar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kavivanar + static TextTheme kavivanarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kavivanar(textStyle: textTheme.headline1), + headline2: GoogleFonts.kavivanar(textStyle: textTheme.headline2), + headline3: GoogleFonts.kavivanar(textStyle: textTheme.headline3), + headline4: GoogleFonts.kavivanar(textStyle: textTheme.headline4), + headline5: GoogleFonts.kavivanar(textStyle: textTheme.headline5), + headline6: GoogleFonts.kavivanar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kavivanar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kavivanar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kavivanar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kavivanar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kavivanar(textStyle: textTheme.caption), + button: GoogleFonts.kavivanar(textStyle: textTheme.button), + overline: GoogleFonts.kavivanar(textStyle: textTheme.overline), + ); + } + + /// Applies the Kavoon font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kavoon + static TextStyle kavoon({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2c2328be5a827d790cddbe56db46b1c94043f473e5d01286be1567e454a4038d', + 52288, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kavoon', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kavoon font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kavoon + static TextTheme kavoonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kavoon(textStyle: textTheme.headline1), + headline2: GoogleFonts.kavoon(textStyle: textTheme.headline2), + headline3: GoogleFonts.kavoon(textStyle: textTheme.headline3), + headline4: GoogleFonts.kavoon(textStyle: textTheme.headline4), + headline5: GoogleFonts.kavoon(textStyle: textTheme.headline5), + headline6: GoogleFonts.kavoon(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kavoon(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kavoon(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kavoon(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kavoon(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kavoon(textStyle: textTheme.caption), + button: GoogleFonts.kavoon(textStyle: textTheme.button), + overline: GoogleFonts.kavoon(textStyle: textTheme.overline), + ); + } + + /// Applies the Kdam Thmor font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kdam+Thmor + static TextStyle kdamThmor({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9fc30fa8d328331e5132a7c7bf04cc803ada727681101c00dce2c9e84732f191', + 56332, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KdamThmor', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kdam Thmor font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kdam+Thmor + static TextTheme kdamThmorTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kdamThmor(textStyle: textTheme.headline1), + headline2: GoogleFonts.kdamThmor(textStyle: textTheme.headline2), + headline3: GoogleFonts.kdamThmor(textStyle: textTheme.headline3), + headline4: GoogleFonts.kdamThmor(textStyle: textTheme.headline4), + headline5: GoogleFonts.kdamThmor(textStyle: textTheme.headline5), + headline6: GoogleFonts.kdamThmor(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kdamThmor(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kdamThmor(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kdamThmor(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kdamThmor(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kdamThmor(textStyle: textTheme.caption), + button: GoogleFonts.kdamThmor(textStyle: textTheme.button), + overline: GoogleFonts.kdamThmor(textStyle: textTheme.overline), + ); + } + + /// Applies the Keania One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Keania+One + static TextStyle keaniaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '39c288c7a1580666e2ebb839a9df6cfb69104742879e8e61900550b02a4f9fb8', + 38764, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KeaniaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Keania One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Keania+One + static TextTheme keaniaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.keaniaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.keaniaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.keaniaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.keaniaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.keaniaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.keaniaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.keaniaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.keaniaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.keaniaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.keaniaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.keaniaOne(textStyle: textTheme.caption), + button: GoogleFonts.keaniaOne(textStyle: textTheme.button), + overline: GoogleFonts.keaniaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Kelly Slab font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kelly+Slab + static TextStyle kellySlab({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0e2083c69e8813f4eaba66f9dbe4960cd23ce5e098577997c4a3ae8d09c15c31', + 77792, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KellySlab', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kelly Slab font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kelly+Slab + static TextTheme kellySlabTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kellySlab(textStyle: textTheme.headline1), + headline2: GoogleFonts.kellySlab(textStyle: textTheme.headline2), + headline3: GoogleFonts.kellySlab(textStyle: textTheme.headline3), + headline4: GoogleFonts.kellySlab(textStyle: textTheme.headline4), + headline5: GoogleFonts.kellySlab(textStyle: textTheme.headline5), + headline6: GoogleFonts.kellySlab(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kellySlab(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kellySlab(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kellySlab(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kellySlab(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kellySlab(textStyle: textTheme.caption), + button: GoogleFonts.kellySlab(textStyle: textTheme.button), + overline: GoogleFonts.kellySlab(textStyle: textTheme.overline), + ); + } + + /// Applies the Kenia font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kenia + static TextStyle kenia({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '504cbb4c7a6888c5333bff718cde206f914f047b6247076cd4033f6457a2a9a6', + 39060, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kenia', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kenia font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kenia + static TextTheme keniaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kenia(textStyle: textTheme.headline1), + headline2: GoogleFonts.kenia(textStyle: textTheme.headline2), + headline3: GoogleFonts.kenia(textStyle: textTheme.headline3), + headline4: GoogleFonts.kenia(textStyle: textTheme.headline4), + headline5: GoogleFonts.kenia(textStyle: textTheme.headline5), + headline6: GoogleFonts.kenia(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kenia(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kenia(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kenia(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kenia(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kenia(textStyle: textTheme.caption), + button: GoogleFonts.kenia(textStyle: textTheme.button), + overline: GoogleFonts.kenia(textStyle: textTheme.overline), + ); + } + + /// Applies the Khand font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Khand + static TextStyle khand({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7cd4683a916646dd278fb0eb4426f6826ca4f0cc92ce083de087f2287fb11f98', + 168560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '325e1b6938310cd0385a917b47fcadabece70ea8fa6356a276e20fb171d57af5', + 168592, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6dd2785eedd866d3f7e329ad7264d66157ec7a40ef41d48aab098287b5a8863d', + 167652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2471269ec4d3228c379da2bc6e54db78b4c7b315613d0cd1e639539c7d92d75d', + 167892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '609dc9682e1321a8db6ab6a4caeffe07395b8517327ee5ce936b365e586fb402', + 167440, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Khand', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Khand font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Khand + static TextTheme khandTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.khand(textStyle: textTheme.headline1), + headline2: GoogleFonts.khand(textStyle: textTheme.headline2), + headline3: GoogleFonts.khand(textStyle: textTheme.headline3), + headline4: GoogleFonts.khand(textStyle: textTheme.headline4), + headline5: GoogleFonts.khand(textStyle: textTheme.headline5), + headline6: GoogleFonts.khand(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.khand(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.khand(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.khand(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.khand(textStyle: textTheme.bodyText2), + caption: GoogleFonts.khand(textStyle: textTheme.caption), + button: GoogleFonts.khand(textStyle: textTheme.button), + overline: GoogleFonts.khand(textStyle: textTheme.overline), + ); + } + + /// Applies the Khula font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Khula + static TextStyle khula({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '565c281fe5c11e451834dd30eda6e6d94a41c1a9c186c175541aa8ddef492d4f', + 103456, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '743e9de20b77192c80fd43452b591fcc85ef36aa1dd7746171503962b5687046', + 101668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'af7d4733894aa875443cf8921445981662df9f4f3ee13e8cc151dee7c9ca5dde', + 101652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f8536c085e0c982334e632c44c763535658fd643b50254fb20784b8f377a6231', + 101984, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '976ee869557699be72a4b83bbb3362cc7be7de27930b5b671210b69063a49d2f', + 103132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Khula', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Khula font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Khula + static TextTheme khulaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.khula(textStyle: textTheme.headline1), + headline2: GoogleFonts.khula(textStyle: textTheme.headline2), + headline3: GoogleFonts.khula(textStyle: textTheme.headline3), + headline4: GoogleFonts.khula(textStyle: textTheme.headline4), + headline5: GoogleFonts.khula(textStyle: textTheme.headline5), + headline6: GoogleFonts.khula(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.khula(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.khula(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.khula(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.khula(textStyle: textTheme.bodyText2), + caption: GoogleFonts.khula(textStyle: textTheme.caption), + button: GoogleFonts.khula(textStyle: textTheme.button), + overline: GoogleFonts.khula(textStyle: textTheme.overline), + ); + } + + /// Applies the Kirang Haerang font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kirang+Haerang + static TextStyle kirangHaerang({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '419ae98f0574b7c2a5b81ce99a859d0db9335d7be00145712bad1d7d8881abb1', + 3554608, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KirangHaerang', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kirang Haerang font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kirang+Haerang + static TextTheme kirangHaerangTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kirangHaerang(textStyle: textTheme.headline1), + headline2: GoogleFonts.kirangHaerang(textStyle: textTheme.headline2), + headline3: GoogleFonts.kirangHaerang(textStyle: textTheme.headline3), + headline4: GoogleFonts.kirangHaerang(textStyle: textTheme.headline4), + headline5: GoogleFonts.kirangHaerang(textStyle: textTheme.headline5), + headline6: GoogleFonts.kirangHaerang(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kirangHaerang(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kirangHaerang(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kirangHaerang(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kirangHaerang(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kirangHaerang(textStyle: textTheme.caption), + button: GoogleFonts.kirangHaerang(textStyle: textTheme.button), + overline: GoogleFonts.kirangHaerang(textStyle: textTheme.overline), + ); + } + + /// Applies the Kite One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kite+One + static TextStyle kiteOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '34684b654cf048f7030568588f753ee06c120f4d68ba9426e47995af21a6aa8b', + 37560, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KiteOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kite One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kite+One + static TextTheme kiteOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kiteOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.kiteOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.kiteOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.kiteOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.kiteOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.kiteOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kiteOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kiteOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kiteOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kiteOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kiteOne(textStyle: textTheme.caption), + button: GoogleFonts.kiteOne(textStyle: textTheme.button), + overline: GoogleFonts.kiteOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Knewave font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Knewave + static TextStyle knewave({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c3a13f54f0f82d09a1c116c40d693c4e9a6212437c8602f91acb88a205ea9fdc', + 32412, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Knewave', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Knewave font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Knewave + static TextTheme knewaveTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.knewave(textStyle: textTheme.headline1), + headline2: GoogleFonts.knewave(textStyle: textTheme.headline2), + headline3: GoogleFonts.knewave(textStyle: textTheme.headline3), + headline4: GoogleFonts.knewave(textStyle: textTheme.headline4), + headline5: GoogleFonts.knewave(textStyle: textTheme.headline5), + headline6: GoogleFonts.knewave(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.knewave(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.knewave(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.knewave(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.knewave(textStyle: textTheme.bodyText2), + caption: GoogleFonts.knewave(textStyle: textTheme.caption), + button: GoogleFonts.knewave(textStyle: textTheme.button), + overline: GoogleFonts.knewave(textStyle: textTheme.overline), + ); + } + + /// Applies the KoHo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/KoHo + static TextStyle koHo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7b4addbdb3d0cadc2f6c0149b90b29c059dc7f2be08d0b28292acb880db45124', + 86716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '73dd6271884581477beeb0860878fd6b524f3e880cc020295c24e2bf1d41a70c', + 90908, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '676e89293e4714a1c63fdd477c5dc88950461834031e2ea0437e65b31fc5a03a', + 86412, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5c2ce20516635678f4f67581782cd3c0429b8cf361e732c24021bc1711fc609e', + 90612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8128e00cc778e37cc7db7f518f22ca833399d8c4bdfac07fd1fd063435ba658', + 86204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3225382b5d36a6963f8d1cc5fb60086a657ecb39882bab5259eda483f292af57', + 90532, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '90a011adf31d93ee90f5e105dd20a7a69e7de53626672d10449e9bced87b5916', + 85892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cd0a466ebee7135ca6790a7908264c0457b65dbd9c927ec7082f43827d45f5d4', + 90208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7cf86562498ddfbbaa3a3b5d46e848407702a925472a4a3e76ab1ef1a7949106', + 85700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cd527fcf4a07b728233b2d93e0ef12477bf9988918e604f16fd823a15a2c3639', + 89800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c059ce850125c2f3bec60528a808fea56f6191b9b9bac380a4a38da9d2f42bfa', + 85128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '16a471d3f9b251d19034945ede1cd8c304c08caba74db67fc08e01556ec0e3b4', + 88844, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KoHo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the KoHo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/KoHo + static TextTheme koHoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.koHo(textStyle: textTheme.headline1), + headline2: GoogleFonts.koHo(textStyle: textTheme.headline2), + headline3: GoogleFonts.koHo(textStyle: textTheme.headline3), + headline4: GoogleFonts.koHo(textStyle: textTheme.headline4), + headline5: GoogleFonts.koHo(textStyle: textTheme.headline5), + headline6: GoogleFonts.koHo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.koHo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.koHo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.koHo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.koHo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.koHo(textStyle: textTheme.caption), + button: GoogleFonts.koHo(textStyle: textTheme.button), + overline: GoogleFonts.koHo(textStyle: textTheme.overline), + ); + } + + /// Applies the Kodchasan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kodchasan + static TextStyle kodchasan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2edcba243e7c1435577d6a15a666013f9b4f4db824a08ac150024e2000e4b7de', + 95536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6dabeb02077bcb1ee80b8aa519c66632dc2429a3cd60c6cabd5f91154288b103', + 99884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6eb43574315a2c2b393aa7ca05550b9b578bddd384857e454e5fbe82b515bfea', + 96716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fb557cb4f6efc30f933535fb5248e6730fbdcd42302a4b7ee4a58357d71aa0a9', + 100924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eeae77f326fa242ac959bdcb27637f93f6ca476033b7d1e36f106cd40c510317', + 96988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ec040aba86add77fe833d612e33ecb85ef59b26b83c92a86771db7e3f11a8f55', + 101700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25d7924da481a4595e389025f7a5d21b4bdcc49e7e9766bcdb939f3fe48a3f11', + 97288, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '86198a3feb862a0d1abbba874238ef724e7f0e39221baf31690c24d363b75c52', + 102088, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fa4d9b59366b50f70d33afeb164cee9a13230055602bfdd410ceba9ec9c94132', + 97376, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bcc4ef0fab22eb3e1e2ef611c53721b1d133ddc5ae972a8e978c4b8024b6aa30', + 102560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7df1e9c701a40ce05b3d8a4189480e045deff521a283218f2094f2cbbc434e17', + 97212, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '37e6fe167fcb53ce25beebb7983c99d3fb3831d1891cb10d36bdffdcc9bef707', + 102668, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kodchasan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kodchasan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kodchasan + static TextTheme kodchasanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kodchasan(textStyle: textTheme.headline1), + headline2: GoogleFonts.kodchasan(textStyle: textTheme.headline2), + headline3: GoogleFonts.kodchasan(textStyle: textTheme.headline3), + headline4: GoogleFonts.kodchasan(textStyle: textTheme.headline4), + headline5: GoogleFonts.kodchasan(textStyle: textTheme.headline5), + headline6: GoogleFonts.kodchasan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kodchasan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kodchasan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kodchasan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kodchasan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kodchasan(textStyle: textTheme.caption), + button: GoogleFonts.kodchasan(textStyle: textTheme.button), + overline: GoogleFonts.kodchasan(textStyle: textTheme.overline), + ); + } + + /// Applies the Kosugi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kosugi + static TextStyle kosugi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '100d52cf4a5ea4cf706199b6573e20b6963747dbf39a6fa2bd5eace488da7cfa', + 1918404, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kosugi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kosugi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kosugi + static TextTheme kosugiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kosugi(textStyle: textTheme.headline1), + headline2: GoogleFonts.kosugi(textStyle: textTheme.headline2), + headline3: GoogleFonts.kosugi(textStyle: textTheme.headline3), + headline4: GoogleFonts.kosugi(textStyle: textTheme.headline4), + headline5: GoogleFonts.kosugi(textStyle: textTheme.headline5), + headline6: GoogleFonts.kosugi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kosugi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kosugi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kosugi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kosugi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kosugi(textStyle: textTheme.caption), + button: GoogleFonts.kosugi(textStyle: textTheme.button), + overline: GoogleFonts.kosugi(textStyle: textTheme.overline), + ); + } + + /// Applies the Kosugi Maru font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kosugi+Maru + static TextStyle kosugiMaru({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9fbe25d62fc496dd41c965a6a410bcb248978277da1dedd4682e2b1d72c4ade9', + 2558132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KosugiMaru', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kosugi Maru font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kosugi+Maru + static TextTheme kosugiMaruTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kosugiMaru(textStyle: textTheme.headline1), + headline2: GoogleFonts.kosugiMaru(textStyle: textTheme.headline2), + headline3: GoogleFonts.kosugiMaru(textStyle: textTheme.headline3), + headline4: GoogleFonts.kosugiMaru(textStyle: textTheme.headline4), + headline5: GoogleFonts.kosugiMaru(textStyle: textTheme.headline5), + headline6: GoogleFonts.kosugiMaru(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kosugiMaru(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kosugiMaru(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kosugiMaru(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kosugiMaru(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kosugiMaru(textStyle: textTheme.caption), + button: GoogleFonts.kosugiMaru(textStyle: textTheme.button), + overline: GoogleFonts.kosugiMaru(textStyle: textTheme.overline), + ); + } + + /// Applies the Kotta One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kotta+One + static TextStyle kottaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0d0a0a70c6c66af4f55948fe817266bdb57b4ac8de0a0fe31f41350ccb139a41', + 36576, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KottaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kotta One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kotta+One + static TextTheme kottaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kottaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.kottaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.kottaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.kottaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.kottaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.kottaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kottaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kottaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kottaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kottaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kottaOne(textStyle: textTheme.caption), + button: GoogleFonts.kottaOne(textStyle: textTheme.button), + overline: GoogleFonts.kottaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Kranky font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kranky + static TextStyle kranky({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6ede337ff9d5b44d7958a35407098749494ddd69efd07cad00c906439794d962', + 198904, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kranky', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kranky font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kranky + static TextTheme krankyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kranky(textStyle: textTheme.headline1), + headline2: GoogleFonts.kranky(textStyle: textTheme.headline2), + headline3: GoogleFonts.kranky(textStyle: textTheme.headline3), + headline4: GoogleFonts.kranky(textStyle: textTheme.headline4), + headline5: GoogleFonts.kranky(textStyle: textTheme.headline5), + headline6: GoogleFonts.kranky(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kranky(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kranky(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kranky(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kranky(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kranky(textStyle: textTheme.caption), + button: GoogleFonts.kranky(textStyle: textTheme.button), + overline: GoogleFonts.kranky(textStyle: textTheme.overline), + ); + } + + /// Applies the Kreon font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kreon + static TextStyle kreon({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '988fb49f563aec3452b26437e4cef99cd52bf368c5fb6c30e7b9e1419e4a3723', + 37016, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '95de76c3d8f95714fbfda4a89b6cf0b74a4285d9d0f81908cbd91c7146109d83', + 36852, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d9092c90a6173026afefda0a94456688b33166363b733d8d42200e68837b012', + 37648, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kreon', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kreon font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kreon + static TextTheme kreonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kreon(textStyle: textTheme.headline1), + headline2: GoogleFonts.kreon(textStyle: textTheme.headline2), + headline3: GoogleFonts.kreon(textStyle: textTheme.headline3), + headline4: GoogleFonts.kreon(textStyle: textTheme.headline4), + headline5: GoogleFonts.kreon(textStyle: textTheme.headline5), + headline6: GoogleFonts.kreon(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kreon(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kreon(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kreon(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kreon(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kreon(textStyle: textTheme.caption), + button: GoogleFonts.kreon(textStyle: textTheme.button), + overline: GoogleFonts.kreon(textStyle: textTheme.overline), + ); + } + + /// Applies the Kristi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kristi + static TextStyle kristi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6769ae6a5019b65b4c320170421385429bc0ab627affdc0b481ad8b7f7e2814b', + 26988, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kristi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kristi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kristi + static TextTheme kristiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kristi(textStyle: textTheme.headline1), + headline2: GoogleFonts.kristi(textStyle: textTheme.headline2), + headline3: GoogleFonts.kristi(textStyle: textTheme.headline3), + headline4: GoogleFonts.kristi(textStyle: textTheme.headline4), + headline5: GoogleFonts.kristi(textStyle: textTheme.headline5), + headline6: GoogleFonts.kristi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kristi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kristi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kristi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kristi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kristi(textStyle: textTheme.caption), + button: GoogleFonts.kristi(textStyle: textTheme.button), + overline: GoogleFonts.kristi(textStyle: textTheme.overline), + ); + } + + /// Applies the Krona One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Krona+One + static TextStyle kronaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c3051123d5b341e07e0a0c83f46022f8c16edd2373a7405e1857ddbf3ac95132', + 35168, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KronaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Krona One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Krona+One + static TextTheme kronaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kronaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.kronaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.kronaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.kronaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.kronaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.kronaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kronaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kronaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kronaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kronaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kronaOne(textStyle: textTheme.caption), + button: GoogleFonts.kronaOne(textStyle: textTheme.button), + overline: GoogleFonts.kronaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Krub font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Krub + static TextStyle krub({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e99da9729e8beb706a3f7dd95ff2b13b7e33f89ceabaf9f2330e61896b93fa39', + 81664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '63f21c0600aea197624e3d1c2e40daafe5eabdfd3f3b604ef5a0240158275df3', + 84648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c051f20fb436fad0503f887fa3835d2787be9ae5fbe5be539dc1532d24f8df2f', + 81100, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e7745d1a884ad74618766af351077c4625adf1e3ba22d4d86f3aa7cf49306b98', + 83988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd0e841ab6bf1b00cdeb73777db2ee1a1cfa53adda512b49fbd12511e8fd15169', + 80988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9e23fec650c8fabcf0ecb628c198acb3c2a8cc928f9ab5814f5eafa81c9ceeaa', + 84040, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2964f338dadae9da331e3cb292ca6fa5a8fe4eb8267fc4846b40115fbb645f2b', + 80900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'defa6560ee637da7a34fda9c66033c4a5465e3bc8b92a02da190b58dfdd71ad6', + 83856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6f875531446bca4ea9d68ff550096ba0371fb5c0b8fa84667d9de385848b424e', + 80800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'af1dcba5de7428e1ddd0d849ddffc16f048518210fefe8a98bf21ff22234b3f1', + 83792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '066231a170b822e951eb201a38fd17e6a13d82773be17af5e9b184928e32c6c7', + 80756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bb202066513c0b7b93b2e8552d17feeaf2580daa45fdf8e88f3e98205ca2342e', + 83796, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Krub', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Krub font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Krub + static TextTheme krubTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.krub(textStyle: textTheme.headline1), + headline2: GoogleFonts.krub(textStyle: textTheme.headline2), + headline3: GoogleFonts.krub(textStyle: textTheme.headline3), + headline4: GoogleFonts.krub(textStyle: textTheme.headline4), + headline5: GoogleFonts.krub(textStyle: textTheme.headline5), + headline6: GoogleFonts.krub(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.krub(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.krub(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.krub(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.krub(textStyle: textTheme.bodyText2), + caption: GoogleFonts.krub(textStyle: textTheme.caption), + button: GoogleFonts.krub(textStyle: textTheme.button), + overline: GoogleFonts.krub(textStyle: textTheme.overline), + ); + } + + /// Applies the Kufam font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kufam + static TextStyle kufam({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5c2bb31f9dd171bed88ba502db12721774a13319071394e56e851504328cced1', + 141620, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '628f6fa7084fc9014fba2e3c27aba50a901a708970eb6979b3fda1ec867cc2ba', + 141724, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '26c69927ca903d5e5ddedc392efcbf0623458d9d352cb29d93560e14a9091a15', + 141764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '18dcfedf39aa5d3740934b3acb3353f04a783bd3837cc96274c8d41714c10959', + 141772, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '80506455dc52f96e1c01dc03895ffd7b6acb1f00e8f25fe7e31f9f23ecd11b5e', + 141780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91956312f9838b7521ffc47c1f995a3e8dab1db5066c4a0c795bb0859bae2d3c', + 141636, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1fb37298bd90094fe92ba44840e627b41bfd6e6efb0815463dd4d930f5c1147a', + 73236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8d94116c2e09feac74f75c363668984bebf577bf9b7ca8536389327c3307d3f5', + 73392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'acba03eb543ba4c89ad5147f7e9e38a08359468fd5207a25654c7ac769fc4f74', + 73420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c905cb847568b45ec8c0e52155436db8588c324545088a9152d3e65b0cec2cf9', + 73292, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '65a1ad9ba5604756d5e0cc9e15ad2e96b5eca8118c8686f1b7a60b10853a0d84', + 73356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3d2ee6303973ef6ff89e5b07b8ee5193f461009ed343aea533496c3c5e2f3f15', + 73304, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kufam', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kufam font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kufam + static TextTheme kufamTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kufam(textStyle: textTheme.headline1), + headline2: GoogleFonts.kufam(textStyle: textTheme.headline2), + headline3: GoogleFonts.kufam(textStyle: textTheme.headline3), + headline4: GoogleFonts.kufam(textStyle: textTheme.headline4), + headline5: GoogleFonts.kufam(textStyle: textTheme.headline5), + headline6: GoogleFonts.kufam(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kufam(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kufam(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kufam(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kufam(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kufam(textStyle: textTheme.caption), + button: GoogleFonts.kufam(textStyle: textTheme.button), + overline: GoogleFonts.kufam(textStyle: textTheme.overline), + ); + } + + /// Applies the Kulim Park font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kulim+Park + static TextStyle kulimPark({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '840c4d3989e45ba899e1b3d09646ca3f9bef766fb66b167c5ea95b0726f44a0b', + 42840, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8737e36ff5a77edc8d6596fcaa803b3cf72b11b077e0b7b0397fa81c2f03dd31', + 44900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5f528827be704c4d4f91d75915cedac8ff4754733bcac2e61e48bdac1e6752eb', + 43988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '62e148954a2bd0e9e8c26272bfc3eedaaeecdf3a318ade20223eb51d2b83abdb', + 45800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd2dc8ced6a590e1bfbabfeaf4b27a7366fccc572cfee1fe459f22618ab3f1e58', + 43976, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd3d40eaa8f0ae675fa6895c58f65a5c082236f54ee433a53963584e3f308f7c8', + 45616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cea3878ffef1244f27d1495beb506d10f3206d59da7d09f737ac355fde66784e', + 43876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '62a7e064a37929edd5a709ff870cd8bafcf530cd6439f26277ab061d4128a8ad', + 45616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '23e77b347e0afbacac1a4ba530b6fc6e0a7e166bd3edf29bdc414dd6497b806d', + 43444, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'baa22986aa8baf32baf6fbbd27e630ee792aac59cbf10df4701f9cd85d3232cd', + 45424, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KulimPark', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kulim Park font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kulim+Park + static TextTheme kulimParkTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kulimPark(textStyle: textTheme.headline1), + headline2: GoogleFonts.kulimPark(textStyle: textTheme.headline2), + headline3: GoogleFonts.kulimPark(textStyle: textTheme.headline3), + headline4: GoogleFonts.kulimPark(textStyle: textTheme.headline4), + headline5: GoogleFonts.kulimPark(textStyle: textTheme.headline5), + headline6: GoogleFonts.kulimPark(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kulimPark(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kulimPark(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kulimPark(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kulimPark(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kulimPark(textStyle: textTheme.caption), + button: GoogleFonts.kulimPark(textStyle: textTheme.button), + overline: GoogleFonts.kulimPark(textStyle: textTheme.overline), + ); + } + + /// Applies the Kumar One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kumar+One + static TextStyle kumarOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7aa5fb44eb6e2f7f5a30bf8ae90da684a6d448b161974422dee1109dcdb3cab', + 94132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KumarOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kumar One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kumar+One + static TextTheme kumarOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kumarOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.kumarOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.kumarOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.kumarOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.kumarOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.kumarOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kumarOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kumarOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kumarOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kumarOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kumarOne(textStyle: textTheme.caption), + button: GoogleFonts.kumarOne(textStyle: textTheme.button), + overline: GoogleFonts.kumarOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Kumar One Outline font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kumar+One+Outline + static TextStyle kumarOneOutline({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b69d95adfdc90ffb8852e1828c7d227219b5374737613f23a88cfbb02439e915', + 127824, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KumarOneOutline', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kumar One Outline font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kumar+One+Outline + static TextTheme kumarOneOutlineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kumarOneOutline(textStyle: textTheme.headline1), + headline2: GoogleFonts.kumarOneOutline(textStyle: textTheme.headline2), + headline3: GoogleFonts.kumarOneOutline(textStyle: textTheme.headline3), + headline4: GoogleFonts.kumarOneOutline(textStyle: textTheme.headline4), + headline5: GoogleFonts.kumarOneOutline(textStyle: textTheme.headline5), + headline6: GoogleFonts.kumarOneOutline(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kumarOneOutline(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kumarOneOutline(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kumarOneOutline(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kumarOneOutline(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kumarOneOutline(textStyle: textTheme.caption), + button: GoogleFonts.kumarOneOutline(textStyle: textTheme.button), + overline: GoogleFonts.kumarOneOutline(textStyle: textTheme.overline), + ); + } + + /// Applies the Kumbh Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kumbh+Sans + static TextStyle kumbhSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '43966dbbdeb9f3181e27f1b0dd5f376b20aeae923063baf51cdf00f5a5824b86', + 29836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cd7e6e35c2af2000577cd756754e4bf710f2fb83ecb7bd9c2252d606f4692770', + 39632, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c164b10128145b6c5fe70f3178d4723c7e6c0c73a40c2a529441dbbe775c61d3', + 33032, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'KumbhSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kumbh Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kumbh+Sans + static TextTheme kumbhSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kumbhSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.kumbhSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.kumbhSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.kumbhSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.kumbhSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.kumbhSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kumbhSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kumbhSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kumbhSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kumbhSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kumbhSans(textStyle: textTheme.caption), + button: GoogleFonts.kumbhSans(textStyle: textTheme.button), + overline: GoogleFonts.kumbhSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Kurale font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kurale + static TextStyle kurale({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dfcb85ac1c2a3ca188df6595b0099ece1a830475577e1897d491f575e6746e56', + 164312, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Kurale', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Kurale font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Kurale + static TextTheme kuraleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.kurale(textStyle: textTheme.headline1), + headline2: GoogleFonts.kurale(textStyle: textTheme.headline2), + headline3: GoogleFonts.kurale(textStyle: textTheme.headline3), + headline4: GoogleFonts.kurale(textStyle: textTheme.headline4), + headline5: GoogleFonts.kurale(textStyle: textTheme.headline5), + headline6: GoogleFonts.kurale(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.kurale(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.kurale(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.kurale(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.kurale(textStyle: textTheme.bodyText2), + caption: GoogleFonts.kurale(textStyle: textTheme.caption), + button: GoogleFonts.kurale(textStyle: textTheme.button), + overline: GoogleFonts.kurale(textStyle: textTheme.overline), + ); + } + + /// Applies the La Belle Aurore font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/La+Belle+Aurore + static TextStyle laBelleAurore({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '604ab650c1e1ab2e45459ba2bc1302e120467025e2f3a9946978bb7e7e0d03a3', + 58692, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LaBelleAurore', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the La Belle Aurore font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/La+Belle+Aurore + static TextTheme laBelleAuroreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.laBelleAurore(textStyle: textTheme.headline1), + headline2: GoogleFonts.laBelleAurore(textStyle: textTheme.headline2), + headline3: GoogleFonts.laBelleAurore(textStyle: textTheme.headline3), + headline4: GoogleFonts.laBelleAurore(textStyle: textTheme.headline4), + headline5: GoogleFonts.laBelleAurore(textStyle: textTheme.headline5), + headline6: GoogleFonts.laBelleAurore(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.laBelleAurore(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.laBelleAurore(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.laBelleAurore(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.laBelleAurore(textStyle: textTheme.bodyText2), + caption: GoogleFonts.laBelleAurore(textStyle: textTheme.caption), + button: GoogleFonts.laBelleAurore(textStyle: textTheme.button), + overline: GoogleFonts.laBelleAurore(textStyle: textTheme.overline), + ); + } + + /// Applies the Lacquer font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lacquer + static TextStyle lacquer({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d33d0518b8cf4ae8d6149c8bc8e7e19ced4124d6b80d47934fd4e7897cda55a', + 203048, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lacquer', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lacquer font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lacquer + static TextTheme lacquerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lacquer(textStyle: textTheme.headline1), + headline2: GoogleFonts.lacquer(textStyle: textTheme.headline2), + headline3: GoogleFonts.lacquer(textStyle: textTheme.headline3), + headline4: GoogleFonts.lacquer(textStyle: textTheme.headline4), + headline5: GoogleFonts.lacquer(textStyle: textTheme.headline5), + headline6: GoogleFonts.lacquer(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lacquer(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lacquer(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lacquer(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lacquer(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lacquer(textStyle: textTheme.caption), + button: GoogleFonts.lacquer(textStyle: textTheme.button), + overline: GoogleFonts.lacquer(textStyle: textTheme.overline), + ); + } + + /// Applies the Laila font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Laila + static TextStyle laila({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8aac335fe109f453ca82438785143a3d54ca6b5860f929a066015b366dd23603', + 203036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba573905733e8e1ec12baa194825add1cb80997c3c08b032d6439d524eef298a', + 203952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '445309cf766b79874168d66f2dc2f5eb067c865989ed496a8e2389411de9e18b', + 202320, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f393a4935161c1ac8a55a20d2a1107e698de003ace696ae5c6db50c7bf8c0781', + 202264, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a2cfeefaeb650171ed23e31b4fe85b7c5b8605f36e351821ffd3a351aeec6c17', + 201144, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Laila', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Laila font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Laila + static TextTheme lailaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.laila(textStyle: textTheme.headline1), + headline2: GoogleFonts.laila(textStyle: textTheme.headline2), + headline3: GoogleFonts.laila(textStyle: textTheme.headline3), + headline4: GoogleFonts.laila(textStyle: textTheme.headline4), + headline5: GoogleFonts.laila(textStyle: textTheme.headline5), + headline6: GoogleFonts.laila(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.laila(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.laila(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.laila(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.laila(textStyle: textTheme.bodyText2), + caption: GoogleFonts.laila(textStyle: textTheme.caption), + button: GoogleFonts.laila(textStyle: textTheme.button), + overline: GoogleFonts.laila(textStyle: textTheme.overline), + ); + } + + /// Applies the Lakki Reddy font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lakki+Reddy + static TextStyle lakkiReddy({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7517025d73568d9d811b25e8c5ef20a9f9d94bb816d4f334668f3c2d2830d079', + 379840, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LakkiReddy', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lakki Reddy font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lakki+Reddy + static TextTheme lakkiReddyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lakkiReddy(textStyle: textTheme.headline1), + headline2: GoogleFonts.lakkiReddy(textStyle: textTheme.headline2), + headline3: GoogleFonts.lakkiReddy(textStyle: textTheme.headline3), + headline4: GoogleFonts.lakkiReddy(textStyle: textTheme.headline4), + headline5: GoogleFonts.lakkiReddy(textStyle: textTheme.headline5), + headline6: GoogleFonts.lakkiReddy(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lakkiReddy(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lakkiReddy(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lakkiReddy(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lakkiReddy(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lakkiReddy(textStyle: textTheme.caption), + button: GoogleFonts.lakkiReddy(textStyle: textTheme.button), + overline: GoogleFonts.lakkiReddy(textStyle: textTheme.overline), + ); + } + + /// Applies the Lalezar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lalezar + static TextStyle lalezar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4fb2ddb0068e2bc905effaccf71a86ff357486d6a30804cd2e1a8109d0f165fc', + 190024, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lalezar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lalezar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lalezar + static TextTheme lalezarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lalezar(textStyle: textTheme.headline1), + headline2: GoogleFonts.lalezar(textStyle: textTheme.headline2), + headline3: GoogleFonts.lalezar(textStyle: textTheme.headline3), + headline4: GoogleFonts.lalezar(textStyle: textTheme.headline4), + headline5: GoogleFonts.lalezar(textStyle: textTheme.headline5), + headline6: GoogleFonts.lalezar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lalezar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lalezar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lalezar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lalezar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lalezar(textStyle: textTheme.caption), + button: GoogleFonts.lalezar(textStyle: textTheme.button), + overline: GoogleFonts.lalezar(textStyle: textTheme.overline), + ); + } + + /// Applies the Lancelot font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lancelot + static TextStyle lancelot({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a717264fe5246a5aae3c8706eb7368a7a36008880de093d205dadca67f8cfc97', + 30668, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lancelot', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lancelot font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lancelot + static TextTheme lancelotTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lancelot(textStyle: textTheme.headline1), + headline2: GoogleFonts.lancelot(textStyle: textTheme.headline2), + headline3: GoogleFonts.lancelot(textStyle: textTheme.headline3), + headline4: GoogleFonts.lancelot(textStyle: textTheme.headline4), + headline5: GoogleFonts.lancelot(textStyle: textTheme.headline5), + headline6: GoogleFonts.lancelot(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lancelot(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lancelot(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lancelot(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lancelot(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lancelot(textStyle: textTheme.caption), + button: GoogleFonts.lancelot(textStyle: textTheme.button), + overline: GoogleFonts.lancelot(textStyle: textTheme.overline), + ); + } + + /// Applies the Langar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Langar + static TextStyle langar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3d494b520a215cbab3c0c1e50463bfebb2e00da8370f5ea578b2c88e43ea824d', + 137468, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Langar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Langar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Langar + static TextTheme langarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.langar(textStyle: textTheme.headline1), + headline2: GoogleFonts.langar(textStyle: textTheme.headline2), + headline3: GoogleFonts.langar(textStyle: textTheme.headline3), + headline4: GoogleFonts.langar(textStyle: textTheme.headline4), + headline5: GoogleFonts.langar(textStyle: textTheme.headline5), + headline6: GoogleFonts.langar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.langar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.langar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.langar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.langar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.langar(textStyle: textTheme.caption), + button: GoogleFonts.langar(textStyle: textTheme.button), + overline: GoogleFonts.langar(textStyle: textTheme.overline), + ); + } + + /// Applies the Lateef font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lateef + static TextStyle lateef({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'db6ed59fb822daefac366cd24ad8a0d2b7d9bf35e1ea45490ab50b3f50b0de88', + 172748, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lateef', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lateef font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lateef + static TextTheme lateefTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lateef(textStyle: textTheme.headline1), + headline2: GoogleFonts.lateef(textStyle: textTheme.headline2), + headline3: GoogleFonts.lateef(textStyle: textTheme.headline3), + headline4: GoogleFonts.lateef(textStyle: textTheme.headline4), + headline5: GoogleFonts.lateef(textStyle: textTheme.headline5), + headline6: GoogleFonts.lateef(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lateef(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lateef(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lateef(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lateef(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lateef(textStyle: textTheme.caption), + button: GoogleFonts.lateef(textStyle: textTheme.button), + overline: GoogleFonts.lateef(textStyle: textTheme.overline), + ); + } + + /// Applies the Lato font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lato + static TextStyle lato({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2e734a39ad0b4a1dffd327f552cce678e867791007200be49b6a93a6c7c71b27', + 83268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '00d4076b836620336e608f16588994045e53f8aca14d9e430205db56649a8a55', + 78920, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9b25850654f3dd59daf526a3d63dcca1c435e231c9fa2dd949ccde9cea994366', + 80608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4cf23877950718d8775e526ee06380072a1bba6692d47bb5fb623fefb650b74b', + 79388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a649aaf21573a59079c46db19314fd95648f531e610fa932101f2705616b2882', + 80676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '484dd58cc095656f129f756067ede55183de20d70a6260c22ac747ed583672d6', + 79376, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '407592da08cb1f6060fbc69262ad33edd0b61ec9160521455eca8f726bbd4353', + 84716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6449b474d050304983a9431099406936e7f6978e22025a4a5ff8533871529bba', + 79536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'abae7ec6de16f8108f1a3e1e3dc9edf11c5903ab89b3513821f4e079a51ae175', + 81116, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '60407472b091a98e26c61f47900329eb3f971651fa76edc26d9f32f87e27f13f', + 76532, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lato', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lato font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lato + static TextTheme latoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lato(textStyle: textTheme.headline1), + headline2: GoogleFonts.lato(textStyle: textTheme.headline2), + headline3: GoogleFonts.lato(textStyle: textTheme.headline3), + headline4: GoogleFonts.lato(textStyle: textTheme.headline4), + headline5: GoogleFonts.lato(textStyle: textTheme.headline5), + headline6: GoogleFonts.lato(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lato(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lato(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lato(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lato(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lato(textStyle: textTheme.caption), + button: GoogleFonts.lato(textStyle: textTheme.button), + overline: GoogleFonts.lato(textStyle: textTheme.overline), + ); + } + + /// Applies the League Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/League+Script + static TextStyle leagueScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ffa526d6dea17c40fade9bfb691be36a5db63e9da4a760462b7df5dce51f4e51', + 51724, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LeagueScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the League Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/League+Script + static TextTheme leagueScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.leagueScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.leagueScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.leagueScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.leagueScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.leagueScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.leagueScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.leagueScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.leagueScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.leagueScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.leagueScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.leagueScript(textStyle: textTheme.caption), + button: GoogleFonts.leagueScript(textStyle: textTheme.button), + overline: GoogleFonts.leagueScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Leckerli One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Leckerli+One + static TextStyle leckerliOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4f4b119a522d79aaa310d37682ccbfd758366df5ab6009b1bd0ff022a5405a5f', + 43164, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LeckerliOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Leckerli One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Leckerli+One + static TextTheme leckerliOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.leckerliOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.leckerliOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.leckerliOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.leckerliOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.leckerliOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.leckerliOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.leckerliOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.leckerliOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.leckerliOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.leckerliOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.leckerliOne(textStyle: textTheme.caption), + button: GoogleFonts.leckerliOne(textStyle: textTheme.button), + overline: GoogleFonts.leckerliOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Ledger font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ledger + static TextStyle ledger({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3d3e17668a2b5762ca671d8a2496ba50de6e3896eaada54fa3f74ad82f0daf43', + 62272, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ledger', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ledger font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ledger + static TextTheme ledgerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ledger(textStyle: textTheme.headline1), + headline2: GoogleFonts.ledger(textStyle: textTheme.headline2), + headline3: GoogleFonts.ledger(textStyle: textTheme.headline3), + headline4: GoogleFonts.ledger(textStyle: textTheme.headline4), + headline5: GoogleFonts.ledger(textStyle: textTheme.headline5), + headline6: GoogleFonts.ledger(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ledger(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ledger(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ledger(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ledger(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ledger(textStyle: textTheme.caption), + button: GoogleFonts.ledger(textStyle: textTheme.button), + overline: GoogleFonts.ledger(textStyle: textTheme.overline), + ); + } + + /// Applies the Lekton font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lekton + static TextStyle lekton({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '919f93dff330901c348455426b31bc6ad6270b29b4527387ab2f16ae1a8b1b37', + 114272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5bdc665e2f574f3cde6b0db13ba296956f6736f4277decf03a015151ca063072', + 34164, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '34d7bf522a1cd2ddb84bd57082d9651c5155029004a5a66c713dec61c865ab08', + 113636, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lekton', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lekton font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lekton + static TextTheme lektonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lekton(textStyle: textTheme.headline1), + headline2: GoogleFonts.lekton(textStyle: textTheme.headline2), + headline3: GoogleFonts.lekton(textStyle: textTheme.headline3), + headline4: GoogleFonts.lekton(textStyle: textTheme.headline4), + headline5: GoogleFonts.lekton(textStyle: textTheme.headline5), + headline6: GoogleFonts.lekton(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lekton(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lekton(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lekton(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lekton(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lekton(textStyle: textTheme.caption), + button: GoogleFonts.lekton(textStyle: textTheme.button), + overline: GoogleFonts.lekton(textStyle: textTheme.overline), + ); + } + + /// Applies the Lemon font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lemon + static TextStyle lemon({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '512e0e1aeb4008ca5b6b9a325a936751f306ba97d1a480fe76da5adfc1f404c8', + 34600, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lemon', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lemon font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lemon + static TextTheme lemonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lemon(textStyle: textTheme.headline1), + headline2: GoogleFonts.lemon(textStyle: textTheme.headline2), + headline3: GoogleFonts.lemon(textStyle: textTheme.headline3), + headline4: GoogleFonts.lemon(textStyle: textTheme.headline4), + headline5: GoogleFonts.lemon(textStyle: textTheme.headline5), + headline6: GoogleFonts.lemon(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lemon(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lemon(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lemon(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lemon(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lemon(textStyle: textTheme.caption), + button: GoogleFonts.lemon(textStyle: textTheme.button), + overline: GoogleFonts.lemon(textStyle: textTheme.overline), + ); + } + + /// Applies the Lemonada font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lemonada + static TextStyle lemonada({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cd1018b5355f76f3e9ff9d859172bbccef3a0e0bb0b6956ed913a2edba4e9673', + 101408, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6c9760a51ed4b78cf2a172836b2cbc10f540963fdcaf88ef76d10cd4559ee07e', + 101664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b17674113757a97537383dc22f4c28496ce5d1fc8274386430fd9d602216a6a7', + 101480, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9f8159cd531775a6fab18432a618771064672ca7a1c6c7db49780d18de0d87d0', + 101300, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lemonada', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lemonada font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lemonada + static TextTheme lemonadaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lemonada(textStyle: textTheme.headline1), + headline2: GoogleFonts.lemonada(textStyle: textTheme.headline2), + headline3: GoogleFonts.lemonada(textStyle: textTheme.headline3), + headline4: GoogleFonts.lemonada(textStyle: textTheme.headline4), + headline5: GoogleFonts.lemonada(textStyle: textTheme.headline5), + headline6: GoogleFonts.lemonada(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lemonada(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lemonada(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lemonada(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lemonada(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lemonada(textStyle: textTheme.caption), + button: GoogleFonts.lemonada(textStyle: textTheme.button), + overline: GoogleFonts.lemonada(textStyle: textTheme.overline), + ); + } + + /// Applies the Lexend Deca font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Deca + static TextStyle lexendDeca({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8189083bf427d48fec9a74c5fc413be97f92e3b7533eb6682832054fc561e6a4', + 65388, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LexendDeca', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lexend Deca font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Deca + static TextTheme lexendDecaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lexendDeca(textStyle: textTheme.headline1), + headline2: GoogleFonts.lexendDeca(textStyle: textTheme.headline2), + headline3: GoogleFonts.lexendDeca(textStyle: textTheme.headline3), + headline4: GoogleFonts.lexendDeca(textStyle: textTheme.headline4), + headline5: GoogleFonts.lexendDeca(textStyle: textTheme.headline5), + headline6: GoogleFonts.lexendDeca(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lexendDeca(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lexendDeca(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lexendDeca(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lexendDeca(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lexendDeca(textStyle: textTheme.caption), + button: GoogleFonts.lexendDeca(textStyle: textTheme.button), + overline: GoogleFonts.lexendDeca(textStyle: textTheme.overline), + ); + } + + /// Applies the Lexend Exa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Exa + static TextStyle lexendExa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fb84184cbd1e9470db5355e5c25309509f5f98bf0676304b47958907ba6f7e12', + 65876, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LexendExa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lexend Exa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Exa + static TextTheme lexendExaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lexendExa(textStyle: textTheme.headline1), + headline2: GoogleFonts.lexendExa(textStyle: textTheme.headline2), + headline3: GoogleFonts.lexendExa(textStyle: textTheme.headline3), + headline4: GoogleFonts.lexendExa(textStyle: textTheme.headline4), + headline5: GoogleFonts.lexendExa(textStyle: textTheme.headline5), + headline6: GoogleFonts.lexendExa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lexendExa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lexendExa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lexendExa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lexendExa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lexendExa(textStyle: textTheme.caption), + button: GoogleFonts.lexendExa(textStyle: textTheme.button), + overline: GoogleFonts.lexendExa(textStyle: textTheme.overline), + ); + } + + /// Applies the Lexend Giga font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Giga + static TextStyle lexendGiga({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1239824b7d568f46db623f61bf9aa0fc21275920dbb5861fdd9d57f132aec548', + 65932, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LexendGiga', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lexend Giga font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Giga + static TextTheme lexendGigaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lexendGiga(textStyle: textTheme.headline1), + headline2: GoogleFonts.lexendGiga(textStyle: textTheme.headline2), + headline3: GoogleFonts.lexendGiga(textStyle: textTheme.headline3), + headline4: GoogleFonts.lexendGiga(textStyle: textTheme.headline4), + headline5: GoogleFonts.lexendGiga(textStyle: textTheme.headline5), + headline6: GoogleFonts.lexendGiga(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lexendGiga(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lexendGiga(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lexendGiga(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lexendGiga(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lexendGiga(textStyle: textTheme.caption), + button: GoogleFonts.lexendGiga(textStyle: textTheme.button), + overline: GoogleFonts.lexendGiga(textStyle: textTheme.overline), + ); + } + + /// Applies the Lexend Mega font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Mega + static TextStyle lexendMega({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2a632f61e3b47867cf774fb3d70ed1a0007cf19ae44be394ea6b878c35648111', + 65940, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LexendMega', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lexend Mega font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Mega + static TextTheme lexendMegaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lexendMega(textStyle: textTheme.headline1), + headline2: GoogleFonts.lexendMega(textStyle: textTheme.headline2), + headline3: GoogleFonts.lexendMega(textStyle: textTheme.headline3), + headline4: GoogleFonts.lexendMega(textStyle: textTheme.headline4), + headline5: GoogleFonts.lexendMega(textStyle: textTheme.headline5), + headline6: GoogleFonts.lexendMega(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lexendMega(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lexendMega(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lexendMega(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lexendMega(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lexendMega(textStyle: textTheme.caption), + button: GoogleFonts.lexendMega(textStyle: textTheme.button), + overline: GoogleFonts.lexendMega(textStyle: textTheme.overline), + ); + } + + /// Applies the Lexend Peta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Peta + static TextStyle lexendPeta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '417f097595c2e66cb6c0ddc8f6add4e4f493b24f53527848dc0d03462e133fd5', + 66008, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LexendPeta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lexend Peta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Peta + static TextTheme lexendPetaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lexendPeta(textStyle: textTheme.headline1), + headline2: GoogleFonts.lexendPeta(textStyle: textTheme.headline2), + headline3: GoogleFonts.lexendPeta(textStyle: textTheme.headline3), + headline4: GoogleFonts.lexendPeta(textStyle: textTheme.headline4), + headline5: GoogleFonts.lexendPeta(textStyle: textTheme.headline5), + headline6: GoogleFonts.lexendPeta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lexendPeta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lexendPeta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lexendPeta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lexendPeta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lexendPeta(textStyle: textTheme.caption), + button: GoogleFonts.lexendPeta(textStyle: textTheme.button), + overline: GoogleFonts.lexendPeta(textStyle: textTheme.overline), + ); + } + + /// Applies the Lexend Tera font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Tera + static TextStyle lexendTera({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5d4d1da38f1fe26a0b69152ff29cb43aa95028fdd9ceda04924ee0236771e324', + 66040, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LexendTera', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lexend Tera font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Tera + static TextTheme lexendTeraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lexendTera(textStyle: textTheme.headline1), + headline2: GoogleFonts.lexendTera(textStyle: textTheme.headline2), + headline3: GoogleFonts.lexendTera(textStyle: textTheme.headline3), + headline4: GoogleFonts.lexendTera(textStyle: textTheme.headline4), + headline5: GoogleFonts.lexendTera(textStyle: textTheme.headline5), + headline6: GoogleFonts.lexendTera(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lexendTera(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lexendTera(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lexendTera(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lexendTera(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lexendTera(textStyle: textTheme.caption), + button: GoogleFonts.lexendTera(textStyle: textTheme.button), + overline: GoogleFonts.lexendTera(textStyle: textTheme.overline), + ); + } + + /// Applies the Lexend Zetta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Zetta + static TextStyle lexendZetta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e6de0f389e45c6725bfc8b444ce22b404d8ef5f4649f41b979fdf5cb1125dfd1', + 65904, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LexendZetta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lexend Zetta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lexend+Zetta + static TextTheme lexendZettaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lexendZetta(textStyle: textTheme.headline1), + headline2: GoogleFonts.lexendZetta(textStyle: textTheme.headline2), + headline3: GoogleFonts.lexendZetta(textStyle: textTheme.headline3), + headline4: GoogleFonts.lexendZetta(textStyle: textTheme.headline4), + headline5: GoogleFonts.lexendZetta(textStyle: textTheme.headline5), + headline6: GoogleFonts.lexendZetta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lexendZetta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lexendZetta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lexendZetta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lexendZetta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lexendZetta(textStyle: textTheme.caption), + button: GoogleFonts.lexendZetta(textStyle: textTheme.button), + overline: GoogleFonts.lexendZetta(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Barcode 128 font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+128 + static TextStyle libreBarcode128({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a60bde92bb99e259f050c9d55ccd67ee6844aacf2e4af2b0e58f75109406ae95', + 11724, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreBarcode128', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Barcode 128 font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+128 + static TextTheme libreBarcode128TextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.libreBarcode128(textStyle: textTheme.headline1), + headline2: GoogleFonts.libreBarcode128(textStyle: textTheme.headline2), + headline3: GoogleFonts.libreBarcode128(textStyle: textTheme.headline3), + headline4: GoogleFonts.libreBarcode128(textStyle: textTheme.headline4), + headline5: GoogleFonts.libreBarcode128(textStyle: textTheme.headline5), + headline6: GoogleFonts.libreBarcode128(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.libreBarcode128(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.libreBarcode128(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.libreBarcode128(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.libreBarcode128(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreBarcode128(textStyle: textTheme.caption), + button: GoogleFonts.libreBarcode128(textStyle: textTheme.button), + overline: GoogleFonts.libreBarcode128(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Barcode 128 Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+128+Text + static TextStyle libreBarcode128Text({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f4129dbbda4ac792c69c162a644275345c7a08c7619a041d31702eca3b14b308', + 23364, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreBarcode128Text', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Barcode 128 Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+128+Text + static TextTheme libreBarcode128TextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.headline1), + headline2: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.headline2), + headline3: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.headline3), + headline4: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.headline4), + headline5: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.headline5), + headline6: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.libreBarcode128Text(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreBarcode128Text(textStyle: textTheme.caption), + button: GoogleFonts.libreBarcode128Text(textStyle: textTheme.button), + overline: GoogleFonts.libreBarcode128Text(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Barcode 39 font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+39 + static TextStyle libreBarcode39({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a605309329470cf91b7f9343b36bcc438da6738fec78fce2ac7a62acf989e1c1', + 7248, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreBarcode39', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Barcode 39 font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+39 + static TextTheme libreBarcode39TextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.libreBarcode39(textStyle: textTheme.headline1), + headline2: GoogleFonts.libreBarcode39(textStyle: textTheme.headline2), + headline3: GoogleFonts.libreBarcode39(textStyle: textTheme.headline3), + headline4: GoogleFonts.libreBarcode39(textStyle: textTheme.headline4), + headline5: GoogleFonts.libreBarcode39(textStyle: textTheme.headline5), + headline6: GoogleFonts.libreBarcode39(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.libreBarcode39(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.libreBarcode39(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.libreBarcode39(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.libreBarcode39(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreBarcode39(textStyle: textTheme.caption), + button: GoogleFonts.libreBarcode39(textStyle: textTheme.button), + overline: GoogleFonts.libreBarcode39(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Barcode 39 Extended font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+39+Extended + static TextStyle libreBarcode39Extended({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'edfdd0513a19347cac4818ed891b4a30a77b1e694da00c3a0e6a1cb397e33c77', + 9912, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreBarcode39Extended', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Barcode 39 Extended font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+39+Extended + static TextTheme libreBarcode39ExtendedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.headline1), + headline2: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.headline2), + headline3: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.headline3), + headline4: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.headline4), + headline5: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.headline5), + headline6: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreBarcode39Extended(textStyle: textTheme.caption), + button: GoogleFonts.libreBarcode39Extended(textStyle: textTheme.button), + overline: + GoogleFonts.libreBarcode39Extended(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Barcode 39 Extended Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+39+Extended+Text + static TextStyle libreBarcode39ExtendedText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd1a436e9eac25119a1f5a775ca357a2bceb9bd198386f7c5ea1d29e70aa83257', + 21148, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreBarcode39ExtendedText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Barcode 39 Extended Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+39+Extended+Text + static TextTheme libreBarcode39ExtendedTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.headline1), + headline2: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.headline2), + headline3: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.headline3), + headline4: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.headline4), + headline5: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.headline5), + headline6: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.headline6), + subtitle1: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.libreBarcode39ExtendedText( + textStyle: textTheme.bodyText2), + caption: + GoogleFonts.libreBarcode39ExtendedText(textStyle: textTheme.caption), + button: + GoogleFonts.libreBarcode39ExtendedText(textStyle: textTheme.button), + overline: + GoogleFonts.libreBarcode39ExtendedText(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Barcode 39 Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+39+Text + static TextStyle libreBarcode39Text({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ee70d574bc973714d8a7d914d0647a5125c638ce6a1f231fae84020e61b2576e', + 12448, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreBarcode39Text', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Barcode 39 Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Barcode+39+Text + static TextTheme libreBarcode39TextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.libreBarcode39Text(textStyle: textTheme.headline1), + headline2: GoogleFonts.libreBarcode39Text(textStyle: textTheme.headline2), + headline3: GoogleFonts.libreBarcode39Text(textStyle: textTheme.headline3), + headline4: GoogleFonts.libreBarcode39Text(textStyle: textTheme.headline4), + headline5: GoogleFonts.libreBarcode39Text(textStyle: textTheme.headline5), + headline6: GoogleFonts.libreBarcode39Text(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.libreBarcode39Text(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.libreBarcode39Text(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.libreBarcode39Text(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.libreBarcode39Text(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreBarcode39Text(textStyle: textTheme.caption), + button: GoogleFonts.libreBarcode39Text(textStyle: textTheme.button), + overline: GoogleFonts.libreBarcode39Text(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Baskerville font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Baskerville + static TextStyle libreBaskerville({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9823638a0177e6fb752280379b200fdaa407e687c8c8e2e7f67bb73b6098f478', + 101356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '47c63ebb507fc5ce683210642c5b0529745a907c2a98ca886eef85e798558b3b', + 121336, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e4f9416f4d8d90e78dc3993de94575a0c44a72da6b4216e5f6346cfee242d201', + 101584, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreBaskerville', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Baskerville font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Baskerville + static TextTheme libreBaskervilleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.libreBaskerville(textStyle: textTheme.headline1), + headline2: GoogleFonts.libreBaskerville(textStyle: textTheme.headline2), + headline3: GoogleFonts.libreBaskerville(textStyle: textTheme.headline3), + headline4: GoogleFonts.libreBaskerville(textStyle: textTheme.headline4), + headline5: GoogleFonts.libreBaskerville(textStyle: textTheme.headline5), + headline6: GoogleFonts.libreBaskerville(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.libreBaskerville(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.libreBaskerville(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.libreBaskerville(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.libreBaskerville(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreBaskerville(textStyle: textTheme.caption), + button: GoogleFonts.libreBaskerville(textStyle: textTheme.button), + overline: GoogleFonts.libreBaskerville(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Caslon Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Caslon+Display + static TextStyle libreCaslonDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c30a6ef1396c17e855a72b95f2848b064fceedce5de3bc974c99f5a75c48148f', + 63388, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreCaslonDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Caslon Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Caslon+Display + static TextTheme libreCaslonDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.caption), + button: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.button), + overline: GoogleFonts.libreCaslonDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Caslon Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Caslon+Text + static TextStyle libreCaslonText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bf61a45047b0948452918933bf02a0c550f66b703720c33a588f9d912c930525', + 58628, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9127e87ed024695b4753bfa734aa694e4e7ca57ec318f8e69856ba19b8bbd8d6', + 64300, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5b9e7454ac79e153edca85178361ae1f5f7e9de7ade1e87c1bc514bdbd0baa5a', + 58284, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreCaslonText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Caslon Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Caslon+Text + static TextTheme libreCaslonTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.libreCaslonText(textStyle: textTheme.headline1), + headline2: GoogleFonts.libreCaslonText(textStyle: textTheme.headline2), + headline3: GoogleFonts.libreCaslonText(textStyle: textTheme.headline3), + headline4: GoogleFonts.libreCaslonText(textStyle: textTheme.headline4), + headline5: GoogleFonts.libreCaslonText(textStyle: textTheme.headline5), + headline6: GoogleFonts.libreCaslonText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.libreCaslonText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.libreCaslonText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.libreCaslonText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.libreCaslonText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreCaslonText(textStyle: textTheme.caption), + button: GoogleFonts.libreCaslonText(textStyle: textTheme.button), + overline: GoogleFonts.libreCaslonText(textStyle: textTheme.overline), + ); + } + + /// Applies the Libre Franklin font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Franklin + static TextStyle libreFranklin({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a1f21b9a28ecb3d6ea935dfde51aee05540140c3a25253b0641b9444dda667c1', + 57732, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '09e958f9da1c899ed89026561f56a7c052b9408db021ae9a897f9247aad44039', + 61308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '97dcc6cedbef15bad22ec4941bcf10ede26cae6bbf0844281f0935c77e475130', + 59320, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd7ed8c62c5358fda45d46e54541af5e0e8397f71242f11a485c04dc39a11218d', + 63088, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '948626a8cfb11d7e06c5fafa6b5e1c4fa4be5db5351c6a223f2ca782b9795798', + 59124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '34e2e0606ed438b0a6d4debccf0e4c6db3db50b9963425c4f53fa58c91e75aae', + 63500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd81c9f4f52bd37777bfda74e64a609d354ef7ccbae5ccc54d946e46d0355ce5d', + 59384, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a6f8c531931908db5a4f8c02ab8f7bb923b97ba2db982c240715f93114bcd958', + 63856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '05ef5f27b97c4867b996bc39496419b7ece8741ac22d6eefe59e893a9a499089', + 59800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '92e317ea35eba4231dde4a6c824a53ccfa8c615e10e8ecc6cae2d148cdff6b49', + 64444, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b31f2f6914b461a54f80a39780a73cfc0e9fdb98c0025558fc780865881f4379', + 59952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '51e7bd4a4cc8faf0e20e3a2f9ee81132e7a586a1cd64c19fa34654b505fd56ec', + 64912, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'df03d679c9dba10b0ec29c9d44006aba2dd476ae7c3886c4b3e713665ca443fe', + 60492, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a6883fda2b8a258fd408d8655880863ebf75e8eb0c22afc895f6e7f60d955d6c', + 65272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '09d37126271e3ab9282776debe97a4652875fb69f4d98f773a1b6b8d37256299', + 61056, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1a059fcf7d8cb61a71e33599611f5f014c20d34592f0ce2d4afb7ce9e3dfbbd8', + 65812, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '41ab0fe0ad9c37f298d693d6b8e4c5f3cef041ad27ed08c25ee44af8653ee501', + 61128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '136f29fe980b3eaed9bf88c730b2383f963681429fc8d55de10ce71392487a12', + 65916, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LibreFranklin', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Libre Franklin font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Libre+Franklin + static TextTheme libreFranklinTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.libreFranklin(textStyle: textTheme.headline1), + headline2: GoogleFonts.libreFranklin(textStyle: textTheme.headline2), + headline3: GoogleFonts.libreFranklin(textStyle: textTheme.headline3), + headline4: GoogleFonts.libreFranklin(textStyle: textTheme.headline4), + headline5: GoogleFonts.libreFranklin(textStyle: textTheme.headline5), + headline6: GoogleFonts.libreFranklin(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.libreFranklin(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.libreFranklin(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.libreFranklin(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.libreFranklin(textStyle: textTheme.bodyText2), + caption: GoogleFonts.libreFranklin(textStyle: textTheme.caption), + button: GoogleFonts.libreFranklin(textStyle: textTheme.button), + overline: GoogleFonts.libreFranklin(textStyle: textTheme.overline), + ); + } + + /// Applies the Life Savers font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Life+Savers + static TextStyle lifeSavers({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '04d39ceac525bd7119947e50ca506cd62efc8803e38347a7b1d07e401463bcee', + 136132, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '362b7da392f70200e34ca8d939a7739b45fdd4cb54b9aee41f6a1db39d13a08b', + 109788, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LifeSavers', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Life Savers font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Life+Savers + static TextTheme lifeSaversTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lifeSavers(textStyle: textTheme.headline1), + headline2: GoogleFonts.lifeSavers(textStyle: textTheme.headline2), + headline3: GoogleFonts.lifeSavers(textStyle: textTheme.headline3), + headline4: GoogleFonts.lifeSavers(textStyle: textTheme.headline4), + headline5: GoogleFonts.lifeSavers(textStyle: textTheme.headline5), + headline6: GoogleFonts.lifeSavers(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lifeSavers(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lifeSavers(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lifeSavers(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lifeSavers(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lifeSavers(textStyle: textTheme.caption), + button: GoogleFonts.lifeSavers(textStyle: textTheme.button), + overline: GoogleFonts.lifeSavers(textStyle: textTheme.overline), + ); + } + + /// Applies the Lilita One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lilita+One + static TextStyle lilitaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9bec8798e040c1fbce51e8a057cea3e28ed1d6af1f649b2abec2cba17eb20016', + 28044, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LilitaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lilita One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lilita+One + static TextTheme lilitaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lilitaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.lilitaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.lilitaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.lilitaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.lilitaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.lilitaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lilitaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lilitaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lilitaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lilitaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lilitaOne(textStyle: textTheme.caption), + button: GoogleFonts.lilitaOne(textStyle: textTheme.button), + overline: GoogleFonts.lilitaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Lily Script One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lily+Script+One + static TextStyle lilyScriptOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8c1fa639d81f625fc5e1f8d3e2988ea5a29d0a6b0a0b6b6a617ee21af28ffc6', + 37524, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LilyScriptOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lily Script One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lily+Script+One + static TextTheme lilyScriptOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lilyScriptOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.lilyScriptOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.lilyScriptOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.lilyScriptOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.lilyScriptOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.lilyScriptOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lilyScriptOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lilyScriptOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lilyScriptOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lilyScriptOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lilyScriptOne(textStyle: textTheme.caption), + button: GoogleFonts.lilyScriptOne(textStyle: textTheme.button), + overline: GoogleFonts.lilyScriptOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Limelight font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Limelight + static TextStyle limelight({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba79f57019c587202d831e35a7e10e6dc9ab23546f46ec9da01aa4d25d509913', + 63860, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Limelight', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Limelight font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Limelight + static TextTheme limelightTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.limelight(textStyle: textTheme.headline1), + headline2: GoogleFonts.limelight(textStyle: textTheme.headline2), + headline3: GoogleFonts.limelight(textStyle: textTheme.headline3), + headline4: GoogleFonts.limelight(textStyle: textTheme.headline4), + headline5: GoogleFonts.limelight(textStyle: textTheme.headline5), + headline6: GoogleFonts.limelight(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.limelight(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.limelight(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.limelight(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.limelight(textStyle: textTheme.bodyText2), + caption: GoogleFonts.limelight(textStyle: textTheme.caption), + button: GoogleFonts.limelight(textStyle: textTheme.button), + overline: GoogleFonts.limelight(textStyle: textTheme.overline), + ); + } + + /// Applies the Linden Hill font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Linden+Hill + static TextStyle lindenHill({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f32a2438962995a6cced863561c2653cdbd06a951ca2497da2a9275d3fb83fcb', + 124796, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '312de55c585397a60a43de01015efb512a794ffb875c4edd86fcb2e8af39db39', + 94492, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LindenHill', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Linden Hill font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Linden+Hill + static TextTheme lindenHillTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lindenHill(textStyle: textTheme.headline1), + headline2: GoogleFonts.lindenHill(textStyle: textTheme.headline2), + headline3: GoogleFonts.lindenHill(textStyle: textTheme.headline3), + headline4: GoogleFonts.lindenHill(textStyle: textTheme.headline4), + headline5: GoogleFonts.lindenHill(textStyle: textTheme.headline5), + headline6: GoogleFonts.lindenHill(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lindenHill(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lindenHill(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lindenHill(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lindenHill(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lindenHill(textStyle: textTheme.caption), + button: GoogleFonts.lindenHill(textStyle: textTheme.button), + overline: GoogleFonts.lindenHill(textStyle: textTheme.overline), + ); + } + + /// Applies the Literata font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Literata + static TextStyle literata({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f994a4c14415cfac63df0a88d12df379634376d190047a3aac8c1ccac859181b', + 136204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1011ff34c164167eb8c8e3cca7b775188431d8992affa5794a30375c51b6d938', + 136324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '497b001be8a26d6015abe84fe17796af4a7dc95f03ad846ec89f4a5555f9f588', + 136392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '438f5478b62d5696ec3eb207a5421131200429183907d6e3b4beb353b7169c6c', + 136280, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fbac7c28db9313dc90a0f798d878fbe937ab215b86a35aef428cbba8f8fa8594', + 130704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4842145089ec9a11f9e11c7ebcfba39e857c3b88315313402619eb2a34bda353', + 130820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '49a0d45ea7e35b031a48ab51d25b49734acf802145bcb84f0870c6629241d148', + 130820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b5feaa5aa4ea544737c3a07671e847a9c6664d791d284ccd3866fe24d45f2927', + 130680, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Literata', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Literata font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Literata + static TextTheme literataTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.literata(textStyle: textTheme.headline1), + headline2: GoogleFonts.literata(textStyle: textTheme.headline2), + headline3: GoogleFonts.literata(textStyle: textTheme.headline3), + headline4: GoogleFonts.literata(textStyle: textTheme.headline4), + headline5: GoogleFonts.literata(textStyle: textTheme.headline5), + headline6: GoogleFonts.literata(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.literata(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.literata(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.literata(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.literata(textStyle: textTheme.bodyText2), + caption: GoogleFonts.literata(textStyle: textTheme.caption), + button: GoogleFonts.literata(textStyle: textTheme.button), + overline: GoogleFonts.literata(textStyle: textTheme.overline), + ); + } + + /// Applies the Liu Jian Mao Cao font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Liu+Jian+Mao+Cao + static TextStyle liuJianMaoCao({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b88821c3a72f98bbab2428a3b3f4a51c2f0eba1644fd8877d195afdf32143cdd', + 4937244, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LiuJianMaoCao', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Liu Jian Mao Cao font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Liu+Jian+Mao+Cao + static TextTheme liuJianMaoCaoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.liuJianMaoCao(textStyle: textTheme.headline1), + headline2: GoogleFonts.liuJianMaoCao(textStyle: textTheme.headline2), + headline3: GoogleFonts.liuJianMaoCao(textStyle: textTheme.headline3), + headline4: GoogleFonts.liuJianMaoCao(textStyle: textTheme.headline4), + headline5: GoogleFonts.liuJianMaoCao(textStyle: textTheme.headline5), + headline6: GoogleFonts.liuJianMaoCao(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.liuJianMaoCao(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.liuJianMaoCao(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.liuJianMaoCao(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.liuJianMaoCao(textStyle: textTheme.bodyText2), + caption: GoogleFonts.liuJianMaoCao(textStyle: textTheme.caption), + button: GoogleFonts.liuJianMaoCao(textStyle: textTheme.button), + overline: GoogleFonts.liuJianMaoCao(textStyle: textTheme.overline), + ); + } + + /// Applies the Livvic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Livvic + static TextStyle livvic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '69cf7d68bd7ea7e4f1eea68a6ce1241109949e773f7342713cc8394cfc3a9350', + 75488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bac5d8a0627f56ade7281b777b0753a1e5c0d8954b749c43c474cef3987fabb3', + 76756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4339e04cdaa30779650ab9cd08a8e6208806c5d3e61ae9934286f6a0fb3045e2', + 75700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1e90ead4569f3a9562d934ed81529f5b9f77d31c3f3fb04d0761808cc8121c00', + 77044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d4d9954fddbfe812dc3f05be50de4c32cc79db0ac03c061be82e347885a0d16', + 75612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '56eb0ced8438e313f473ed5c0d4ee2b2a14fd14f795e437c8fe91da30d6bfa87', + 77080, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '684c0977078ce7a0aa4baca696a867093d47a8b698ac6524e6cba0262e63cc57', + 75488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ed0c728d0a90d1b99fd01bfbc0371e526ddad2ea79d269182c60cd5bb8241393', + 77004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c9399fe200dc52728dd923fc8ef5e8f2566eaa599bfcc903102b49126535701f', + 75736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eebd5e2f0a3762de32ae06a0aecd96d94322b7e078bc768455d63e202a74411f', + 77136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '38ef1c46a21565d37981213d2daba4d8f216e1f0f25972c1003069f2c05df6d1', + 75880, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4c557b68961f711648417be8fe965f0ee26452f0b78ade0beda7fdfa4a13b939', + 77048, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '87b0c42cfd0f29daea2867b06adda2fdf978a1c565072fc54ba65774ef420c1e', + 75936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5431f875e19403b74700eaecfee54e157b5661d8a1fb32712bee2165274e7b03', + 77016, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a61243d45e4b7c886a8af1be0488f4cd259518fea160b655891a491dc90bd01', + 76060, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '541bf67ff4d9b5b56c9d47e30220519bc5d38c2ca202037bf673fba3fe3a8b77', + 77112, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Livvic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Livvic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Livvic + static TextTheme livvicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.livvic(textStyle: textTheme.headline1), + headline2: GoogleFonts.livvic(textStyle: textTheme.headline2), + headline3: GoogleFonts.livvic(textStyle: textTheme.headline3), + headline4: GoogleFonts.livvic(textStyle: textTheme.headline4), + headline5: GoogleFonts.livvic(textStyle: textTheme.headline5), + headline6: GoogleFonts.livvic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.livvic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.livvic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.livvic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.livvic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.livvic(textStyle: textTheme.caption), + button: GoogleFonts.livvic(textStyle: textTheme.button), + overline: GoogleFonts.livvic(textStyle: textTheme.overline), + ); + } + + /// Applies the Lobster font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lobster + static TextStyle lobster({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ce455bfe5094ab723cf0b59871eb112f9f9acbe6d58811590b3d22a7236fa435', + 257344, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lobster', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lobster font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lobster + static TextTheme lobsterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lobster(textStyle: textTheme.headline1), + headline2: GoogleFonts.lobster(textStyle: textTheme.headline2), + headline3: GoogleFonts.lobster(textStyle: textTheme.headline3), + headline4: GoogleFonts.lobster(textStyle: textTheme.headline4), + headline5: GoogleFonts.lobster(textStyle: textTheme.headline5), + headline6: GoogleFonts.lobster(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lobster(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lobster(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lobster(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lobster(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lobster(textStyle: textTheme.caption), + button: GoogleFonts.lobster(textStyle: textTheme.button), + overline: GoogleFonts.lobster(textStyle: textTheme.overline), + ); + } + + /// Applies the Lobster Two font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lobster+Two + static TextStyle lobsterTwo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0c7a1501aa183946996d6a6dd00639131356d161f596511cf06339053570e634', + 108456, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c0dbd5c04e410d8e4da9017651e742b0e62adac50ae9b77ad22cf0407e27e211', + 111476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '510f984a2bfaf23d533e8c389063fe40f2e0d02c2d16889ff79e565345b3aaa5', + 106956, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '37a829bca6d8cab14c9768897a1dafc7fcc08b7b459ba3bd2a2e0dac406eead9', + 110608, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LobsterTwo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lobster Two font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lobster+Two + static TextTheme lobsterTwoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lobsterTwo(textStyle: textTheme.headline1), + headline2: GoogleFonts.lobsterTwo(textStyle: textTheme.headline2), + headline3: GoogleFonts.lobsterTwo(textStyle: textTheme.headline3), + headline4: GoogleFonts.lobsterTwo(textStyle: textTheme.headline4), + headline5: GoogleFonts.lobsterTwo(textStyle: textTheme.headline5), + headline6: GoogleFonts.lobsterTwo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lobsterTwo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lobsterTwo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lobsterTwo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lobsterTwo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lobsterTwo(textStyle: textTheme.caption), + button: GoogleFonts.lobsterTwo(textStyle: textTheme.button), + overline: GoogleFonts.lobsterTwo(textStyle: textTheme.overline), + ); + } + + /// Applies the Londrina Outline font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Londrina+Outline + static TextStyle londrinaOutline({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f2c1c90df8f0b2111b8b45fe4112b8016fcde0874de248c3bd10e4f63da86e57', + 79572, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LondrinaOutline', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Londrina Outline font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Londrina+Outline + static TextTheme londrinaOutlineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.londrinaOutline(textStyle: textTheme.headline1), + headline2: GoogleFonts.londrinaOutline(textStyle: textTheme.headline2), + headline3: GoogleFonts.londrinaOutline(textStyle: textTheme.headline3), + headline4: GoogleFonts.londrinaOutline(textStyle: textTheme.headline4), + headline5: GoogleFonts.londrinaOutline(textStyle: textTheme.headline5), + headline6: GoogleFonts.londrinaOutline(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.londrinaOutline(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.londrinaOutline(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.londrinaOutline(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.londrinaOutline(textStyle: textTheme.bodyText2), + caption: GoogleFonts.londrinaOutline(textStyle: textTheme.caption), + button: GoogleFonts.londrinaOutline(textStyle: textTheme.button), + overline: GoogleFonts.londrinaOutline(textStyle: textTheme.overline), + ); + } + + /// Applies the Londrina Shadow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Londrina+Shadow + static TextStyle londrinaShadow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '84cd8dae1b878c823a1c39d7d9e9893bae747ef212a4a917ab537193b2399287', + 85464, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LondrinaShadow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Londrina Shadow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Londrina+Shadow + static TextTheme londrinaShadowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.londrinaShadow(textStyle: textTheme.headline1), + headline2: GoogleFonts.londrinaShadow(textStyle: textTheme.headline2), + headline3: GoogleFonts.londrinaShadow(textStyle: textTheme.headline3), + headline4: GoogleFonts.londrinaShadow(textStyle: textTheme.headline4), + headline5: GoogleFonts.londrinaShadow(textStyle: textTheme.headline5), + headline6: GoogleFonts.londrinaShadow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.londrinaShadow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.londrinaShadow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.londrinaShadow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.londrinaShadow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.londrinaShadow(textStyle: textTheme.caption), + button: GoogleFonts.londrinaShadow(textStyle: textTheme.button), + overline: GoogleFonts.londrinaShadow(textStyle: textTheme.overline), + ); + } + + /// Applies the Londrina Sketch font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Londrina+Sketch + static TextStyle londrinaSketch({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f0bd303136aee90e673136b6266fb6b196cc94ef0966d955269deffaecbffacc', + 172392, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LondrinaSketch', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Londrina Sketch font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Londrina+Sketch + static TextTheme londrinaSketchTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.londrinaSketch(textStyle: textTheme.headline1), + headline2: GoogleFonts.londrinaSketch(textStyle: textTheme.headline2), + headline3: GoogleFonts.londrinaSketch(textStyle: textTheme.headline3), + headline4: GoogleFonts.londrinaSketch(textStyle: textTheme.headline4), + headline5: GoogleFonts.londrinaSketch(textStyle: textTheme.headline5), + headline6: GoogleFonts.londrinaSketch(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.londrinaSketch(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.londrinaSketch(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.londrinaSketch(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.londrinaSketch(textStyle: textTheme.bodyText2), + caption: GoogleFonts.londrinaSketch(textStyle: textTheme.caption), + button: GoogleFonts.londrinaSketch(textStyle: textTheme.button), + overline: GoogleFonts.londrinaSketch(textStyle: textTheme.overline), + ); + } + + /// Applies the Londrina Solid font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Londrina+Solid + static TextStyle londrinaSolid({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '85115a63ada513540474540a077cb696b1e089220014e3496bbb17c6d81ae8af', + 51980, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LondrinaSolid', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Londrina Solid font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Londrina+Solid + static TextTheme londrinaSolidTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.londrinaSolid(textStyle: textTheme.headline1), + headline2: GoogleFonts.londrinaSolid(textStyle: textTheme.headline2), + headline3: GoogleFonts.londrinaSolid(textStyle: textTheme.headline3), + headline4: GoogleFonts.londrinaSolid(textStyle: textTheme.headline4), + headline5: GoogleFonts.londrinaSolid(textStyle: textTheme.headline5), + headline6: GoogleFonts.londrinaSolid(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.londrinaSolid(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.londrinaSolid(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.londrinaSolid(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.londrinaSolid(textStyle: textTheme.bodyText2), + caption: GoogleFonts.londrinaSolid(textStyle: textTheme.caption), + button: GoogleFonts.londrinaSolid(textStyle: textTheme.button), + overline: GoogleFonts.londrinaSolid(textStyle: textTheme.overline), + ); + } + + /// Applies the Long Cang font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Long+Cang + static TextStyle longCang({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'abadf560e9284e557329d5cac93ab26b805d175ed1d48da30b843ac4c21623a2', + 5150448, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LongCang', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Long Cang font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Long+Cang + static TextTheme longCangTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.longCang(textStyle: textTheme.headline1), + headline2: GoogleFonts.longCang(textStyle: textTheme.headline2), + headline3: GoogleFonts.longCang(textStyle: textTheme.headline3), + headline4: GoogleFonts.longCang(textStyle: textTheme.headline4), + headline5: GoogleFonts.longCang(textStyle: textTheme.headline5), + headline6: GoogleFonts.longCang(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.longCang(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.longCang(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.longCang(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.longCang(textStyle: textTheme.bodyText2), + caption: GoogleFonts.longCang(textStyle: textTheme.caption), + button: GoogleFonts.longCang(textStyle: textTheme.button), + overline: GoogleFonts.longCang(textStyle: textTheme.overline), + ); + } + + /// Applies the Lora font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lora + static TextStyle lora({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ab4a36d4eeabba7b21d6d9f9cf3402c3cfc28c64a4fb06cb6c424de03a8c98b9', + 116620, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5bda244cfbcaf07666bfff144e4e1e5809f93966fa537d9ba1a29fcfd7e0ebb5', + 127672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aada77cdac3a872737be48f8c95b39befadbb124e16cc8b8e5076dd429400ea1', + 114072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b8238541d0dfa01767e098baf5d7942885a58372a7b97e09d2af15e9d295f2f2', + 118464, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lora', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lora font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lora + static TextTheme loraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lora(textStyle: textTheme.headline1), + headline2: GoogleFonts.lora(textStyle: textTheme.headline2), + headline3: GoogleFonts.lora(textStyle: textTheme.headline3), + headline4: GoogleFonts.lora(textStyle: textTheme.headline4), + headline5: GoogleFonts.lora(textStyle: textTheme.headline5), + headline6: GoogleFonts.lora(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lora(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lora(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lora(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lora(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lora(textStyle: textTheme.caption), + button: GoogleFonts.lora(textStyle: textTheme.button), + overline: GoogleFonts.lora(textStyle: textTheme.overline), + ); + } + + /// Applies the Love Ya Like A Sister font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Love+Ya+Like+A+Sister + static TextStyle loveYaLikeASister({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd7068a0e071e73ae0e18893c97cb33a901b4cd1482fed4150d017e6ac0f7a636', + 271876, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LoveYaLikeASister', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Love Ya Like A Sister font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Love+Ya+Like+A+Sister + static TextTheme loveYaLikeASisterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.loveYaLikeASister(textStyle: textTheme.headline1), + headline2: GoogleFonts.loveYaLikeASister(textStyle: textTheme.headline2), + headline3: GoogleFonts.loveYaLikeASister(textStyle: textTheme.headline3), + headline4: GoogleFonts.loveYaLikeASister(textStyle: textTheme.headline4), + headline5: GoogleFonts.loveYaLikeASister(textStyle: textTheme.headline5), + headline6: GoogleFonts.loveYaLikeASister(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.loveYaLikeASister(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.loveYaLikeASister(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.loveYaLikeASister(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.loveYaLikeASister(textStyle: textTheme.bodyText2), + caption: GoogleFonts.loveYaLikeASister(textStyle: textTheme.caption), + button: GoogleFonts.loveYaLikeASister(textStyle: textTheme.button), + overline: GoogleFonts.loveYaLikeASister(textStyle: textTheme.overline), + ); + } + + /// Applies the Loved by the King font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Loved+by+the+King + static TextStyle lovedByTheKing({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a37e323dc32cf1679842583e8ac1cf460c0cbf68f0367394bb943ad1f662a77b', + 27432, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LovedbytheKing', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Loved by the King font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Loved+by+the+King + static TextTheme lovedByTheKingTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lovedByTheKing(textStyle: textTheme.headline1), + headline2: GoogleFonts.lovedByTheKing(textStyle: textTheme.headline2), + headline3: GoogleFonts.lovedByTheKing(textStyle: textTheme.headline3), + headline4: GoogleFonts.lovedByTheKing(textStyle: textTheme.headline4), + headline5: GoogleFonts.lovedByTheKing(textStyle: textTheme.headline5), + headline6: GoogleFonts.lovedByTheKing(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lovedByTheKing(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lovedByTheKing(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lovedByTheKing(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lovedByTheKing(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lovedByTheKing(textStyle: textTheme.caption), + button: GoogleFonts.lovedByTheKing(textStyle: textTheme.button), + overline: GoogleFonts.lovedByTheKing(textStyle: textTheme.overline), + ); + } + + /// Applies the Lovers Quarrel font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lovers+Quarrel + static TextStyle loversQuarrel({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2b3afd5d2a24b3641cc9053301da4dd11e595d360d1f052a9527036e96ab00e9', + 61824, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LoversQuarrel', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lovers Quarrel font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lovers+Quarrel + static TextTheme loversQuarrelTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.loversQuarrel(textStyle: textTheme.headline1), + headline2: GoogleFonts.loversQuarrel(textStyle: textTheme.headline2), + headline3: GoogleFonts.loversQuarrel(textStyle: textTheme.headline3), + headline4: GoogleFonts.loversQuarrel(textStyle: textTheme.headline4), + headline5: GoogleFonts.loversQuarrel(textStyle: textTheme.headline5), + headline6: GoogleFonts.loversQuarrel(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.loversQuarrel(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.loversQuarrel(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.loversQuarrel(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.loversQuarrel(textStyle: textTheme.bodyText2), + caption: GoogleFonts.loversQuarrel(textStyle: textTheme.caption), + button: GoogleFonts.loversQuarrel(textStyle: textTheme.button), + overline: GoogleFonts.loversQuarrel(textStyle: textTheme.overline), + ); + } + + /// Applies the Luckiest Guy font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Luckiest+Guy + static TextStyle luckiestGuy({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6a9e5eaeb4d4b04aa5e82f16dabc4206d86d2981ac19d033b535be88d1a773e7', + 72952, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'LuckiestGuy', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Luckiest Guy font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Luckiest+Guy + static TextTheme luckiestGuyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.luckiestGuy(textStyle: textTheme.headline1), + headline2: GoogleFonts.luckiestGuy(textStyle: textTheme.headline2), + headline3: GoogleFonts.luckiestGuy(textStyle: textTheme.headline3), + headline4: GoogleFonts.luckiestGuy(textStyle: textTheme.headline4), + headline5: GoogleFonts.luckiestGuy(textStyle: textTheme.headline5), + headline6: GoogleFonts.luckiestGuy(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.luckiestGuy(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.luckiestGuy(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.luckiestGuy(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.luckiestGuy(textStyle: textTheme.bodyText2), + caption: GoogleFonts.luckiestGuy(textStyle: textTheme.caption), + button: GoogleFonts.luckiestGuy(textStyle: textTheme.button), + overline: GoogleFonts.luckiestGuy(textStyle: textTheme.overline), + ); + } + + /// Applies the Lusitana font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lusitana + static TextStyle lusitana({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c6df963163bf20f6d3c7e20307b4e363715e13d9047b5707caa9407e11af4ebb', + 30140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f5505e39683b141ee21482fcfc3818a5bb6f049abf15928c81caac05296eba18', + 29236, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lusitana', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lusitana font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lusitana + static TextTheme lusitanaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lusitana(textStyle: textTheme.headline1), + headline2: GoogleFonts.lusitana(textStyle: textTheme.headline2), + headline3: GoogleFonts.lusitana(textStyle: textTheme.headline3), + headline4: GoogleFonts.lusitana(textStyle: textTheme.headline4), + headline5: GoogleFonts.lusitana(textStyle: textTheme.headline5), + headline6: GoogleFonts.lusitana(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lusitana(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lusitana(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lusitana(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lusitana(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lusitana(textStyle: textTheme.caption), + button: GoogleFonts.lusitana(textStyle: textTheme.button), + overline: GoogleFonts.lusitana(textStyle: textTheme.overline), + ); + } + + /// Applies the Lustria font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lustria + static TextStyle lustria({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba208c56243ec0aa08c1b911132f8649f5d87f93a699d115fbb59cf02e5bd636', + 37352, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Lustria', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Lustria font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Lustria + static TextTheme lustriaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.lustria(textStyle: textTheme.headline1), + headline2: GoogleFonts.lustria(textStyle: textTheme.headline2), + headline3: GoogleFonts.lustria(textStyle: textTheme.headline3), + headline4: GoogleFonts.lustria(textStyle: textTheme.headline4), + headline5: GoogleFonts.lustria(textStyle: textTheme.headline5), + headline6: GoogleFonts.lustria(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.lustria(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.lustria(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.lustria(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.lustria(textStyle: textTheme.bodyText2), + caption: GoogleFonts.lustria(textStyle: textTheme.caption), + button: GoogleFonts.lustria(textStyle: textTheme.button), + overline: GoogleFonts.lustria(textStyle: textTheme.overline), + ); + } + + /// Applies the M PLUS 1p font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/M+PLUS+1p + static TextStyle mPlus1p({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0654233f2cc095bd1af48724031070c0b16e3dd46fc5c29bd87070d485b7a366', + 1766584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '328d60a811d0715a23a96805dda2004f69c4b0a888dc1711c77a2d589650c97f', + 1762104, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6d33f3ea856c224db5e2d573ab252d85cc66e3d2ec9981d4dded4cb5df17a345', + 1753640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '45129fd4450f7465b6ad68ee3a7f2579df75712cdedec1690b2f2b8e2a008400', + 1753792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '42106dfc33cc933616115e3c69191bc75d0675df68106571eedbe23c14b5ad1f', + 1761472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '27bd65580cfc4564b1dc3ee85e12bdc336861dc586fd838a943bdef4a3bd8730', + 1768720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '21baffc573a6103dcd6c23b9ad751e3686f142c921212717fa3b4356e01a38bc', + 1769116, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MPLUS1p', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the M PLUS 1p font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/M+PLUS+1p + static TextTheme mPlus1pTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mPlus1p(textStyle: textTheme.headline1), + headline2: GoogleFonts.mPlus1p(textStyle: textTheme.headline2), + headline3: GoogleFonts.mPlus1p(textStyle: textTheme.headline3), + headline4: GoogleFonts.mPlus1p(textStyle: textTheme.headline4), + headline5: GoogleFonts.mPlus1p(textStyle: textTheme.headline5), + headline6: GoogleFonts.mPlus1p(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mPlus1p(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mPlus1p(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mPlus1p(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mPlus1p(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mPlus1p(textStyle: textTheme.caption), + button: GoogleFonts.mPlus1p(textStyle: textTheme.button), + overline: GoogleFonts.mPlus1p(textStyle: textTheme.overline), + ); + } + + /// Applies the M PLUS Rounded 1c font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/M+PLUS+Rounded+1c + static TextStyle mPlusRounded1c({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6d028025ec621f30d69f25f3b121f0eb6e4678e96d47f16d760f1fcf59248d2c', + 2899200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8e6655c0fc1e40abbfe6631bef1b71cf55ed1f706c0d130fa9fc82cfb1a644c7', + 3284736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ff70cb1f3f4fe4691c6ec7c7725c4a0aa37e2d1fa2704d659c9efcd304a6bb24', + 3379736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a6066483cf3c5b68c17d69a4a957e9a50dbe366ac10cbf88a9f3776744ec5048', + 3422384, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c9070409f93c9e7a46a302d0205de1c15bdde3b59f65c32ff73315592afaf17e', + 3532232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7b92c0902d7c3f543a4ecc04c44c8cf62f26c4bcc92ecb26e40ef9849277e61', + 3617848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cadad2376795cd1bcdaae984a16f1fef7e2f18ca27fd2493f32f620867a1ef05', + 3624724, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MPLUSRounded1c', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the M PLUS Rounded 1c font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/M+PLUS+Rounded+1c + static TextTheme mPlusRounded1cTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mPlusRounded1c(textStyle: textTheme.headline1), + headline2: GoogleFonts.mPlusRounded1c(textStyle: textTheme.headline2), + headline3: GoogleFonts.mPlusRounded1c(textStyle: textTheme.headline3), + headline4: GoogleFonts.mPlusRounded1c(textStyle: textTheme.headline4), + headline5: GoogleFonts.mPlusRounded1c(textStyle: textTheme.headline5), + headline6: GoogleFonts.mPlusRounded1c(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mPlusRounded1c(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mPlusRounded1c(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mPlusRounded1c(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mPlusRounded1c(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mPlusRounded1c(textStyle: textTheme.caption), + button: GoogleFonts.mPlusRounded1c(textStyle: textTheme.button), + overline: GoogleFonts.mPlusRounded1c(textStyle: textTheme.overline), + ); + } + + /// Applies the Ma Shan Zheng font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ma+Shan+Zheng + static TextStyle maShanZheng({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b09c8b63681f2770158618c3110f15aa53948e2ef43d7bcbee34cfe43cdfa646', + 5855516, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MaShanZheng', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ma Shan Zheng font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ma+Shan+Zheng + static TextTheme maShanZhengTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.maShanZheng(textStyle: textTheme.headline1), + headline2: GoogleFonts.maShanZheng(textStyle: textTheme.headline2), + headline3: GoogleFonts.maShanZheng(textStyle: textTheme.headline3), + headline4: GoogleFonts.maShanZheng(textStyle: textTheme.headline4), + headline5: GoogleFonts.maShanZheng(textStyle: textTheme.headline5), + headline6: GoogleFonts.maShanZheng(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.maShanZheng(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.maShanZheng(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.maShanZheng(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.maShanZheng(textStyle: textTheme.bodyText2), + caption: GoogleFonts.maShanZheng(textStyle: textTheme.caption), + button: GoogleFonts.maShanZheng(textStyle: textTheme.button), + overline: GoogleFonts.maShanZheng(textStyle: textTheme.overline), + ); + } + + /// Applies the Macondo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Macondo + static TextStyle macondo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ecbf710a53864dd6307e2422a043a2a6904563df10226e7278fea2ef2d293dbd', + 48728, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Macondo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Macondo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Macondo + static TextTheme macondoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.macondo(textStyle: textTheme.headline1), + headline2: GoogleFonts.macondo(textStyle: textTheme.headline2), + headline3: GoogleFonts.macondo(textStyle: textTheme.headline3), + headline4: GoogleFonts.macondo(textStyle: textTheme.headline4), + headline5: GoogleFonts.macondo(textStyle: textTheme.headline5), + headline6: GoogleFonts.macondo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.macondo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.macondo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.macondo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.macondo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.macondo(textStyle: textTheme.caption), + button: GoogleFonts.macondo(textStyle: textTheme.button), + overline: GoogleFonts.macondo(textStyle: textTheme.overline), + ); + } + + /// Applies the Macondo Swash Caps font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Macondo+Swash+Caps + static TextStyle macondoSwashCaps({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4143af0ceceb156b80e5e2055d178d84cfca13b39056f49121b05c6b3843f1fd', + 32968, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MacondoSwashCaps', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Macondo Swash Caps font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Macondo+Swash+Caps + static TextTheme macondoSwashCapsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.macondoSwashCaps(textStyle: textTheme.headline1), + headline2: GoogleFonts.macondoSwashCaps(textStyle: textTheme.headline2), + headline3: GoogleFonts.macondoSwashCaps(textStyle: textTheme.headline3), + headline4: GoogleFonts.macondoSwashCaps(textStyle: textTheme.headline4), + headline5: GoogleFonts.macondoSwashCaps(textStyle: textTheme.headline5), + headline6: GoogleFonts.macondoSwashCaps(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.macondoSwashCaps(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.macondoSwashCaps(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.macondoSwashCaps(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.macondoSwashCaps(textStyle: textTheme.bodyText2), + caption: GoogleFonts.macondoSwashCaps(textStyle: textTheme.caption), + button: GoogleFonts.macondoSwashCaps(textStyle: textTheme.button), + overline: GoogleFonts.macondoSwashCaps(textStyle: textTheme.overline), + ); + } + + /// Applies the Mada font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mada + static TextStyle mada({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e8f4edc7b74697883d4382000502d7429481f7ccc59b65ac62c28e99481cbc3', + 40552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4987425fde45e8da45ede3fad409b0ac00e32ca0255a60b44b8e1f701764346c', + 40352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e3c24ab83037a6d4fc5b72d068caaa6a0767414bd20d7defe31c562ced6d6e7', + 40316, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c3e70bf71ab0557ddd82906726c36d89e199792db1997040b1599f61e00acd78', + 40136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '052e0e0f174e9e8ff63bf2a85f70db6cc59d3391a016a31ace8e20c49d0fa0d6', + 40004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b94e1f9c917ae40e5e6b8d95fe24de1817e37942aafb9b9310d5e0d4b049221a', + 39924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7746a4ca1c6767a971c0db31ec18594fa5211adcc318e293d27b55efc36bded9', + 40036, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mada', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mada font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mada + static TextTheme madaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mada(textStyle: textTheme.headline1), + headline2: GoogleFonts.mada(textStyle: textTheme.headline2), + headline3: GoogleFonts.mada(textStyle: textTheme.headline3), + headline4: GoogleFonts.mada(textStyle: textTheme.headline4), + headline5: GoogleFonts.mada(textStyle: textTheme.headline5), + headline6: GoogleFonts.mada(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mada(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mada(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mada(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mada(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mada(textStyle: textTheme.caption), + button: GoogleFonts.mada(textStyle: textTheme.button), + overline: GoogleFonts.mada(textStyle: textTheme.overline), + ); + } + + /// Applies the Magra font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Magra + static TextStyle magra({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9af41cbbd0f37a100cfb6828248fbfbac10111faefb7b379eb4d74092ebd2f8b', + 45488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ab81d03efbb8cfb766cdee7ef1e7333d196769ab264426971367541a4feee673', + 44452, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Magra', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Magra font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Magra + static TextTheme magraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.magra(textStyle: textTheme.headline1), + headline2: GoogleFonts.magra(textStyle: textTheme.headline2), + headline3: GoogleFonts.magra(textStyle: textTheme.headline3), + headline4: GoogleFonts.magra(textStyle: textTheme.headline4), + headline5: GoogleFonts.magra(textStyle: textTheme.headline5), + headline6: GoogleFonts.magra(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.magra(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.magra(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.magra(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.magra(textStyle: textTheme.bodyText2), + caption: GoogleFonts.magra(textStyle: textTheme.caption), + button: GoogleFonts.magra(textStyle: textTheme.button), + overline: GoogleFonts.magra(textStyle: textTheme.overline), + ); + } + + /// Applies the Maiden Orange font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Maiden+Orange + static TextStyle maidenOrange({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f4952dcb36962c7d3f35f54be08eb204ab4600cfc9afad59f213d36b5ff5e8e6', + 60316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MaidenOrange', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Maiden Orange font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Maiden+Orange + static TextTheme maidenOrangeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.maidenOrange(textStyle: textTheme.headline1), + headline2: GoogleFonts.maidenOrange(textStyle: textTheme.headline2), + headline3: GoogleFonts.maidenOrange(textStyle: textTheme.headline3), + headline4: GoogleFonts.maidenOrange(textStyle: textTheme.headline4), + headline5: GoogleFonts.maidenOrange(textStyle: textTheme.headline5), + headline6: GoogleFonts.maidenOrange(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.maidenOrange(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.maidenOrange(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.maidenOrange(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.maidenOrange(textStyle: textTheme.bodyText2), + caption: GoogleFonts.maidenOrange(textStyle: textTheme.caption), + button: GoogleFonts.maidenOrange(textStyle: textTheme.button), + overline: GoogleFonts.maidenOrange(textStyle: textTheme.overline), + ); + } + + /// Applies the Maitree font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Maitree + static TextStyle maitree({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0739208db7083eb1320ec06ca68d5399840b972ed04401c338c373289f55ea74', + 123008, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '19f05ca05c789289a2d8b35a68f7d2eb186a1bdbb47ff7d630f96485b8d06f67', + 120308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'acbe712e2f0c98c52be38409f5b250521e6124b9af003a579b4c94e4e1ad0f49', + 121608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '40f80d32ae82b7f67fe5a2ba972ccaecdf4b1cafee213b04baf2deb885eaf0a5', + 123172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fa9e3fc69089c2a19cf33871b62432a04f1b7d8bbb7faa0150665802ed267f0e', + 124716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0dd3d4080658f7cdb11b91c35ec62b8ff94caac9d5808f03343f66556b2f0ed9', + 126316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Maitree', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Maitree font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Maitree + static TextTheme maitreeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.maitree(textStyle: textTheme.headline1), + headline2: GoogleFonts.maitree(textStyle: textTheme.headline2), + headline3: GoogleFonts.maitree(textStyle: textTheme.headline3), + headline4: GoogleFonts.maitree(textStyle: textTheme.headline4), + headline5: GoogleFonts.maitree(textStyle: textTheme.headline5), + headline6: GoogleFonts.maitree(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.maitree(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.maitree(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.maitree(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.maitree(textStyle: textTheme.bodyText2), + caption: GoogleFonts.maitree(textStyle: textTheme.caption), + button: GoogleFonts.maitree(textStyle: textTheme.button), + overline: GoogleFonts.maitree(textStyle: textTheme.overline), + ); + } + + /// Applies the Major Mono Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Major+Mono+Display + static TextStyle majorMonoDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9901077f5681d4ec7e01e0ebe4bd61ba47669c64a7aedea472cd94fe1175751b', + 73196, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MajorMonoDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Major Mono Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Major+Mono+Display + static TextTheme majorMonoDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.majorMonoDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.majorMonoDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.majorMonoDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.majorMonoDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.majorMonoDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.majorMonoDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.majorMonoDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.majorMonoDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.majorMonoDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.majorMonoDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.majorMonoDisplay(textStyle: textTheme.caption), + button: GoogleFonts.majorMonoDisplay(textStyle: textTheme.button), + overline: GoogleFonts.majorMonoDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Mako font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mako + static TextStyle mako({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'db4609e335050755bb95ce1a179f4666e1a93d3fac9c679e99d96b472582d0a1', + 64280, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mako', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mako font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mako + static TextTheme makoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mako(textStyle: textTheme.headline1), + headline2: GoogleFonts.mako(textStyle: textTheme.headline2), + headline3: GoogleFonts.mako(textStyle: textTheme.headline3), + headline4: GoogleFonts.mako(textStyle: textTheme.headline4), + headline5: GoogleFonts.mako(textStyle: textTheme.headline5), + headline6: GoogleFonts.mako(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mako(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mako(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mako(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mako(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mako(textStyle: textTheme.caption), + button: GoogleFonts.mako(textStyle: textTheme.button), + overline: GoogleFonts.mako(textStyle: textTheme.overline), + ); + } + + /// Applies the Mali font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mali + static TextStyle mali({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e492669e95f03389c8fdab60ebc0fc25dc89f921dfa3b4156ed4ee3556b26a22', + 104192, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9c4049d3990bfb82d515b0f6b44c0669352cf1d4f0ad71a6c39c4d800d91afc5', + 107084, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7ea3a4d356e5cb938ea97489c60b148dd2e33b9bdc641f01c245b965a8028725', + 104400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4aec4ec351696e4bc5a49deed841e02a84880d0fdc72dafdedce7154770dd8d0', + 107256, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cc1fb36bca8387ebe3fdb1a9052a01ed8312a51a3ac265b51d93b7a6bf6ae45c', + 104480, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '575418ad9604b624f1d09cbaa0d15edbdec2653423419c83fae61131d0f0fdc5', + 107544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '56baed7152d5e08635cc8a9e3a241afd0e7659f30374cb82033266959d273382', + 104528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd1e4f0963402e82a0e541cc7ff0d371c1311270840c7059b94bd710b0953210a', + 107536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3d34348744efcb7d239f7d07237bf644507c1d98545de940f5e36475267d7937', + 104580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '56a65ebf56f24e0082786c224207d28f9e3ac7d58473839ef4e014f58dddc92e', + 107532, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7d22887c912c6d24c96e8a7bd85a8bec285b2f6e82cb0f1239c7d62df8d66db1', + 103972, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0cf0f0229db8cba537f46efd1c9a4734268f6011e5e10fc1ad8981849edfc421', + 107396, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mali', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mali font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mali + static TextTheme maliTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mali(textStyle: textTheme.headline1), + headline2: GoogleFonts.mali(textStyle: textTheme.headline2), + headline3: GoogleFonts.mali(textStyle: textTheme.headline3), + headline4: GoogleFonts.mali(textStyle: textTheme.headline4), + headline5: GoogleFonts.mali(textStyle: textTheme.headline5), + headline6: GoogleFonts.mali(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mali(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mali(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mali(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mali(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mali(textStyle: textTheme.caption), + button: GoogleFonts.mali(textStyle: textTheme.button), + overline: GoogleFonts.mali(textStyle: textTheme.overline), + ); + } + + /// Applies the Mallanna font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mallanna + static TextStyle mallanna({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '81feb01d40b2b7875e496dde6320f6af4ca381b03d376608ba5d8f9a8eb72db4', + 359540, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mallanna', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mallanna font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mallanna + static TextTheme mallannaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mallanna(textStyle: textTheme.headline1), + headline2: GoogleFonts.mallanna(textStyle: textTheme.headline2), + headline3: GoogleFonts.mallanna(textStyle: textTheme.headline3), + headline4: GoogleFonts.mallanna(textStyle: textTheme.headline4), + headline5: GoogleFonts.mallanna(textStyle: textTheme.headline5), + headline6: GoogleFonts.mallanna(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mallanna(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mallanna(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mallanna(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mallanna(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mallanna(textStyle: textTheme.caption), + button: GoogleFonts.mallanna(textStyle: textTheme.button), + overline: GoogleFonts.mallanna(textStyle: textTheme.overline), + ); + } + + /// Applies the Mandali font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mandali + static TextStyle mandali({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bf8fcb272aa15d749c2b5a6660a64af1b0014a47b0fe3ed3394e761ce7637f1d', + 368992, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mandali', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mandali font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mandali + static TextTheme mandaliTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mandali(textStyle: textTheme.headline1), + headline2: GoogleFonts.mandali(textStyle: textTheme.headline2), + headline3: GoogleFonts.mandali(textStyle: textTheme.headline3), + headline4: GoogleFonts.mandali(textStyle: textTheme.headline4), + headline5: GoogleFonts.mandali(textStyle: textTheme.headline5), + headline6: GoogleFonts.mandali(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mandali(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mandali(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mandali(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mandali(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mandali(textStyle: textTheme.caption), + button: GoogleFonts.mandali(textStyle: textTheme.button), + overline: GoogleFonts.mandali(textStyle: textTheme.overline), + ); + } + + /// Applies the Manjari font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Manjari + static TextStyle manjari({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bf27671bb835dda0357f930bf36e8187a3b84c55eee29c45942c1f24658669b6', + 136496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1f336f99d4a94b987c207d844c5dcf944f0499c38fa5136e75debe864ea9cb43', + 136428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3679ad318e4f3587d288eeeedd62d875b904a491a6163aecc418b38e359be2d4', + 135944, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Manjari', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Manjari font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Manjari + static TextTheme manjariTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.manjari(textStyle: textTheme.headline1), + headline2: GoogleFonts.manjari(textStyle: textTheme.headline2), + headline3: GoogleFonts.manjari(textStyle: textTheme.headline3), + headline4: GoogleFonts.manjari(textStyle: textTheme.headline4), + headline5: GoogleFonts.manjari(textStyle: textTheme.headline5), + headline6: GoogleFonts.manjari(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.manjari(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.manjari(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.manjari(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.manjari(textStyle: textTheme.bodyText2), + caption: GoogleFonts.manjari(textStyle: textTheme.caption), + button: GoogleFonts.manjari(textStyle: textTheme.button), + overline: GoogleFonts.manjari(textStyle: textTheme.overline), + ); + } + + /// Applies the Manrope font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Manrope + static TextStyle manrope({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0e0aac7c30d815ffee8f590cf386f62ccea077282904c5bcc089f83e1e3fa6ba', + 84572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b00c95e47bd20d7096fc9bd66552bab89fdaee62611c600e651efcc4c1808b29', + 84708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1f742b6ef495bb5b9f5b968a27c50281ca1f9822bb53ec99bb3757ff2f3febfd', + 84680, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1b26cd5641c96028ba3251bc1c3017c3b7f0f66db8bffa236e6a9fba9273dbe4', + 84776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2926db83b22f15d5dead94c407d4b830fe032adae54af4611e4a3b1d95e5059b', + 84684, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '89fbadf5ffbbcf438d182a4931c241c4beb528b1c11c22290afc4b4b8c8f854d', + 84536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f94757bb3fe3b1f1a20cdb49284c1a311dec4ed72554c5858d186fc93db7afaf', + 85448, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Manrope', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Manrope font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Manrope + static TextTheme manropeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.manrope(textStyle: textTheme.headline1), + headline2: GoogleFonts.manrope(textStyle: textTheme.headline2), + headline3: GoogleFonts.manrope(textStyle: textTheme.headline3), + headline4: GoogleFonts.manrope(textStyle: textTheme.headline4), + headline5: GoogleFonts.manrope(textStyle: textTheme.headline5), + headline6: GoogleFonts.manrope(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.manrope(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.manrope(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.manrope(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.manrope(textStyle: textTheme.bodyText2), + caption: GoogleFonts.manrope(textStyle: textTheme.caption), + button: GoogleFonts.manrope(textStyle: textTheme.button), + overline: GoogleFonts.manrope(textStyle: textTheme.overline), + ); + } + + /// Applies the Mansalva font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mansalva + static TextStyle mansalva({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7918b7006d7a856d653dd2465a093d28c6a2fd94aca6109ecd700d5e4c09dc7e', + 79052, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mansalva', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mansalva font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mansalva + static TextTheme mansalvaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mansalva(textStyle: textTheme.headline1), + headline2: GoogleFonts.mansalva(textStyle: textTheme.headline2), + headline3: GoogleFonts.mansalva(textStyle: textTheme.headline3), + headline4: GoogleFonts.mansalva(textStyle: textTheme.headline4), + headline5: GoogleFonts.mansalva(textStyle: textTheme.headline5), + headline6: GoogleFonts.mansalva(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mansalva(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mansalva(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mansalva(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mansalva(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mansalva(textStyle: textTheme.caption), + button: GoogleFonts.mansalva(textStyle: textTheme.button), + overline: GoogleFonts.mansalva(textStyle: textTheme.overline), + ); + } + + /// Applies the Manuale font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Manuale + static TextStyle manuale({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cfd06fa1d33d937fd3d097835096788da1e29fe217c0e6619d7f4e92770987f2', + 91676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b7144bb9db9fc28df1a2f22173a91396c535d078a58256b0937d0ed4916ac08d', + 96700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bee63de104b5fab81c246551830fd9cf2910da15ffb1fe837913493df2612797', + 94432, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b9d7d38e3301e49ed48cee4bdbfdf8bf85004f299e7d33795cc55fad29b5406f', + 101664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1b0e482a58bde31d3c0408ea84a5ce8287b1669e24bb7e75648b20ee859ade8b', + 94576, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '023ded306bfcddff115b0b04ed36de8a5184275774cd972ce1fb34d8d917c61e', + 101776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '50014d6214dc09001362c4e4a770de808a95fc3f590d52d895c9eef86b71d68a', + 91536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2a59ed27fb6985f70acb9fc94d9038ae63cfc4a2ddc5226dfecb7c8407b5a93f', + 96612, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Manuale', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Manuale font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Manuale + static TextTheme manualeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.manuale(textStyle: textTheme.headline1), + headline2: GoogleFonts.manuale(textStyle: textTheme.headline2), + headline3: GoogleFonts.manuale(textStyle: textTheme.headline3), + headline4: GoogleFonts.manuale(textStyle: textTheme.headline4), + headline5: GoogleFonts.manuale(textStyle: textTheme.headline5), + headline6: GoogleFonts.manuale(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.manuale(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.manuale(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.manuale(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.manuale(textStyle: textTheme.bodyText2), + caption: GoogleFonts.manuale(textStyle: textTheme.caption), + button: GoogleFonts.manuale(textStyle: textTheme.button), + overline: GoogleFonts.manuale(textStyle: textTheme.overline), + ); + } + + /// Applies the Marcellus font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marcellus + static TextStyle marcellus({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'da6549c2bc3ceec2f36d4caac4758fda610e67ff654b4c90304b83b55ee36084', + 45588, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Marcellus', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Marcellus font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marcellus + static TextTheme marcellusTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.marcellus(textStyle: textTheme.headline1), + headline2: GoogleFonts.marcellus(textStyle: textTheme.headline2), + headline3: GoogleFonts.marcellus(textStyle: textTheme.headline3), + headline4: GoogleFonts.marcellus(textStyle: textTheme.headline4), + headline5: GoogleFonts.marcellus(textStyle: textTheme.headline5), + headline6: GoogleFonts.marcellus(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.marcellus(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.marcellus(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.marcellus(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.marcellus(textStyle: textTheme.bodyText2), + caption: GoogleFonts.marcellus(textStyle: textTheme.caption), + button: GoogleFonts.marcellus(textStyle: textTheme.button), + overline: GoogleFonts.marcellus(textStyle: textTheme.overline), + ); + } + + /// Applies the Marcellus SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marcellus+SC + static TextStyle marcellusSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7c5ce48eb9c8ceab009d792056be549983c1b1322fca2784a6e75e7579b347f9', + 47472, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MarcellusSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Marcellus SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marcellus+SC + static TextTheme marcellusScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.marcellusSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.marcellusSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.marcellusSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.marcellusSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.marcellusSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.marcellusSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.marcellusSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.marcellusSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.marcellusSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.marcellusSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.marcellusSc(textStyle: textTheme.caption), + button: GoogleFonts.marcellusSc(textStyle: textTheme.button), + overline: GoogleFonts.marcellusSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Marck Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marck+Script + static TextStyle marckScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f111edb73a2a290328fb706396fd239519a491528780e18030fc8b0265a1b669', + 83616, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MarckScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Marck Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marck+Script + static TextTheme marckScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.marckScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.marckScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.marckScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.marckScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.marckScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.marckScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.marckScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.marckScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.marckScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.marckScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.marckScript(textStyle: textTheme.caption), + button: GoogleFonts.marckScript(textStyle: textTheme.button), + overline: GoogleFonts.marckScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Margarine font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Margarine + static TextStyle margarine({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '86d801ed5c2e92441a7292c5dd8599a87757c63d0c8723543bcd44b504f37776', + 148404, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Margarine', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Margarine font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Margarine + static TextTheme margarineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.margarine(textStyle: textTheme.headline1), + headline2: GoogleFonts.margarine(textStyle: textTheme.headline2), + headline3: GoogleFonts.margarine(textStyle: textTheme.headline3), + headline4: GoogleFonts.margarine(textStyle: textTheme.headline4), + headline5: GoogleFonts.margarine(textStyle: textTheme.headline5), + headline6: GoogleFonts.margarine(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.margarine(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.margarine(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.margarine(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.margarine(textStyle: textTheme.bodyText2), + caption: GoogleFonts.margarine(textStyle: textTheme.caption), + button: GoogleFonts.margarine(textStyle: textTheme.button), + overline: GoogleFonts.margarine(textStyle: textTheme.overline), + ); + } + + /// Applies the Markazi Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Markazi+Text + static TextStyle markaziText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0e5e6bb8cf276742072a5a22282dd79c7d532219e9a950faad9fcf21d2cf8cea', + 120520, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd6f033a9cc38e8da2e1570b35f84c43b8312a13a2f126dfd89f67a322513d7eb', + 120652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '68bfe2ab439b778907c8544102bbbb7de31be886ff40a6bf5172cab6c7c23eee', + 120692, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '342d38b7c70eeaf282e54f367d5ba4eba6d1c07b2c2363023084bcbed4d1c05e', + 120648, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MarkaziText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Markazi Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Markazi+Text + static TextTheme markaziTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.markaziText(textStyle: textTheme.headline1), + headline2: GoogleFonts.markaziText(textStyle: textTheme.headline2), + headline3: GoogleFonts.markaziText(textStyle: textTheme.headline3), + headline4: GoogleFonts.markaziText(textStyle: textTheme.headline4), + headline5: GoogleFonts.markaziText(textStyle: textTheme.headline5), + headline6: GoogleFonts.markaziText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.markaziText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.markaziText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.markaziText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.markaziText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.markaziText(textStyle: textTheme.caption), + button: GoogleFonts.markaziText(textStyle: textTheme.button), + overline: GoogleFonts.markaziText(textStyle: textTheme.overline), + ); + } + + /// Applies the Marko One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marko+One + static TextStyle markoOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f84b713ecebd47ffa67dc6fea96096b65f6a1abfb9819f1014a1ed0d1a4c1455', + 34436, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MarkoOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Marko One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marko+One + static TextTheme markoOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.markoOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.markoOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.markoOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.markoOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.markoOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.markoOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.markoOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.markoOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.markoOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.markoOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.markoOne(textStyle: textTheme.caption), + button: GoogleFonts.markoOne(textStyle: textTheme.button), + overline: GoogleFonts.markoOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Marmelad font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marmelad + static TextStyle marmelad({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d26c08790a329b7df0bf3cd14c6102856d22040c14545f72c05a2f1f47633d6', + 64620, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Marmelad', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Marmelad font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marmelad + static TextTheme marmeladTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.marmelad(textStyle: textTheme.headline1), + headline2: GoogleFonts.marmelad(textStyle: textTheme.headline2), + headline3: GoogleFonts.marmelad(textStyle: textTheme.headline3), + headline4: GoogleFonts.marmelad(textStyle: textTheme.headline4), + headline5: GoogleFonts.marmelad(textStyle: textTheme.headline5), + headline6: GoogleFonts.marmelad(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.marmelad(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.marmelad(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.marmelad(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.marmelad(textStyle: textTheme.bodyText2), + caption: GoogleFonts.marmelad(textStyle: textTheme.caption), + button: GoogleFonts.marmelad(textStyle: textTheme.button), + overline: GoogleFonts.marmelad(textStyle: textTheme.overline), + ); + } + + /// Applies the Martel font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Martel + static TextStyle martel({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c4024da71647bc66c6880037b41d29ad5ae7b5426518ad225ee14562d6dae75a', + 120120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '138cff935a5284819d91b6908fed6fc1cb770eddf8d812c17ef1dc6092010fb9', + 121516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0bd68a5be6ee9107bc21ade86bd0199d47d96c7895a7a1c2c3080377779b268a', + 121136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd22af0f3a51da296280637f9124f2579cf8b495c74ce080f84aca6ad6c12c889', + 120600, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5b81175087fcd5061785115771a9e1c7ab3c69ca0de682426b8338a372e23153', + 120924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3e03eaab1b6ec761214d4dc76edf835a3eafc1c7170942a240f46c25a571bd41', + 121552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8d00654db8f5901e4a51129ff21160fe34513ff2284309ccd0b00cc79684c7cb', + 114876, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Martel', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Martel font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Martel + static TextTheme martelTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.martel(textStyle: textTheme.headline1), + headline2: GoogleFonts.martel(textStyle: textTheme.headline2), + headline3: GoogleFonts.martel(textStyle: textTheme.headline3), + headline4: GoogleFonts.martel(textStyle: textTheme.headline4), + headline5: GoogleFonts.martel(textStyle: textTheme.headline5), + headline6: GoogleFonts.martel(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.martel(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.martel(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.martel(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.martel(textStyle: textTheme.bodyText2), + caption: GoogleFonts.martel(textStyle: textTheme.caption), + button: GoogleFonts.martel(textStyle: textTheme.button), + overline: GoogleFonts.martel(textStyle: textTheme.overline), + ); + } + + /// Applies the Martel Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Martel+Sans + static TextStyle martelSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1fc958d478da9b8b19e77c989d4fb6dbbd2f412a15b122ba72a2b11ee450907f', + 107308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2115f8757576a27c80ccede4ba84e8febb53a0ec9f63840ab713b4d5e848f950', + 107084, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f782be9e1cecfb4c75dd0bb7a8d88dce2794738a35bf5532079d99d4d529502d', + 107068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '52f4a456d3927808cd2aa64f46cd6d63f7a938b904b289f66ab69c0db2e884a7', + 106336, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fcf8c1bb73f62f8c3e86ed5126daf3eb4ee130c49e70f7ebdcaf27ae635bfc1b', + 106340, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0860874935148b1b8ffd9705d6ccef02322d3972a1bf7a38e63a65cf542e6395', + 106224, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9145c71bcab8472ba22b19f9e4e898639945be5fed13f10cd4d399fd5eac5a83', + 105840, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MartelSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Martel Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Martel+Sans + static TextTheme martelSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.martelSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.martelSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.martelSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.martelSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.martelSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.martelSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.martelSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.martelSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.martelSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.martelSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.martelSans(textStyle: textTheme.caption), + button: GoogleFonts.martelSans(textStyle: textTheme.button), + overline: GoogleFonts.martelSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Marvel font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marvel + static TextStyle marvel({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3762fad5facc07dfebad111a683192dbddb8dc02a4a43406d2c79a4303b11b95', + 38196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'aaf0a4ec8425cfad4c7d8c41f37da8d7de878baf6fe877de46e9bb6a21afa443', + 40644, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '84edf56bb5528f4a5a646cc54e1df7f8b8f0acfcab08ba176e2140d05e3576dc', + 36944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3b41fd323f8f2702af4eac210e3a7aaccc576298b28256bf11c98cba436c90c9', + 40056, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Marvel', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Marvel font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Marvel + static TextTheme marvelTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.marvel(textStyle: textTheme.headline1), + headline2: GoogleFonts.marvel(textStyle: textTheme.headline2), + headline3: GoogleFonts.marvel(textStyle: textTheme.headline3), + headline4: GoogleFonts.marvel(textStyle: textTheme.headline4), + headline5: GoogleFonts.marvel(textStyle: textTheme.headline5), + headline6: GoogleFonts.marvel(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.marvel(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.marvel(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.marvel(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.marvel(textStyle: textTheme.bodyText2), + caption: GoogleFonts.marvel(textStyle: textTheme.caption), + button: GoogleFonts.marvel(textStyle: textTheme.button), + overline: GoogleFonts.marvel(textStyle: textTheme.overline), + ); + } + + /// Applies the Mate font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mate + static TextStyle mate({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5701b2952429c600058781ef4db8a7525ee3bfcdc98015ed08588eff40647848', + 28168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '30cd036adcb37680b470e2671c3973733f6900c1cc99419e1fde6201aa100018', + 27660, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mate', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mate font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mate + static TextTheme mateTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mate(textStyle: textTheme.headline1), + headline2: GoogleFonts.mate(textStyle: textTheme.headline2), + headline3: GoogleFonts.mate(textStyle: textTheme.headline3), + headline4: GoogleFonts.mate(textStyle: textTheme.headline4), + headline5: GoogleFonts.mate(textStyle: textTheme.headline5), + headline6: GoogleFonts.mate(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mate(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mate(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mate(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mate(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mate(textStyle: textTheme.caption), + button: GoogleFonts.mate(textStyle: textTheme.button), + overline: GoogleFonts.mate(textStyle: textTheme.overline), + ); + } + + /// Applies the Mate SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mate+SC + static TextStyle mateSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9105b12c369a593ea31abf9530db6e89458635e2c5584c36d4e9af55177be4b8', + 29808, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MateSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mate SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mate+SC + static TextTheme mateScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mateSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.mateSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.mateSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.mateSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.mateSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.mateSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mateSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mateSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mateSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mateSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mateSc(textStyle: textTheme.caption), + button: GoogleFonts.mateSc(textStyle: textTheme.button), + overline: GoogleFonts.mateSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Maven Pro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Maven+Pro + static TextStyle mavenPro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '20ff29ac0e19858eec2689ee81f18e45489d0afec4b61a21036d0c755edafcd7', + 60872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'afd784d77bd20f7e76864636023d94a988f8732c47ec791f79d096b11d1c327c', + 61472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1f1c606af4cb59fd55c5e9d478e3c109eb47ee3c48c458ab10edcbcde15f0562', + 61364, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9a922f263eff247f7ccc3823865c2b9241e10c305b6c64b3754dbb06ce6b5e33', + 60948, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MavenPro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Maven Pro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Maven+Pro + static TextTheme mavenProTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mavenPro(textStyle: textTheme.headline1), + headline2: GoogleFonts.mavenPro(textStyle: textTheme.headline2), + headline3: GoogleFonts.mavenPro(textStyle: textTheme.headline3), + headline4: GoogleFonts.mavenPro(textStyle: textTheme.headline4), + headline5: GoogleFonts.mavenPro(textStyle: textTheme.headline5), + headline6: GoogleFonts.mavenPro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mavenPro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mavenPro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mavenPro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mavenPro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mavenPro(textStyle: textTheme.caption), + button: GoogleFonts.mavenPro(textStyle: textTheme.button), + overline: GoogleFonts.mavenPro(textStyle: textTheme.overline), + ); + } + + /// Applies the McLaren font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/McLaren + static TextStyle mcLaren({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ca48a5e17b0201057453d49c4271d139e5824b553505ad1c6fbbd7cbbbf4d1dc', + 54088, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'McLaren', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the McLaren font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/McLaren + static TextTheme mcLarenTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mcLaren(textStyle: textTheme.headline1), + headline2: GoogleFonts.mcLaren(textStyle: textTheme.headline2), + headline3: GoogleFonts.mcLaren(textStyle: textTheme.headline3), + headline4: GoogleFonts.mcLaren(textStyle: textTheme.headline4), + headline5: GoogleFonts.mcLaren(textStyle: textTheme.headline5), + headline6: GoogleFonts.mcLaren(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mcLaren(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mcLaren(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mcLaren(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mcLaren(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mcLaren(textStyle: textTheme.caption), + button: GoogleFonts.mcLaren(textStyle: textTheme.button), + overline: GoogleFonts.mcLaren(textStyle: textTheme.overline), + ); + } + + /// Applies the Meddon font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Meddon + static TextStyle meddon({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '50d2aafad12ffd4c696c904a7fdfa8fa855a6edc2d671fdd64af6375a052029e', + 79884, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Meddon', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Meddon font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Meddon + static TextTheme meddonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.meddon(textStyle: textTheme.headline1), + headline2: GoogleFonts.meddon(textStyle: textTheme.headline2), + headline3: GoogleFonts.meddon(textStyle: textTheme.headline3), + headline4: GoogleFonts.meddon(textStyle: textTheme.headline4), + headline5: GoogleFonts.meddon(textStyle: textTheme.headline5), + headline6: GoogleFonts.meddon(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.meddon(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.meddon(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.meddon(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.meddon(textStyle: textTheme.bodyText2), + caption: GoogleFonts.meddon(textStyle: textTheme.caption), + button: GoogleFonts.meddon(textStyle: textTheme.button), + overline: GoogleFonts.meddon(textStyle: textTheme.overline), + ); + } + + /// Applies the MedievalSharp font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/MedievalSharp + static TextStyle medievalSharp({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '93afbe692f662b93c6faf17b061d07ad7b343db38496d49e05bc31fcfaf585ae', + 71108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MedievalSharp', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the MedievalSharp font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/MedievalSharp + static TextTheme medievalSharpTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.medievalSharp(textStyle: textTheme.headline1), + headline2: GoogleFonts.medievalSharp(textStyle: textTheme.headline2), + headline3: GoogleFonts.medievalSharp(textStyle: textTheme.headline3), + headline4: GoogleFonts.medievalSharp(textStyle: textTheme.headline4), + headline5: GoogleFonts.medievalSharp(textStyle: textTheme.headline5), + headline6: GoogleFonts.medievalSharp(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.medievalSharp(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.medievalSharp(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.medievalSharp(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.medievalSharp(textStyle: textTheme.bodyText2), + caption: GoogleFonts.medievalSharp(textStyle: textTheme.caption), + button: GoogleFonts.medievalSharp(textStyle: textTheme.button), + overline: GoogleFonts.medievalSharp(textStyle: textTheme.overline), + ); + } + + /// Applies the Medula One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Medula+One + static TextStyle medulaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '01411348aab468ebfca2f176a931010b30ec982ff382993310e5cc4d65e49904', + 33636, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MedulaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Medula One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Medula+One + static TextTheme medulaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.medulaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.medulaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.medulaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.medulaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.medulaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.medulaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.medulaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.medulaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.medulaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.medulaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.medulaOne(textStyle: textTheme.caption), + button: GoogleFonts.medulaOne(textStyle: textTheme.button), + overline: GoogleFonts.medulaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Meera Inimai font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Meera+Inimai + static TextStyle meeraInimai({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '199785360f92220660b6a90e66afd8907c31df21ef4e4470e2af99c968017208', + 72272, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MeeraInimai', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Meera Inimai font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Meera+Inimai + static TextTheme meeraInimaiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.meeraInimai(textStyle: textTheme.headline1), + headline2: GoogleFonts.meeraInimai(textStyle: textTheme.headline2), + headline3: GoogleFonts.meeraInimai(textStyle: textTheme.headline3), + headline4: GoogleFonts.meeraInimai(textStyle: textTheme.headline4), + headline5: GoogleFonts.meeraInimai(textStyle: textTheme.headline5), + headline6: GoogleFonts.meeraInimai(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.meeraInimai(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.meeraInimai(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.meeraInimai(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.meeraInimai(textStyle: textTheme.bodyText2), + caption: GoogleFonts.meeraInimai(textStyle: textTheme.caption), + button: GoogleFonts.meeraInimai(textStyle: textTheme.button), + overline: GoogleFonts.meeraInimai(textStyle: textTheme.overline), + ); + } + + /// Applies the Megrim font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Megrim + static TextStyle megrim({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'af75cd9219b5b5df8c1ebc7dff3232935d81325c33d502dfabc83f32a310831d', + 32164, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Megrim', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Megrim font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Megrim + static TextTheme megrimTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.megrim(textStyle: textTheme.headline1), + headline2: GoogleFonts.megrim(textStyle: textTheme.headline2), + headline3: GoogleFonts.megrim(textStyle: textTheme.headline3), + headline4: GoogleFonts.megrim(textStyle: textTheme.headline4), + headline5: GoogleFonts.megrim(textStyle: textTheme.headline5), + headline6: GoogleFonts.megrim(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.megrim(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.megrim(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.megrim(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.megrim(textStyle: textTheme.bodyText2), + caption: GoogleFonts.megrim(textStyle: textTheme.caption), + button: GoogleFonts.megrim(textStyle: textTheme.button), + overline: GoogleFonts.megrim(textStyle: textTheme.overline), + ); + } + + /// Applies the Meie Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Meie+Script + static TextStyle meieScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aefe23d9bdd07bdf03debfd770abb2ea2f50634e5b0803593abf3eb0b9a784c4', + 53640, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MeieScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Meie Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Meie+Script + static TextTheme meieScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.meieScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.meieScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.meieScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.meieScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.meieScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.meieScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.meieScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.meieScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.meieScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.meieScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.meieScript(textStyle: textTheme.caption), + button: GoogleFonts.meieScript(textStyle: textTheme.button), + overline: GoogleFonts.meieScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Merienda font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Merienda + static TextStyle merienda({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1132399bc1f3e2caf41c69cc4f7c590c83da549f8e9b8cf43dadc262df733048', + 41028, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5f177984e147fff648e2e2bd9ca6e74e13c2be2d6d14b466b154b51e93df5f14', + 34984, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Merienda', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Merienda font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Merienda + static TextTheme meriendaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.merienda(textStyle: textTheme.headline1), + headline2: GoogleFonts.merienda(textStyle: textTheme.headline2), + headline3: GoogleFonts.merienda(textStyle: textTheme.headline3), + headline4: GoogleFonts.merienda(textStyle: textTheme.headline4), + headline5: GoogleFonts.merienda(textStyle: textTheme.headline5), + headline6: GoogleFonts.merienda(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.merienda(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.merienda(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.merienda(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.merienda(textStyle: textTheme.bodyText2), + caption: GoogleFonts.merienda(textStyle: textTheme.caption), + button: GoogleFonts.merienda(textStyle: textTheme.button), + overline: GoogleFonts.merienda(textStyle: textTheme.overline), + ); + } + + /// Applies the Merienda One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Merienda+One + static TextStyle meriendaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aa4c2d33606a440380daab12052cc4b38ac64de26f9dc46de18e3405571ea638', + 30500, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MeriendaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Merienda One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Merienda+One + static TextTheme meriendaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.meriendaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.meriendaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.meriendaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.meriendaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.meriendaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.meriendaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.meriendaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.meriendaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.meriendaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.meriendaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.meriendaOne(textStyle: textTheme.caption), + button: GoogleFonts.meriendaOne(textStyle: textTheme.button), + overline: GoogleFonts.meriendaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Merriweather font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Merriweather + static TextStyle merriweather({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8e88a5324d8b8b44503a016700f8509fb935a78d5668c821daa0092bfea21493', + 73036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '328531f24df7325999a988ae9020486990b3f719e0380ebc4c92287bf487a8ff', + 77736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7c2d3ddfee4c635410c77868a5443efcbf7f660b64d159ba2cbd7d03f43e02f3', + 74308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ec0e385dcae93a7bfa85adcf27ca8465f179fba9a112e05f07384561b29a4b1a', + 77292, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '853dd62f5464fdb7677eeceedf17f771b710501d4fb15dd7076912d7430e92e3', + 73672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'acca91ffc59368ee6894a41c9c417f5d2ec9f03c2c181b8e90013e49a401caf4', + 77196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aeb362f6ad7c32d24b6a96265394b98c1da77b6620d79ecace57a083ff21c9d2', + 74176, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c6aef6fa65ac3afe1f4e813c13cc623329ddae356f8fa330370e3f1cd754f928', + 76980, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Merriweather', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Merriweather font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Merriweather + static TextTheme merriweatherTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.merriweather(textStyle: textTheme.headline1), + headline2: GoogleFonts.merriweather(textStyle: textTheme.headline2), + headline3: GoogleFonts.merriweather(textStyle: textTheme.headline3), + headline4: GoogleFonts.merriweather(textStyle: textTheme.headline4), + headline5: GoogleFonts.merriweather(textStyle: textTheme.headline5), + headline6: GoogleFonts.merriweather(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.merriweather(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.merriweather(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.merriweather(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.merriweather(textStyle: textTheme.bodyText2), + caption: GoogleFonts.merriweather(textStyle: textTheme.caption), + button: GoogleFonts.merriweather(textStyle: textTheme.button), + overline: GoogleFonts.merriweather(textStyle: textTheme.overline), + ); + } + + /// Applies the Merriweather Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Merriweather+Sans + static TextStyle merriweatherSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f616380e06211b4f761656da4fa581a7d0342e10ef56f5be45bee9306dfc3a9b', + 41572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '05ca1d14a17191d43a6d7622e29059462800af4da0f507c95243b2bad8fa630c', + 42068, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6bed429e28f419d7f2a83544104f8c0561a37b088ae9f84c2bcd7400c2589dea', + 41204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2064c7a30f875f7364657c94031f67a4ec37225a03e604d81190ef884df6b744', + 41616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fa38d2e5c8adaa4e200490a344d5cf28495405d0d83c6a0620bef8510853c9ac', + 41152, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5c33c69255f4345f6510aeb92fb1edd05495c99313368face8b8c9f996bf5545', + 41752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '344758d11e4f83c18b0998f11d76dfc215dabfffa863207739c8a99248ec5f89', + 41740, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '45321dfdc3c655bfed2b7abc7fb30131d49e307233bf42d8a8d477135890fc04', + 42420, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MerriweatherSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Merriweather Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Merriweather+Sans + static TextTheme merriweatherSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.merriweatherSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.merriweatherSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.merriweatherSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.merriweatherSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.merriweatherSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.merriweatherSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.merriweatherSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.merriweatherSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.merriweatherSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.merriweatherSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.merriweatherSans(textStyle: textTheme.caption), + button: GoogleFonts.merriweatherSans(textStyle: textTheme.button), + overline: GoogleFonts.merriweatherSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Metal Mania font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Metal+Mania + static TextStyle metalMania({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9495d91ee2029ca622be05cf5924ab5d44a3f54809cb02e792987386e0ba2265', + 215332, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MetalMania', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Metal Mania font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Metal+Mania + static TextTheme metalManiaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.metalMania(textStyle: textTheme.headline1), + headline2: GoogleFonts.metalMania(textStyle: textTheme.headline2), + headline3: GoogleFonts.metalMania(textStyle: textTheme.headline3), + headline4: GoogleFonts.metalMania(textStyle: textTheme.headline4), + headline5: GoogleFonts.metalMania(textStyle: textTheme.headline5), + headline6: GoogleFonts.metalMania(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.metalMania(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.metalMania(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.metalMania(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.metalMania(textStyle: textTheme.bodyText2), + caption: GoogleFonts.metalMania(textStyle: textTheme.caption), + button: GoogleFonts.metalMania(textStyle: textTheme.button), + overline: GoogleFonts.metalMania(textStyle: textTheme.overline), + ); + } + + /// Applies the Metamorphous font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Metamorphous + static TextStyle metamorphous({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '83d03fe24f83517affbc43ea6f81ba72a2accf111f2e33ccc4cfe1a857789185', + 68972, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Metamorphous', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Metamorphous font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Metamorphous + static TextTheme metamorphousTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.metamorphous(textStyle: textTheme.headline1), + headline2: GoogleFonts.metamorphous(textStyle: textTheme.headline2), + headline3: GoogleFonts.metamorphous(textStyle: textTheme.headline3), + headline4: GoogleFonts.metamorphous(textStyle: textTheme.headline4), + headline5: GoogleFonts.metamorphous(textStyle: textTheme.headline5), + headline6: GoogleFonts.metamorphous(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.metamorphous(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.metamorphous(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.metamorphous(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.metamorphous(textStyle: textTheme.bodyText2), + caption: GoogleFonts.metamorphous(textStyle: textTheme.caption), + button: GoogleFonts.metamorphous(textStyle: textTheme.button), + overline: GoogleFonts.metamorphous(textStyle: textTheme.overline), + ); + } + + /// Applies the Metrophobic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Metrophobic + static TextStyle metrophobic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fba0d5a8f2ffaa5c02bcfc5580a50f6b1dac80580d8d3a77073e6a74aa189b5c', + 30912, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Metrophobic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Metrophobic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Metrophobic + static TextTheme metrophobicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.metrophobic(textStyle: textTheme.headline1), + headline2: GoogleFonts.metrophobic(textStyle: textTheme.headline2), + headline3: GoogleFonts.metrophobic(textStyle: textTheme.headline3), + headline4: GoogleFonts.metrophobic(textStyle: textTheme.headline4), + headline5: GoogleFonts.metrophobic(textStyle: textTheme.headline5), + headline6: GoogleFonts.metrophobic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.metrophobic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.metrophobic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.metrophobic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.metrophobic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.metrophobic(textStyle: textTheme.caption), + button: GoogleFonts.metrophobic(textStyle: textTheme.button), + overline: GoogleFonts.metrophobic(textStyle: textTheme.overline), + ); + } + + /// Applies the Michroma font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Michroma + static TextStyle michroma({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5799106e7f554ca9657d0f56c31b6babe55b321aefea779d8eae0c68dec1fd03', + 46924, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Michroma', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Michroma font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Michroma + static TextTheme michromaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.michroma(textStyle: textTheme.headline1), + headline2: GoogleFonts.michroma(textStyle: textTheme.headline2), + headline3: GoogleFonts.michroma(textStyle: textTheme.headline3), + headline4: GoogleFonts.michroma(textStyle: textTheme.headline4), + headline5: GoogleFonts.michroma(textStyle: textTheme.headline5), + headline6: GoogleFonts.michroma(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.michroma(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.michroma(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.michroma(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.michroma(textStyle: textTheme.bodyText2), + caption: GoogleFonts.michroma(textStyle: textTheme.caption), + button: GoogleFonts.michroma(textStyle: textTheme.button), + overline: GoogleFonts.michroma(textStyle: textTheme.overline), + ); + } + + /// Applies the Milonga font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Milonga + static TextStyle milonga({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0754de34c73ed1446cebd4a2c6594cd4e24a2b8cd3512ad6e0d157285e9c2f7f', + 128132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Milonga', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Milonga font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Milonga + static TextTheme milongaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.milonga(textStyle: textTheme.headline1), + headline2: GoogleFonts.milonga(textStyle: textTheme.headline2), + headline3: GoogleFonts.milonga(textStyle: textTheme.headline3), + headline4: GoogleFonts.milonga(textStyle: textTheme.headline4), + headline5: GoogleFonts.milonga(textStyle: textTheme.headline5), + headline6: GoogleFonts.milonga(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.milonga(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.milonga(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.milonga(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.milonga(textStyle: textTheme.bodyText2), + caption: GoogleFonts.milonga(textStyle: textTheme.caption), + button: GoogleFonts.milonga(textStyle: textTheme.button), + overline: GoogleFonts.milonga(textStyle: textTheme.overline), + ); + } + + /// Applies the Miltonian font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miltonian + static TextStyle miltonian({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '39ba52477439aa52410287a79a2d8064fb7b18f82af5f6ae22fd50b70e31d96c', + 91816, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Miltonian', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Miltonian font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miltonian + static TextTheme miltonianTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.miltonian(textStyle: textTheme.headline1), + headline2: GoogleFonts.miltonian(textStyle: textTheme.headline2), + headline3: GoogleFonts.miltonian(textStyle: textTheme.headline3), + headline4: GoogleFonts.miltonian(textStyle: textTheme.headline4), + headline5: GoogleFonts.miltonian(textStyle: textTheme.headline5), + headline6: GoogleFonts.miltonian(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.miltonian(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.miltonian(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.miltonian(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.miltonian(textStyle: textTheme.bodyText2), + caption: GoogleFonts.miltonian(textStyle: textTheme.caption), + button: GoogleFonts.miltonian(textStyle: textTheme.button), + overline: GoogleFonts.miltonian(textStyle: textTheme.overline), + ); + } + + /// Applies the Miltonian Tattoo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miltonian+Tattoo + static TextStyle miltonianTattoo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e6b0d4cb984d618866e97a59156c448971703186b779d38d1402b650790004cf', + 69528, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MiltonianTattoo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Miltonian Tattoo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miltonian+Tattoo + static TextTheme miltonianTattooTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.miltonianTattoo(textStyle: textTheme.headline1), + headline2: GoogleFonts.miltonianTattoo(textStyle: textTheme.headline2), + headline3: GoogleFonts.miltonianTattoo(textStyle: textTheme.headline3), + headline4: GoogleFonts.miltonianTattoo(textStyle: textTheme.headline4), + headline5: GoogleFonts.miltonianTattoo(textStyle: textTheme.headline5), + headline6: GoogleFonts.miltonianTattoo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.miltonianTattoo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.miltonianTattoo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.miltonianTattoo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.miltonianTattoo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.miltonianTattoo(textStyle: textTheme.caption), + button: GoogleFonts.miltonianTattoo(textStyle: textTheme.button), + overline: GoogleFonts.miltonianTattoo(textStyle: textTheme.overline), + ); + } + + /// Applies the Mina font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mina + static TextStyle mina({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2cb3c2707dad5e0a5f21dbad8da10b86eb3b1da477394a33f4d47a819fafb82d', + 151172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7dae008ee6a398a7d7b23f1fbdeeaced41fd8ba3b71cb12b94900ded063f6467', + 152540, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mina', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mina font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mina + static TextTheme minaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mina(textStyle: textTheme.headline1), + headline2: GoogleFonts.mina(textStyle: textTheme.headline2), + headline3: GoogleFonts.mina(textStyle: textTheme.headline3), + headline4: GoogleFonts.mina(textStyle: textTheme.headline4), + headline5: GoogleFonts.mina(textStyle: textTheme.headline5), + headline6: GoogleFonts.mina(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mina(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mina(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mina(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mina(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mina(textStyle: textTheme.caption), + button: GoogleFonts.mina(textStyle: textTheme.button), + overline: GoogleFonts.mina(textStyle: textTheme.overline), + ); + } + + /// Applies the Miniver font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miniver + static TextStyle miniver({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5fee893072a2326d9baa9122deb089cd6f8d0645ee00cd02de22b415de3c7c54', + 45408, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Miniver', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Miniver font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miniver + static TextTheme miniverTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.miniver(textStyle: textTheme.headline1), + headline2: GoogleFonts.miniver(textStyle: textTheme.headline2), + headline3: GoogleFonts.miniver(textStyle: textTheme.headline3), + headline4: GoogleFonts.miniver(textStyle: textTheme.headline4), + headline5: GoogleFonts.miniver(textStyle: textTheme.headline5), + headline6: GoogleFonts.miniver(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.miniver(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.miniver(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.miniver(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.miniver(textStyle: textTheme.bodyText2), + caption: GoogleFonts.miniver(textStyle: textTheme.caption), + button: GoogleFonts.miniver(textStyle: textTheme.button), + overline: GoogleFonts.miniver(textStyle: textTheme.overline), + ); + } + + /// Applies the Miriam Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miriam+Libre + static TextStyle miriamLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c4dc8662662a1708ab4d397f59152bba9bde4ce4c524d9286d49d078a8c58dc6', + 74628, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cbe1ade0a4a8eddd786eb1050d18d81c71465545f3f80392927a36af9035c775', + 72092, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MiriamLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Miriam Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miriam+Libre + static TextTheme miriamLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.miriamLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.miriamLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.miriamLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.miriamLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.miriamLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.miriamLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.miriamLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.miriamLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.miriamLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.miriamLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.miriamLibre(textStyle: textTheme.caption), + button: GoogleFonts.miriamLibre(textStyle: textTheme.button), + overline: GoogleFonts.miriamLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Mirza font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mirza + static TextStyle mirza({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5b1ac6cb285ca3492e313a53d5252b9784bf7607f2835a2d44cb3cbad0168539', + 177820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '423532407cc832ef84cc8f08a3359f26b50e721c8aa0e00221e4215cc83440b3', + 177352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4225215d0df4ad389c4ac29d48fddc531703776591ade64c23f6f995669d4078', + 177188, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '306b412a39d9f93ca840c13ca62300eb5c7712e2afa94bd7ef2272b51131be6d', + 177052, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mirza', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mirza font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mirza + static TextTheme mirzaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mirza(textStyle: textTheme.headline1), + headline2: GoogleFonts.mirza(textStyle: textTheme.headline2), + headline3: GoogleFonts.mirza(textStyle: textTheme.headline3), + headline4: GoogleFonts.mirza(textStyle: textTheme.headline4), + headline5: GoogleFonts.mirza(textStyle: textTheme.headline5), + headline6: GoogleFonts.mirza(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mirza(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mirza(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mirza(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mirza(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mirza(textStyle: textTheme.caption), + button: GoogleFonts.mirza(textStyle: textTheme.button), + overline: GoogleFonts.mirza(textStyle: textTheme.overline), + ); + } + + /// Applies the Miss Fajardose font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miss+Fajardose + static TextStyle missFajardose({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8de81a59ca34a15be7f6749a4f5247486c41ce79afb9b16e4212d54c0e5d9a89', + 58824, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MissFajardose', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Miss Fajardose font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Miss+Fajardose + static TextTheme missFajardoseTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.missFajardose(textStyle: textTheme.headline1), + headline2: GoogleFonts.missFajardose(textStyle: textTheme.headline2), + headline3: GoogleFonts.missFajardose(textStyle: textTheme.headline3), + headline4: GoogleFonts.missFajardose(textStyle: textTheme.headline4), + headline5: GoogleFonts.missFajardose(textStyle: textTheme.headline5), + headline6: GoogleFonts.missFajardose(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.missFajardose(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.missFajardose(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.missFajardose(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.missFajardose(textStyle: textTheme.bodyText2), + caption: GoogleFonts.missFajardose(textStyle: textTheme.caption), + button: GoogleFonts.missFajardose(textStyle: textTheme.button), + overline: GoogleFonts.missFajardose(textStyle: textTheme.overline), + ); + } + + /// Applies the Mitr font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mitr + static TextStyle mitr({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '13aa43b100ddb2ef3f574409c44d5148c96e262d636030f3546632afc8bec583', + 140672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '42aaeccd38bab09aab541391f181cf90544aed031b28240064e03a597d820aff', + 146132, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '51a838bb86fd8ae3d3b14861b86090b8e590d6cec16828f5ff85cc29e255fdd4', + 148012, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a8c0fad121eecc6ccc06afd51a3ed04b7632eabd778490fabe406d010d492fb6', + 148128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f52b41a04226fd35e8292e4074e68cf18847a0b362d1ea41038b6cebcad7953c', + 147556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '302b58d18b982fe3745338cc6ea87e5868436d2ba962262423c98cac9d161c47', + 148144, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mitr', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mitr font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mitr + static TextTheme mitrTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mitr(textStyle: textTheme.headline1), + headline2: GoogleFonts.mitr(textStyle: textTheme.headline2), + headline3: GoogleFonts.mitr(textStyle: textTheme.headline3), + headline4: GoogleFonts.mitr(textStyle: textTheme.headline4), + headline5: GoogleFonts.mitr(textStyle: textTheme.headline5), + headline6: GoogleFonts.mitr(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mitr(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mitr(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mitr(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mitr(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mitr(textStyle: textTheme.caption), + button: GoogleFonts.mitr(textStyle: textTheme.button), + overline: GoogleFonts.mitr(textStyle: textTheme.overline), + ); + } + + /// Applies the Modak font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Modak + static TextStyle modak({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '999298cc9b836b6d428706a18192f20ce4f95b9ffc84c016dd59527f7735bdd4', + 362296, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Modak', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Modak font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Modak + static TextTheme modakTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.modak(textStyle: textTheme.headline1), + headline2: GoogleFonts.modak(textStyle: textTheme.headline2), + headline3: GoogleFonts.modak(textStyle: textTheme.headline3), + headline4: GoogleFonts.modak(textStyle: textTheme.headline4), + headline5: GoogleFonts.modak(textStyle: textTheme.headline5), + headline6: GoogleFonts.modak(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.modak(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.modak(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.modak(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.modak(textStyle: textTheme.bodyText2), + caption: GoogleFonts.modak(textStyle: textTheme.caption), + button: GoogleFonts.modak(textStyle: textTheme.button), + overline: GoogleFonts.modak(textStyle: textTheme.overline), + ); + } + + /// Applies the Modern Antiqua font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Modern+Antiqua + static TextStyle modernAntiqua({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'df7e73ec3e130e1a70e2680351228d3e058ceea718f4e7ab314b98ce3978d7f9', + 70060, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ModernAntiqua', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Modern Antiqua font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Modern+Antiqua + static TextTheme modernAntiquaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.modernAntiqua(textStyle: textTheme.headline1), + headline2: GoogleFonts.modernAntiqua(textStyle: textTheme.headline2), + headline3: GoogleFonts.modernAntiqua(textStyle: textTheme.headline3), + headline4: GoogleFonts.modernAntiqua(textStyle: textTheme.headline4), + headline5: GoogleFonts.modernAntiqua(textStyle: textTheme.headline5), + headline6: GoogleFonts.modernAntiqua(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.modernAntiqua(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.modernAntiqua(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.modernAntiqua(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.modernAntiqua(textStyle: textTheme.bodyText2), + caption: GoogleFonts.modernAntiqua(textStyle: textTheme.caption), + button: GoogleFonts.modernAntiqua(textStyle: textTheme.button), + overline: GoogleFonts.modernAntiqua(textStyle: textTheme.overline), + ); + } + + /// Applies the Mogra font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mogra + static TextStyle mogra({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '11a1b64ecdf329dcbc068f036c2c09a2058b63bda66c3a541102b48e959c2a4e', + 233848, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mogra', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mogra font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mogra + static TextTheme mograTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mogra(textStyle: textTheme.headline1), + headline2: GoogleFonts.mogra(textStyle: textTheme.headline2), + headline3: GoogleFonts.mogra(textStyle: textTheme.headline3), + headline4: GoogleFonts.mogra(textStyle: textTheme.headline4), + headline5: GoogleFonts.mogra(textStyle: textTheme.headline5), + headline6: GoogleFonts.mogra(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mogra(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mogra(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mogra(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mogra(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mogra(textStyle: textTheme.caption), + button: GoogleFonts.mogra(textStyle: textTheme.button), + overline: GoogleFonts.mogra(textStyle: textTheme.overline), + ); + } + + /// Applies the Molengo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Molengo + static TextStyle molengo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c17cda006ffaf122363be2ad7ed8394c0bf59581bd9e5e9a7e7f5c0ed161a4c0', + 34868, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Molengo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Molengo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Molengo + static TextTheme molengoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.molengo(textStyle: textTheme.headline1), + headline2: GoogleFonts.molengo(textStyle: textTheme.headline2), + headline3: GoogleFonts.molengo(textStyle: textTheme.headline3), + headline4: GoogleFonts.molengo(textStyle: textTheme.headline4), + headline5: GoogleFonts.molengo(textStyle: textTheme.headline5), + headline6: GoogleFonts.molengo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.molengo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.molengo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.molengo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.molengo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.molengo(textStyle: textTheme.caption), + button: GoogleFonts.molengo(textStyle: textTheme.button), + overline: GoogleFonts.molengo(textStyle: textTheme.overline), + ); + } + + /// Applies the Molle font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Molle + static TextStyle molle({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd081c5d8d7d19361eaa68e5c05b211b519fa2d27ca94a3ec76da0a39f880acb9', + 35904, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Molle', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Molle font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Molle + static TextTheme molleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.molle(textStyle: textTheme.headline1), + headline2: GoogleFonts.molle(textStyle: textTheme.headline2), + headline3: GoogleFonts.molle(textStyle: textTheme.headline3), + headline4: GoogleFonts.molle(textStyle: textTheme.headline4), + headline5: GoogleFonts.molle(textStyle: textTheme.headline5), + headline6: GoogleFonts.molle(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.molle(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.molle(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.molle(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.molle(textStyle: textTheme.bodyText2), + caption: GoogleFonts.molle(textStyle: textTheme.caption), + button: GoogleFonts.molle(textStyle: textTheme.button), + overline: GoogleFonts.molle(textStyle: textTheme.overline), + ); + } + + /// Applies the Monda font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Monda + static TextStyle monda({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b28adc169d42a434c7b435bab7f4c11ae50fdc1516bc03426f8835d8b70dbee7', + 28212, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b05dc6798c3ea80d95c20709740c72bb72d07040538c1240f850c220292e3f6f', + 29004, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Monda', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Monda font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Monda + static TextTheme mondaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.monda(textStyle: textTheme.headline1), + headline2: GoogleFonts.monda(textStyle: textTheme.headline2), + headline3: GoogleFonts.monda(textStyle: textTheme.headline3), + headline4: GoogleFonts.monda(textStyle: textTheme.headline4), + headline5: GoogleFonts.monda(textStyle: textTheme.headline5), + headline6: GoogleFonts.monda(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.monda(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.monda(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.monda(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.monda(textStyle: textTheme.bodyText2), + caption: GoogleFonts.monda(textStyle: textTheme.caption), + button: GoogleFonts.monda(textStyle: textTheme.button), + overline: GoogleFonts.monda(textStyle: textTheme.overline), + ); + } + + /// Applies the Monofett font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Monofett + static TextStyle monofett({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ebeb36e324072bc8a4e7717f33c5c72271409af395fdf3b4f1e66b529addb881', + 58108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Monofett', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Monofett font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Monofett + static TextTheme monofettTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.monofett(textStyle: textTheme.headline1), + headline2: GoogleFonts.monofett(textStyle: textTheme.headline2), + headline3: GoogleFonts.monofett(textStyle: textTheme.headline3), + headline4: GoogleFonts.monofett(textStyle: textTheme.headline4), + headline5: GoogleFonts.monofett(textStyle: textTheme.headline5), + headline6: GoogleFonts.monofett(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.monofett(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.monofett(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.monofett(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.monofett(textStyle: textTheme.bodyText2), + caption: GoogleFonts.monofett(textStyle: textTheme.caption), + button: GoogleFonts.monofett(textStyle: textTheme.button), + overline: GoogleFonts.monofett(textStyle: textTheme.overline), + ); + } + + /// Applies the Monoton font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Monoton + static TextStyle monoton({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '432f7ab89e5991e379800eb285fad653a999a44aca1f9204e62060bbf932b2bf', + 51556, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Monoton', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Monoton font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Monoton + static TextTheme monotonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.monoton(textStyle: textTheme.headline1), + headline2: GoogleFonts.monoton(textStyle: textTheme.headline2), + headline3: GoogleFonts.monoton(textStyle: textTheme.headline3), + headline4: GoogleFonts.monoton(textStyle: textTheme.headline4), + headline5: GoogleFonts.monoton(textStyle: textTheme.headline5), + headline6: GoogleFonts.monoton(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.monoton(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.monoton(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.monoton(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.monoton(textStyle: textTheme.bodyText2), + caption: GoogleFonts.monoton(textStyle: textTheme.caption), + button: GoogleFonts.monoton(textStyle: textTheme.button), + overline: GoogleFonts.monoton(textStyle: textTheme.overline), + ); + } + + /// Applies the Monsieur La Doulaise font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Monsieur+La+Doulaise + static TextStyle monsieurLaDoulaise({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'def26258142aeeb4021fb91331bd0a7dae943c48caa8b09211393a16ed3c53c9', + 54240, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MonsieurLaDoulaise', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Monsieur La Doulaise font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Monsieur+La+Doulaise + static TextTheme monsieurLaDoulaiseTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.headline1), + headline2: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.headline2), + headline3: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.headline3), + headline4: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.headline4), + headline5: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.headline5), + headline6: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.bodyText2), + caption: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.caption), + button: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.button), + overline: GoogleFonts.monsieurLaDoulaise(textStyle: textTheme.overline), + ); + } + + /// Applies the Montaga font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montaga + static TextStyle montaga({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3b97268f12c527fb933009800e8d887c083f48fa733c69dba7961c887909d99e', + 33908, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Montaga', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Montaga font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montaga + static TextTheme montagaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.montaga(textStyle: textTheme.headline1), + headline2: GoogleFonts.montaga(textStyle: textTheme.headline2), + headline3: GoogleFonts.montaga(textStyle: textTheme.headline3), + headline4: GoogleFonts.montaga(textStyle: textTheme.headline4), + headline5: GoogleFonts.montaga(textStyle: textTheme.headline5), + headline6: GoogleFonts.montaga(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.montaga(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.montaga(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.montaga(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.montaga(textStyle: textTheme.bodyText2), + caption: GoogleFonts.montaga(textStyle: textTheme.caption), + button: GoogleFonts.montaga(textStyle: textTheme.button), + overline: GoogleFonts.montaga(textStyle: textTheme.overline), + ); + } + + /// Applies the Montez font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montez + static TextStyle montez({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd2ffdd5ee7b2b6e5f8a08b9bc62a24eac29a4755576e27b7856e039043d596ea', + 76776, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Montez', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Montez font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montez + static TextTheme montezTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.montez(textStyle: textTheme.headline1), + headline2: GoogleFonts.montez(textStyle: textTheme.headline2), + headline3: GoogleFonts.montez(textStyle: textTheme.headline3), + headline4: GoogleFonts.montez(textStyle: textTheme.headline4), + headline5: GoogleFonts.montez(textStyle: textTheme.headline5), + headline6: GoogleFonts.montez(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.montez(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.montez(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.montez(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.montez(textStyle: textTheme.bodyText2), + caption: GoogleFonts.montez(textStyle: textTheme.caption), + button: GoogleFonts.montez(textStyle: textTheme.button), + overline: GoogleFonts.montez(textStyle: textTheme.overline), + ); + } + + /// Applies the Montserrat font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montserrat + static TextStyle montserrat({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '13b843ab4d5acd6d99d06a88bbc492bd3ffb0d55b01f159c34a0a6237cb2f148', + 151968, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '282f82e77ce6ec450987922f6c8c55456bd826c8a1557a007adeb4c460c6ce27', + 151680, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b058309166a4bdbc1e36f0f4ca0b8349e9705f457bc71a190e34624de2062455', + 153076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '778b3406a7b740d7d857323720a66ef72ccb3b507b3488b2e56fb9c9f52977b8', + 152248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25cab2a480827c3b70f98fa4fe09b06a974b8afb996f60232b5acacb57acade2', + 152908, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7b490e666930fe7f1379aa62b203966a6f284a9dc74b09e8dd5c59760da460f8', + 151788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '470e93c06a9fffa6851375f54047917a9d774ed6027d9f044cd1bc8d4cd5630b', + 152396, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '83e171717660560888d9a84b2a2b1409b6fb43b806ce9b96059c974be4126d64', + 151288, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cec0f6e0bfbfaa352eb189f0eb220916dd278b02aaf824be87055ba5cc38d58b', + 152092, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a61fc08703fd75883c389503641242523b7140ac0b6df6b22106902767e7bb2c', + 150928, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5f82f6e55db43e905c6ab9d04395566b243c41798d6a53545ffbd10ed6c424c4', + 152148, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '625ed5e1a74ead073b6562f04b509f83c2e1630b25ea4c98ccd3d275418c0308', + 150648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '052bfd7f3dc788ae3f0d59dc8e5d65be0c1ec9acaa6fbe53dc70640f64c075bd', + 151780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7c882260e0b6664897eb1747188ca151cea2a966109ae534e0eb706aa990510d', + 150528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8bac23178f38bab6018ed343c524a822a5bcbe2a021decbf30f85a9cb61aade0', + 151776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f2c00bb055d9f815d97ed28ae9e26ae9bff8d0ffa7c6e9ddd3cc47c070c922ea', + 150292, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c64d95a01ae992dd8ff7474e55c16b2a05ea6c4e9aa944ccb51d4b1016232583', + 149380, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6eac88b190248d68069db0de9c165f24aaffc22097fec98ba72710c2f9a96a71', + 148416, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Montserrat', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Montserrat font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montserrat + static TextTheme montserratTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.montserrat(textStyle: textTheme.headline1), + headline2: GoogleFonts.montserrat(textStyle: textTheme.headline2), + headline3: GoogleFonts.montserrat(textStyle: textTheme.headline3), + headline4: GoogleFonts.montserrat(textStyle: textTheme.headline4), + headline5: GoogleFonts.montserrat(textStyle: textTheme.headline5), + headline6: GoogleFonts.montserrat(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.montserrat(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.montserrat(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.montserrat(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.montserrat(textStyle: textTheme.bodyText2), + caption: GoogleFonts.montserrat(textStyle: textTheme.caption), + button: GoogleFonts.montserrat(textStyle: textTheme.button), + overline: GoogleFonts.montserrat(textStyle: textTheme.overline), + ); + } + + /// Applies the Montserrat Alternates font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montserrat+Alternates + static TextStyle montserratAlternates({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5c09b026797ce5fac448caefbdc866f5a81bf9cc625984ef1aa9403631484819', + 111412, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c82e331c5ea52753b4551af7eff9d03c3662fb16fea5c00fa558120532424212', + 114640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a0f2fd4ee372169bc19522956923e1ade9563dbf8789d7a74576eca54c0cb98', + 111792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9e8fdaa328523c20fe857f63acd10406a6fe6165bc82fd41a676e77c55374087', + 114648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '009e98fbd7f5568e68b9379e0d049e1f646ef5001f366eca34cd44c262443dbb', + 111672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd82d87be0bd762617314db90ed2694ea7a75e7aeb4e4da266a9581c67fd97d09', + 114248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b2f5d183ba5588c36e0f975cd5c154bfab1c4defaf7edcacb101f20a83721bb0', + 111272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a94551458451c010e364df974a12e6de5911fe56b117390ba8d52ac82dfaaec5', + 113800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0ad6f1c378b9acd74dc8ac990b61607e3b218a3fbf0988f0ef5c508fa13fdab1', + 110856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4afe42c2aeb0bd46a2c9f199560bd2ebedb166d1e67618651870b8421499c300', + 113540, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2fec79e6e398e2c513322f7af66001553bf74c69cefe117fb05472b44f6d95ed', + 111008, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3ef634325d5a61d0891d3a6eacd265a2983cf1e9e84caafc7bc2addf2f554d69', + 113232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '54d33b2d46c465e38dbbac2b2b8b5f0a6242270cf0d5511f0161c21e1f0d4ccf', + 110620, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '95d8420481ab395146970da7489bd9b91f5c0437ac1806c84583787cdd4d9b58', + 113136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2dd175394efc14d9c412b3bad3e06b26a98655760909e676e5be12e642daee59', + 110684, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0ea02188bddfbe57ace54b7785d677eddcdd630d1073fdcda277f1186aaedf20', + 112928, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d1eed87eda713f3f729c721ae1754c382e1517f51f29be05babf98f8e985693', + 109236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '59d0191230f070e7792b5c21e8a1f3ebc0c132ed6564d765d8759903325bda9b', + 111956, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MontserratAlternates', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Montserrat Alternates font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montserrat+Alternates + static TextTheme montserratAlternatesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.montserratAlternates(textStyle: textTheme.headline1), + headline2: + GoogleFonts.montserratAlternates(textStyle: textTheme.headline2), + headline3: + GoogleFonts.montserratAlternates(textStyle: textTheme.headline3), + headline4: + GoogleFonts.montserratAlternates(textStyle: textTheme.headline4), + headline5: + GoogleFonts.montserratAlternates(textStyle: textTheme.headline5), + headline6: + GoogleFonts.montserratAlternates(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.montserratAlternates(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.montserratAlternates(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.montserratAlternates(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.montserratAlternates(textStyle: textTheme.bodyText2), + caption: GoogleFonts.montserratAlternates(textStyle: textTheme.caption), + button: GoogleFonts.montserratAlternates(textStyle: textTheme.button), + overline: GoogleFonts.montserratAlternates(textStyle: textTheme.overline), + ); + } + + /// Applies the Montserrat Subrayada font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montserrat+Subrayada + static TextStyle montserratSubrayada({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bcf81f50b96cbae5ccbd3337f693c53bbbe2bb5717bb8637eeaf4d5dff5699c4', + 24284, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6a2a4c0ee5aade485aa6bf9a1a43b1ef3fe0aa5dda27e70b0b9abe7625562124', + 24316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MontserratSubrayada', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Montserrat Subrayada font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Montserrat+Subrayada + static TextTheme montserratSubrayadaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.montserratSubrayada(textStyle: textTheme.headline1), + headline2: + GoogleFonts.montserratSubrayada(textStyle: textTheme.headline2), + headline3: + GoogleFonts.montserratSubrayada(textStyle: textTheme.headline3), + headline4: + GoogleFonts.montserratSubrayada(textStyle: textTheme.headline4), + headline5: + GoogleFonts.montserratSubrayada(textStyle: textTheme.headline5), + headline6: + GoogleFonts.montserratSubrayada(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.montserratSubrayada(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.montserratSubrayada(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.montserratSubrayada(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.montserratSubrayada(textStyle: textTheme.bodyText2), + caption: GoogleFonts.montserratSubrayada(textStyle: textTheme.caption), + button: GoogleFonts.montserratSubrayada(textStyle: textTheme.button), + overline: GoogleFonts.montserratSubrayada(textStyle: textTheme.overline), + ); + } + + /// Applies the Mountains of Christmas font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mountains+of+Christmas + static TextStyle mountainsOfChristmas({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c2200cef227dc27280b133ec5d366a7a1c5e8956523b6a69490c6d3be875831f', + 122496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '52a7b2b21269dc6d67187a7882fa4bbc19f093792adc852c62497c6495d129e6', + 123356, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MountainsofChristmas', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mountains of Christmas font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mountains+of+Christmas + static TextTheme mountainsOfChristmasTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.headline1), + headline2: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.headline2), + headline3: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.headline3), + headline4: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.headline4), + headline5: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.headline5), + headline6: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.mountainsOfChristmas(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mountainsOfChristmas(textStyle: textTheme.caption), + button: GoogleFonts.mountainsOfChristmas(textStyle: textTheme.button), + overline: GoogleFonts.mountainsOfChristmas(textStyle: textTheme.overline), + ); + } + + /// Applies the Mouse Memoirs font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mouse+Memoirs + static TextStyle mouseMemoirs({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '36717824ce8893e8e49e371730b587484db4b095302a60970bffe613c3a81960', + 55516, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MouseMemoirs', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mouse Memoirs font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mouse+Memoirs + static TextTheme mouseMemoirsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mouseMemoirs(textStyle: textTheme.headline1), + headline2: GoogleFonts.mouseMemoirs(textStyle: textTheme.headline2), + headline3: GoogleFonts.mouseMemoirs(textStyle: textTheme.headline3), + headline4: GoogleFonts.mouseMemoirs(textStyle: textTheme.headline4), + headline5: GoogleFonts.mouseMemoirs(textStyle: textTheme.headline5), + headline6: GoogleFonts.mouseMemoirs(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mouseMemoirs(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mouseMemoirs(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mouseMemoirs(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mouseMemoirs(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mouseMemoirs(textStyle: textTheme.caption), + button: GoogleFonts.mouseMemoirs(textStyle: textTheme.button), + overline: GoogleFonts.mouseMemoirs(textStyle: textTheme.overline), + ); + } + + /// Applies the Mr Bedfort font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mr+Bedfort + static TextStyle mrBedfort({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e15139ad970a418042aa1bd423cac0ecbc77211a359ea93bf60c67ade7f97542', + 37204, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MrBedfort', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mr Bedfort font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mr+Bedfort + static TextTheme mrBedfortTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mrBedfort(textStyle: textTheme.headline1), + headline2: GoogleFonts.mrBedfort(textStyle: textTheme.headline2), + headline3: GoogleFonts.mrBedfort(textStyle: textTheme.headline3), + headline4: GoogleFonts.mrBedfort(textStyle: textTheme.headline4), + headline5: GoogleFonts.mrBedfort(textStyle: textTheme.headline5), + headline6: GoogleFonts.mrBedfort(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mrBedfort(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mrBedfort(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mrBedfort(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mrBedfort(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mrBedfort(textStyle: textTheme.caption), + button: GoogleFonts.mrBedfort(textStyle: textTheme.button), + overline: GoogleFonts.mrBedfort(textStyle: textTheme.overline), + ); + } + + /// Applies the Mr Dafoe font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mr+Dafoe + static TextStyle mrDafoe({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7130e498cceb99869e8233972404152d7f191ca5b5e37435cbd7b31758dec294', + 47928, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MrDafoe', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mr Dafoe font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mr+Dafoe + static TextTheme mrDafoeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mrDafoe(textStyle: textTheme.headline1), + headline2: GoogleFonts.mrDafoe(textStyle: textTheme.headline2), + headline3: GoogleFonts.mrDafoe(textStyle: textTheme.headline3), + headline4: GoogleFonts.mrDafoe(textStyle: textTheme.headline4), + headline5: GoogleFonts.mrDafoe(textStyle: textTheme.headline5), + headline6: GoogleFonts.mrDafoe(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mrDafoe(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mrDafoe(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mrDafoe(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mrDafoe(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mrDafoe(textStyle: textTheme.caption), + button: GoogleFonts.mrDafoe(textStyle: textTheme.button), + overline: GoogleFonts.mrDafoe(textStyle: textTheme.overline), + ); + } + + /// Applies the Mr De Haviland font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mr+De+Haviland + static TextStyle mrDeHaviland({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd8eabbdbc1c25c4982d316b366f4cd39f1d12589d7442ec03923353e8b739132', + 44624, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MrDeHaviland', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mr De Haviland font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mr+De+Haviland + static TextTheme mrDeHavilandTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mrDeHaviland(textStyle: textTheme.headline1), + headline2: GoogleFonts.mrDeHaviland(textStyle: textTheme.headline2), + headline3: GoogleFonts.mrDeHaviland(textStyle: textTheme.headline3), + headline4: GoogleFonts.mrDeHaviland(textStyle: textTheme.headline4), + headline5: GoogleFonts.mrDeHaviland(textStyle: textTheme.headline5), + headline6: GoogleFonts.mrDeHaviland(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mrDeHaviland(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mrDeHaviland(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mrDeHaviland(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mrDeHaviland(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mrDeHaviland(textStyle: textTheme.caption), + button: GoogleFonts.mrDeHaviland(textStyle: textTheme.button), + overline: GoogleFonts.mrDeHaviland(textStyle: textTheme.overline), + ); + } + + /// Applies the Mrs Saint Delafield font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mrs+Saint+Delafield + static TextStyle mrsSaintDelafield({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b864d74de51aa37c270217c9c01320fd78f8b1c23077b4ef0c20cb697a41d899', + 49092, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MrsSaintDelafield', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mrs Saint Delafield font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mrs+Saint+Delafield + static TextTheme mrsSaintDelafieldTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.headline1), + headline2: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.headline2), + headline3: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.headline3), + headline4: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.headline4), + headline5: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.headline5), + headline6: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.caption), + button: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.button), + overline: GoogleFonts.mrsSaintDelafield(textStyle: textTheme.overline), + ); + } + + /// Applies the Mrs Sheppards font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mrs+Sheppards + static TextStyle mrsSheppards({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e405bf3cb038e30fac744c48068e8e3687a50c1b5cff874a57476b07f44b3b04', + 42336, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MrsSheppards', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mrs Sheppards font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mrs+Sheppards + static TextTheme mrsSheppardsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mrsSheppards(textStyle: textTheme.headline1), + headline2: GoogleFonts.mrsSheppards(textStyle: textTheme.headline2), + headline3: GoogleFonts.mrsSheppards(textStyle: textTheme.headline3), + headline4: GoogleFonts.mrsSheppards(textStyle: textTheme.headline4), + headline5: GoogleFonts.mrsSheppards(textStyle: textTheme.headline5), + headline6: GoogleFonts.mrsSheppards(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mrsSheppards(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mrsSheppards(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mrsSheppards(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mrsSheppards(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mrsSheppards(textStyle: textTheme.caption), + button: GoogleFonts.mrsSheppards(textStyle: textTheme.button), + overline: GoogleFonts.mrsSheppards(textStyle: textTheme.overline), + ); + } + + /// Applies the Mukta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mukta + static TextStyle mukta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a09d53371d63ff1a2007025ba620e2d49a10d6fa1cfd9771079b881fb10260b', + 302792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'afd7468706fa0ed52e0b848541b4e7443296d0e40213e7903e1d85de5b78c259', + 299500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7a26594f60f0a156f11685565fac877993f2081741d7eafc7a67d82010f730f8', + 303624, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a8691ddcdc7892d423b4906d2316da09de32309d3d68b21b5d3d640e28901896', + 297420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7d8e1e1ee78a611bd420d3ad4fb7812e49164acc68f473ee133666fe5376d477', + 293224, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e6fcac27938712ebc52654eee052ffee3cb5608feef54db55a22964fe8c7d974', + 294800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '861cea1030f95eb8f746e95524c8440b56afdd6606e07782193fe436cc52f46b', + 294532, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mukta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mukta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mukta + static TextTheme muktaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mukta(textStyle: textTheme.headline1), + headline2: GoogleFonts.mukta(textStyle: textTheme.headline2), + headline3: GoogleFonts.mukta(textStyle: textTheme.headline3), + headline4: GoogleFonts.mukta(textStyle: textTheme.headline4), + headline5: GoogleFonts.mukta(textStyle: textTheme.headline5), + headline6: GoogleFonts.mukta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mukta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mukta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mukta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mukta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mukta(textStyle: textTheme.caption), + button: GoogleFonts.mukta(textStyle: textTheme.button), + overline: GoogleFonts.mukta(textStyle: textTheme.overline), + ); + } + + /// Applies the Mukta Mahee font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mukta+Mahee + static TextStyle muktaMahee({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'deb2926281b06e4d02371cd3f6f4883d13a38514549e581c6269cb16250c5a63', + 159216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '448813ce747d7ccc8e7b380c48932fe537454f9a86ac18052fa515874298334e', + 158236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e185695b95ca5300e131bf6cf64a2442b7517874432a1a82f968ee61ed116717', + 159340, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e224c5c38bb5fe5efb69e8392dfd476427211ddb37a97f4fd77b807d5aad8b7c', + 155880, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f2c62fede24e5fe712f6f59500c550749c89e47b21cb749ea96f447ace17a57a', + 155776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0bde54d9dc9448b8d81abd2d849dade4e04c4b7c4ec8565ccb09e80f0fd2be99', + 155836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '561a2604bd143dc10cc3499ba4e3c7eef16b6705db72db31da22ad356b76feb5', + 155592, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MuktaMahee', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mukta Mahee font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mukta+Mahee + static TextTheme muktaMaheeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.muktaMahee(textStyle: textTheme.headline1), + headline2: GoogleFonts.muktaMahee(textStyle: textTheme.headline2), + headline3: GoogleFonts.muktaMahee(textStyle: textTheme.headline3), + headline4: GoogleFonts.muktaMahee(textStyle: textTheme.headline4), + headline5: GoogleFonts.muktaMahee(textStyle: textTheme.headline5), + headline6: GoogleFonts.muktaMahee(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.muktaMahee(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.muktaMahee(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.muktaMahee(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.muktaMahee(textStyle: textTheme.bodyText2), + caption: GoogleFonts.muktaMahee(textStyle: textTheme.caption), + button: GoogleFonts.muktaMahee(textStyle: textTheme.button), + overline: GoogleFonts.muktaMahee(textStyle: textTheme.overline), + ); + } + + /// Applies the Mukta Malar font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mukta+Malar + static TextStyle muktaMalar({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ae35f34ee0aecd84455b8074812b101d5d11bc4ae0ada4a90c3e6963cf1b93c', + 176484, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2d5b4747199d5f755d4d21f2dfb23f52cbeba3d94d82a526575d63a6be36c99b', + 175612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e58544a43eef9e9b107ca973ca2d3233a1e15b8eddffcc73a3cb767a82c86fd6', + 175612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '05e1d0c09c615550bb87408248e0d42ce654f55e0757f1fa6f4f93323f8c8121', + 171128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e4f26dcbc25c0f26d1fce4a3558f4aacdf8089148a638079c3353f6049ae21e9', + 171032, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bacffc5f82b7219e1a4ff85b030aca1a5f805e0a1224534a6f2bfb01e4bd61cc', + 171620, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '848b7be10b4d701ac02f5f2208071858aa399b564d503cd2e4ca428d25886da9', + 172316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MuktaMalar', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mukta Malar font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mukta+Malar + static TextTheme muktaMalarTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.muktaMalar(textStyle: textTheme.headline1), + headline2: GoogleFonts.muktaMalar(textStyle: textTheme.headline2), + headline3: GoogleFonts.muktaMalar(textStyle: textTheme.headline3), + headline4: GoogleFonts.muktaMalar(textStyle: textTheme.headline4), + headline5: GoogleFonts.muktaMalar(textStyle: textTheme.headline5), + headline6: GoogleFonts.muktaMalar(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.muktaMalar(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.muktaMalar(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.muktaMalar(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.muktaMalar(textStyle: textTheme.bodyText2), + caption: GoogleFonts.muktaMalar(textStyle: textTheme.caption), + button: GoogleFonts.muktaMalar(textStyle: textTheme.button), + overline: GoogleFonts.muktaMalar(textStyle: textTheme.overline), + ); + } + + /// Applies the Mukta Vaani font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mukta+Vaani + static TextStyle muktaVaani({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '29b1cbb5d158be22b06c5c6af360d55da720b6c8a7b9b218dd184cbfc2a97885', + 346528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b273ecb298d23bd198fdcf92d8137f3bb392abc1843e055c814580f254f3a4d2', + 354676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '89cee2e2edc87643ff46594bc56da0b32e9f4fd9acb8b87979dda5d4da2bccb6', + 344512, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5da49257aaa42ad92f5abf8235b58834033471554455112dea55a3a00761f1c0', + 351576, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7f14d4f17f14c4106a7fe56a9e591a9ef7d89e8dee221d5b4d359cac2667f138', + 349868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6e1e0572586f30b3b9b794997b0b26cc725d41d3348eda988662d14d1fdc89b4', + 349956, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '09f9de8c00ef147925056cf61c1d7e324b50fd29b1fe15c95500c506ddd79aeb', + 342704, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MuktaVaani', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mukta Vaani font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mukta+Vaani + static TextTheme muktaVaaniTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.muktaVaani(textStyle: textTheme.headline1), + headline2: GoogleFonts.muktaVaani(textStyle: textTheme.headline2), + headline3: GoogleFonts.muktaVaani(textStyle: textTheme.headline3), + headline4: GoogleFonts.muktaVaani(textStyle: textTheme.headline4), + headline5: GoogleFonts.muktaVaani(textStyle: textTheme.headline5), + headline6: GoogleFonts.muktaVaani(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.muktaVaani(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.muktaVaani(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.muktaVaani(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.muktaVaani(textStyle: textTheme.bodyText2), + caption: GoogleFonts.muktaVaani(textStyle: textTheme.caption), + button: GoogleFonts.muktaVaani(textStyle: textTheme.button), + overline: GoogleFonts.muktaVaani(textStyle: textTheme.overline), + ); + } + + /// Applies the Mulish font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mulish + static TextStyle mulish({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dc074694927dbce58bd63b595cc483ded638a26c22f710d73845272851b2213c', + 54528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dbbab3b59151f460bdf1f12758d040c9e37221fdefdbf9fd481a7f50e9498569', + 54552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd52df2665a07c5362afe32bf698279bafe9ab2a37600e7497bda6db762c77ee8', + 54520, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd9b94a4c139afb4207b54e2c678fb1f22ec963e2cee2971851ac2ca63db17bd6', + 54524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd471469a6b88140da82d8d273049b27e5b3aceabdc838a96638f37249ebe794a', + 54564, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8bc3182a11f1754d82bfd883278a476fd5aed240f3563114703b3a2e6639f15', + 54496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '32d3d52cf3d09684d2cd75cd09bc7d04f22dc8d3c814f83cad9b392425c751e4', + 54564, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '74162598504efb80255ca4edc6f6102f5d9c22ccbc48f6c1a46c4c61431b9a0a', + 54520, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '995c490c95855f035c47bbe977ce3a1dbf25274a927c70878e505882f289b519', + 55608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9ac161b22df9d48b43d4da45af4f3007eab8333ff64f40a93632161598120480', + 55616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2c129f664b0b43ed35946c2fdedabba6b0e6d4bcc9aa2c9962a69c4e54854db5', + 55524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '69b8fe61efaa11f5f869f2ae7b076bfdc68fe0ac6eda05b3937509de8893c377', + 55616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c4afaac18b96a0f0e80cc5f1ec8636eaf19a44ba4f3fa9c7c93779e658d030af', + 55668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9133e97bd644680203fea17a613c54fcd160a6d4ca9e3b941762359ba186ea67', + 55572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9f4fd9f9b2e55994361ce16aa2163406eeb8bc74416b02d1f90a254477655d30', + 55652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '41d7defaa9cd7ffb2ed9a76faa3a89f305b1359f572133232ecc1d35a18e2fe7', + 55616, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Mulish', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mulish font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mulish + static TextTheme mulishTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mulish(textStyle: textTheme.headline1), + headline2: GoogleFonts.mulish(textStyle: textTheme.headline2), + headline3: GoogleFonts.mulish(textStyle: textTheme.headline3), + headline4: GoogleFonts.mulish(textStyle: textTheme.headline4), + headline5: GoogleFonts.mulish(textStyle: textTheme.headline5), + headline6: GoogleFonts.mulish(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mulish(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mulish(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mulish(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mulish(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mulish(textStyle: textTheme.caption), + button: GoogleFonts.mulish(textStyle: textTheme.button), + overline: GoogleFonts.mulish(textStyle: textTheme.overline), + ); + } + + /// Applies the MuseoModerno font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/MuseoModerno + static TextStyle museoModerno({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3cac957efd66e1fe4dc998a948578d0471cf18aa442a9a8f2f4d9174f5c1ae85', + 45816, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b98ce4cb9c3f6d5b3a8e1a9e40d8ddf9fefca2892751c78af2a6341fd75ea039', + 45836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ce4f8c87125d83b607172cc4b2726e1802fb331be7e2cfee607108fc3b84686', + 45792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '04f3a18b5a0e5e4fe7d617eac6117871f7181659f7fc1c6b05ff948d6e287e8a', + 45740, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd9998799cff52088708609e7e5f54ee0d8a833144d937036e932bb7d36c977be', + 45720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '812e04e6d5e42c6dcb8b016e5174959bd94fee17658653b9c2c2d9204fd75aba', + 45744, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c5e29fd93e2824b7d21f84cc95d9a04adc84707e76fa2152184f883aa09802b9', + 45684, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6bdab1653eee057851ba7fff16af3f2aed3fcb223f32fdd0b3eb31f5488dcd80', + 45700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0fe3f5ff8e5303a6624b6ffb654c57a87c095ac8172cd65d3dc1eeddb96933b4', + 45652, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MuseoModerno', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the MuseoModerno font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/MuseoModerno + static TextTheme museoModernoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.museoModerno(textStyle: textTheme.headline1), + headline2: GoogleFonts.museoModerno(textStyle: textTheme.headline2), + headline3: GoogleFonts.museoModerno(textStyle: textTheme.headline3), + headline4: GoogleFonts.museoModerno(textStyle: textTheme.headline4), + headline5: GoogleFonts.museoModerno(textStyle: textTheme.headline5), + headline6: GoogleFonts.museoModerno(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.museoModerno(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.museoModerno(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.museoModerno(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.museoModerno(textStyle: textTheme.bodyText2), + caption: GoogleFonts.museoModerno(textStyle: textTheme.caption), + button: GoogleFonts.museoModerno(textStyle: textTheme.button), + overline: GoogleFonts.museoModerno(textStyle: textTheme.overline), + ); + } + + /// Applies the Mystery Quest font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mystery+Quest + static TextStyle mysteryQuest({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '45f3b5f241a077e28d45ad6f0d542f3d9f2e2204a6d7ba78f4438c3960639003', + 41708, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'MysteryQuest', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Mystery Quest font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Mystery+Quest + static TextTheme mysteryQuestTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.mysteryQuest(textStyle: textTheme.headline1), + headline2: GoogleFonts.mysteryQuest(textStyle: textTheme.headline2), + headline3: GoogleFonts.mysteryQuest(textStyle: textTheme.headline3), + headline4: GoogleFonts.mysteryQuest(textStyle: textTheme.headline4), + headline5: GoogleFonts.mysteryQuest(textStyle: textTheme.headline5), + headline6: GoogleFonts.mysteryQuest(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.mysteryQuest(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.mysteryQuest(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.mysteryQuest(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.mysteryQuest(textStyle: textTheme.bodyText2), + caption: GoogleFonts.mysteryQuest(textStyle: textTheme.caption), + button: GoogleFonts.mysteryQuest(textStyle: textTheme.button), + overline: GoogleFonts.mysteryQuest(textStyle: textTheme.overline), + ); + } + + /// Applies the NTR font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/NTR + static TextStyle ntr({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a81d9625c6e1cc5d20f097e68c4604194966a833b0bacfa533a882ad3fe92592', + 197756, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NTR', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the NTR font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/NTR + static TextTheme ntrTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ntr(textStyle: textTheme.headline1), + headline2: GoogleFonts.ntr(textStyle: textTheme.headline2), + headline3: GoogleFonts.ntr(textStyle: textTheme.headline3), + headline4: GoogleFonts.ntr(textStyle: textTheme.headline4), + headline5: GoogleFonts.ntr(textStyle: textTheme.headline5), + headline6: GoogleFonts.ntr(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ntr(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ntr(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ntr(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ntr(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ntr(textStyle: textTheme.caption), + button: GoogleFonts.ntr(textStyle: textTheme.button), + overline: GoogleFonts.ntr(textStyle: textTheme.overline), + ); + } + + /// Applies the Nanum Brush Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Brush+Script + static TextStyle nanumBrushScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e99eadfe916b8afa1065e368b0c06a725089504ffa9cd2bb1832cbe59ecb4822', + 2740080, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NanumBrushScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nanum Brush Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Brush+Script + static TextTheme nanumBrushScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nanumBrushScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.nanumBrushScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.nanumBrushScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.nanumBrushScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.nanumBrushScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.nanumBrushScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nanumBrushScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nanumBrushScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nanumBrushScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nanumBrushScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nanumBrushScript(textStyle: textTheme.caption), + button: GoogleFonts.nanumBrushScript(textStyle: textTheme.button), + overline: GoogleFonts.nanumBrushScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Nanum Gothic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Gothic + static TextStyle nanumGothic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '384554f92bd4d754bd8750f8885c456c5264d6814731376178dd0727fcf2d98c', + 2879864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '66257cb7dbb7d38dd5d9b0c7a1f9df7ae828f4a2a79a37070603405220e9f32b', + 2891140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '560717e4c667f1bdf58f6426ef133e74637eb3c1868feff814bb8a5b707e6880', + 2951544, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NanumGothic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nanum Gothic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Gothic + static TextTheme nanumGothicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nanumGothic(textStyle: textTheme.headline1), + headline2: GoogleFonts.nanumGothic(textStyle: textTheme.headline2), + headline3: GoogleFonts.nanumGothic(textStyle: textTheme.headline3), + headline4: GoogleFonts.nanumGothic(textStyle: textTheme.headline4), + headline5: GoogleFonts.nanumGothic(textStyle: textTheme.headline5), + headline6: GoogleFonts.nanumGothic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nanumGothic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nanumGothic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nanumGothic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nanumGothic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nanumGothic(textStyle: textTheme.caption), + button: GoogleFonts.nanumGothic(textStyle: textTheme.button), + overline: GoogleFonts.nanumGothic(textStyle: textTheme.overline), + ); + } + + /// Applies the Nanum Gothic Coding font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Gothic+Coding + static TextStyle nanumGothicCoding({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '87aa4e424fb41b2eb66974966afbb9b9d113444c73ddfec8d9960d1c9f15ca2a', + 1432612, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bfd061e7ac41bb2ac41c1b32e194b64a92ea19253afc0008d1a5e58e330434f9', + 1458744, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NanumGothicCoding', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nanum Gothic Coding font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Gothic+Coding + static TextTheme nanumGothicCodingTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nanumGothicCoding(textStyle: textTheme.headline1), + headline2: GoogleFonts.nanumGothicCoding(textStyle: textTheme.headline2), + headline3: GoogleFonts.nanumGothicCoding(textStyle: textTheme.headline3), + headline4: GoogleFonts.nanumGothicCoding(textStyle: textTheme.headline4), + headline5: GoogleFonts.nanumGothicCoding(textStyle: textTheme.headline5), + headline6: GoogleFonts.nanumGothicCoding(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nanumGothicCoding(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nanumGothicCoding(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nanumGothicCoding(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nanumGothicCoding(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nanumGothicCoding(textStyle: textTheme.caption), + button: GoogleFonts.nanumGothicCoding(textStyle: textTheme.button), + overline: GoogleFonts.nanumGothicCoding(textStyle: textTheme.overline), + ); + } + + /// Applies the Nanum Myeongjo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Myeongjo + static TextStyle nanumMyeongjo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3df71af0cacc55f9ee8f8e5e35a48672e379aefb187f3ae133a8fd5100c3810f', + 2167668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c78488cd4af94bf04459b776f90fbe7942e11af15dda46bd856a1abc0523ae11', + 2241272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2da8166e69673863a98b44792cb5b54e1a13b597c11dca437783e5a9336cfa9c', + 2293712, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NanumMyeongjo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nanum Myeongjo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Myeongjo + static TextTheme nanumMyeongjoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nanumMyeongjo(textStyle: textTheme.headline1), + headline2: GoogleFonts.nanumMyeongjo(textStyle: textTheme.headline2), + headline3: GoogleFonts.nanumMyeongjo(textStyle: textTheme.headline3), + headline4: GoogleFonts.nanumMyeongjo(textStyle: textTheme.headline4), + headline5: GoogleFonts.nanumMyeongjo(textStyle: textTheme.headline5), + headline6: GoogleFonts.nanumMyeongjo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nanumMyeongjo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nanumMyeongjo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nanumMyeongjo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nanumMyeongjo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nanumMyeongjo(textStyle: textTheme.caption), + button: GoogleFonts.nanumMyeongjo(textStyle: textTheme.button), + overline: GoogleFonts.nanumMyeongjo(textStyle: textTheme.overline), + ); + } + + /// Applies the Nanum Pen Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Pen+Script + static TextStyle nanumPenScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2e0017c2efd9b7de2cf1b9d90c99ebfd4be478763a4f265915ce2302d928a6f4', + 2533592, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NanumPenScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nanum Pen Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nanum+Pen+Script + static TextTheme nanumPenScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nanumPenScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.nanumPenScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.nanumPenScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.nanumPenScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.nanumPenScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.nanumPenScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nanumPenScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nanumPenScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nanumPenScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nanumPenScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nanumPenScript(textStyle: textTheme.caption), + button: GoogleFonts.nanumPenScript(textStyle: textTheme.button), + overline: GoogleFonts.nanumPenScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Nerko One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nerko+One + static TextStyle nerkoOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '878f83135fb709ecde10c8995a744ad075b82815f89387dc1804f7a288fe9ff6', + 102004, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NerkoOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nerko One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nerko+One + static TextTheme nerkoOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nerkoOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.nerkoOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.nerkoOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.nerkoOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.nerkoOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.nerkoOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nerkoOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nerkoOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nerkoOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nerkoOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nerkoOne(textStyle: textTheme.caption), + button: GoogleFonts.nerkoOne(textStyle: textTheme.button), + overline: GoogleFonts.nerkoOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Neucha font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Neucha + static TextStyle neucha({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1e6e5577b90d7925c65ee7e36c988d5da0c8abd382abf4f7d7a5cbc0ab477a99', + 74808, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Neucha', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Neucha font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Neucha + static TextTheme neuchaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.neucha(textStyle: textTheme.headline1), + headline2: GoogleFonts.neucha(textStyle: textTheme.headline2), + headline3: GoogleFonts.neucha(textStyle: textTheme.headline3), + headline4: GoogleFonts.neucha(textStyle: textTheme.headline4), + headline5: GoogleFonts.neucha(textStyle: textTheme.headline5), + headline6: GoogleFonts.neucha(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.neucha(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.neucha(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.neucha(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.neucha(textStyle: textTheme.bodyText2), + caption: GoogleFonts.neucha(textStyle: textTheme.caption), + button: GoogleFonts.neucha(textStyle: textTheme.button), + overline: GoogleFonts.neucha(textStyle: textTheme.overline), + ); + } + + /// Applies the Neuton font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Neuton + static TextStyle neuton({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '52a1f786965c5e1a5ddb72c3453133e67248c6daa74320a01e034161e4476a0f', + 36124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ff0297b52f6d34d72fb14e197dd0504d57fdb2769b98619facc41590e900c8e9', + 35804, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2147893351f8ace96b011dcc7c1c826ba84daac170ed6538e0456e5ed8ffe947', + 40944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8be52f34f889303ed24d24ec94bc56c8fb7130049db10eb3983aab619a05bcb5', + 38564, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1c83bf4d18e666ffe37bb75b7005b9ad99f4166347cbce93e1f798c45954f87e', + 37052, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2ccde11ee55979183e280ea4860ec28e4fd88da81c66a8eee82963c4fe2befca', + 36760, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Neuton', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Neuton font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Neuton + static TextTheme neutonTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.neuton(textStyle: textTheme.headline1), + headline2: GoogleFonts.neuton(textStyle: textTheme.headline2), + headline3: GoogleFonts.neuton(textStyle: textTheme.headline3), + headline4: GoogleFonts.neuton(textStyle: textTheme.headline4), + headline5: GoogleFonts.neuton(textStyle: textTheme.headline5), + headline6: GoogleFonts.neuton(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.neuton(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.neuton(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.neuton(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.neuton(textStyle: textTheme.bodyText2), + caption: GoogleFonts.neuton(textStyle: textTheme.caption), + button: GoogleFonts.neuton(textStyle: textTheme.button), + overline: GoogleFonts.neuton(textStyle: textTheme.overline), + ); + } + + /// Applies the New Rocker font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/New+Rocker + static TextStyle newRocker({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '20dd1e4e2d3c0003707b649a59ebb5a729e108cc20929f1a1c06bb03319b07d7', + 128612, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NewRocker', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the New Rocker font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/New+Rocker + static TextTheme newRockerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.newRocker(textStyle: textTheme.headline1), + headline2: GoogleFonts.newRocker(textStyle: textTheme.headline2), + headline3: GoogleFonts.newRocker(textStyle: textTheme.headline3), + headline4: GoogleFonts.newRocker(textStyle: textTheme.headline4), + headline5: GoogleFonts.newRocker(textStyle: textTheme.headline5), + headline6: GoogleFonts.newRocker(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.newRocker(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.newRocker(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.newRocker(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.newRocker(textStyle: textTheme.bodyText2), + caption: GoogleFonts.newRocker(textStyle: textTheme.caption), + button: GoogleFonts.newRocker(textStyle: textTheme.button), + overline: GoogleFonts.newRocker(textStyle: textTheme.overline), + ); + } + + /// Applies the News Cycle font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/News+Cycle + static TextStyle newsCycle({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9dc74270959405ee468a6ea83452b01a8075067bf71cb96c8097511477f8aec6', + 178676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '301d13c6e3a40093c2244566226928b2e8bd2843d5cb06302c5c30b44c3d4bc2', + 60472, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NewsCycle', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the News Cycle font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/News+Cycle + static TextTheme newsCycleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.newsCycle(textStyle: textTheme.headline1), + headline2: GoogleFonts.newsCycle(textStyle: textTheme.headline2), + headline3: GoogleFonts.newsCycle(textStyle: textTheme.headline3), + headline4: GoogleFonts.newsCycle(textStyle: textTheme.headline4), + headline5: GoogleFonts.newsCycle(textStyle: textTheme.headline5), + headline6: GoogleFonts.newsCycle(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.newsCycle(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.newsCycle(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.newsCycle(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.newsCycle(textStyle: textTheme.bodyText2), + caption: GoogleFonts.newsCycle(textStyle: textTheme.caption), + button: GoogleFonts.newsCycle(textStyle: textTheme.button), + overline: GoogleFonts.newsCycle(textStyle: textTheme.overline), + ); + } + + /// Applies the Niconne font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Niconne + static TextStyle niconne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c5d99f37c7fc29904227e4a5909347b604c87dbe244293db4353ba24f5263d28', + 45568, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Niconne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Niconne font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Niconne + static TextTheme niconneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.niconne(textStyle: textTheme.headline1), + headline2: GoogleFonts.niconne(textStyle: textTheme.headline2), + headline3: GoogleFonts.niconne(textStyle: textTheme.headline3), + headline4: GoogleFonts.niconne(textStyle: textTheme.headline4), + headline5: GoogleFonts.niconne(textStyle: textTheme.headline5), + headline6: GoogleFonts.niconne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.niconne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.niconne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.niconne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.niconne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.niconne(textStyle: textTheme.caption), + button: GoogleFonts.niconne(textStyle: textTheme.button), + overline: GoogleFonts.niconne(textStyle: textTheme.overline), + ); + } + + /// Applies the Niramit font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Niramit + static TextStyle niramit({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e92669e514d741863c49ee66189090f4d5dca5b6a9d34ccbe435b2f5af660c42', + 89528, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd2d4697e15bf89f5f5ef604984ccc6a79f078de6f91e60deae5736de825110bc', + 92352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cc8b41b318e8ef4a063f6a1d3c4b2b8b07029e70b412f4aff994ee4849efb09c', + 89344, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8b5560e9959b3ffe8583ea5591a0852f3cb9dd7d8f256327fd1dfa761aebbc97', + 91988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b73b7564f064368ecc427a55f6f52ab3191726827cc1b6c8fe10059308a2c576', + 89224, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f2f02627999eb05690e589cbb7e0c1ab1e977f24c976bbeafab5c8bb041cb23c', + 91860, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd57314c8b28aa732f0904f616db80bd02f471e91a0c0620454016ddb37200371', + 89172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3c7d65b0b7438466a6707ae7ee57b82aad56e02798b2bd582110803cfd632e40', + 91624, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '932bdc0ea4e9406b713a29b1a936c3bfba71853a8f834dcf9129914d6ed2f0e7', + 89112, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'deb26883a193441eb594a0e8e42bac1d2d1ac822053c3bd7fcaf06161fbc281d', + 91760, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '67d40f2a9e3f3cc8c4e0873f0c6aa8b2db46210c344b6805eb7a3280b6430a85', + 89328, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2d5a53eeb80546748e52c84452b17b60d1e4abfcd7e01f6d6f909ad0446c9f19', + 91772, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Niramit', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Niramit font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Niramit + static TextTheme niramitTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.niramit(textStyle: textTheme.headline1), + headline2: GoogleFonts.niramit(textStyle: textTheme.headline2), + headline3: GoogleFonts.niramit(textStyle: textTheme.headline3), + headline4: GoogleFonts.niramit(textStyle: textTheme.headline4), + headline5: GoogleFonts.niramit(textStyle: textTheme.headline5), + headline6: GoogleFonts.niramit(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.niramit(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.niramit(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.niramit(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.niramit(textStyle: textTheme.bodyText2), + caption: GoogleFonts.niramit(textStyle: textTheme.caption), + button: GoogleFonts.niramit(textStyle: textTheme.button), + overline: GoogleFonts.niramit(textStyle: textTheme.overline), + ); + } + + /// Applies the Nixie One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nixie+One + static TextStyle nixieOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '087111fe60593408bf58ff7befff4b557a237a72d80e56ad3727d99693b4a087', + 52532, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NixieOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nixie One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nixie+One + static TextTheme nixieOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nixieOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.nixieOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.nixieOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.nixieOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.nixieOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.nixieOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nixieOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nixieOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nixieOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nixieOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nixieOne(textStyle: textTheme.caption), + button: GoogleFonts.nixieOne(textStyle: textTheme.button), + overline: GoogleFonts.nixieOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Nobile font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nobile + static TextStyle nobile({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd0fcaab1c3dc981d4dcbe2840d5a12039de03b68f4f2736ac648e6eb339249c1', + 35992, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '88fda8926ed6fdf634aeaf690e2d21e66e8e88231993df94bf3b2359a617491b', + 44588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '809ce5e05bb84a8872fd7ec295e71892fab43593a18179bb43c2a0f94cca53d2', + 34836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c889dceebe4337abc148cab8adbcb5ad8e6277635316b13a75afb02db100212d', + 44532, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Nobile', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nobile font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nobile + static TextTheme nobileTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nobile(textStyle: textTheme.headline1), + headline2: GoogleFonts.nobile(textStyle: textTheme.headline2), + headline3: GoogleFonts.nobile(textStyle: textTheme.headline3), + headline4: GoogleFonts.nobile(textStyle: textTheme.headline4), + headline5: GoogleFonts.nobile(textStyle: textTheme.headline5), + headline6: GoogleFonts.nobile(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nobile(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nobile(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nobile(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nobile(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nobile(textStyle: textTheme.caption), + button: GoogleFonts.nobile(textStyle: textTheme.button), + overline: GoogleFonts.nobile(textStyle: textTheme.overline), + ); + } + + /// Applies the Norican font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Norican + static TextStyle norican({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f4fbc9fb71760f8b74862d7d705863f375de95bb99192acfeca61ab3185b6468', + 46812, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Norican', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Norican font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Norican + static TextTheme noricanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.norican(textStyle: textTheme.headline1), + headline2: GoogleFonts.norican(textStyle: textTheme.headline2), + headline3: GoogleFonts.norican(textStyle: textTheme.headline3), + headline4: GoogleFonts.norican(textStyle: textTheme.headline4), + headline5: GoogleFonts.norican(textStyle: textTheme.headline5), + headline6: GoogleFonts.norican(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.norican(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.norican(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.norican(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.norican(textStyle: textTheme.bodyText2), + caption: GoogleFonts.norican(textStyle: textTheme.caption), + button: GoogleFonts.norican(textStyle: textTheme.button), + overline: GoogleFonts.norican(textStyle: textTheme.overline), + ); + } + + /// Applies the Nosifer font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nosifer + static TextStyle nosifer({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'db6d798eb7a5adc1193a4757fba4b3bf0f2bf34f9456f9b72dd63e8c21a304e3', + 43228, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Nosifer', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nosifer font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nosifer + static TextTheme nosiferTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nosifer(textStyle: textTheme.headline1), + headline2: GoogleFonts.nosifer(textStyle: textTheme.headline2), + headline3: GoogleFonts.nosifer(textStyle: textTheme.headline3), + headline4: GoogleFonts.nosifer(textStyle: textTheme.headline4), + headline5: GoogleFonts.nosifer(textStyle: textTheme.headline5), + headline6: GoogleFonts.nosifer(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nosifer(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nosifer(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nosifer(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nosifer(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nosifer(textStyle: textTheme.caption), + button: GoogleFonts.nosifer(textStyle: textTheme.button), + overline: GoogleFonts.nosifer(textStyle: textTheme.overline), + ); + } + + /// Applies the Notable font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Notable + static TextStyle notable({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '17b2981242270d0087017ea92cac3bb8bad89c43bd4d9907ded7255e92dbc8aa', + 24588, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Notable', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Notable font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Notable + static TextTheme notableTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.notable(textStyle: textTheme.headline1), + headline2: GoogleFonts.notable(textStyle: textTheme.headline2), + headline3: GoogleFonts.notable(textStyle: textTheme.headline3), + headline4: GoogleFonts.notable(textStyle: textTheme.headline4), + headline5: GoogleFonts.notable(textStyle: textTheme.headline5), + headline6: GoogleFonts.notable(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.notable(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.notable(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.notable(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.notable(textStyle: textTheme.bodyText2), + caption: GoogleFonts.notable(textStyle: textTheme.caption), + button: GoogleFonts.notable(textStyle: textTheme.button), + overline: GoogleFonts.notable(textStyle: textTheme.overline), + ); + } + + /// Applies the Nothing You Could Do font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nothing+You+Could+Do + static TextStyle nothingYouCouldDo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'be0f234b092c9c449e02760df9a51ff0a1bb5867a70825d7074238c1e26e9664', + 34872, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NothingYouCouldDo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nothing You Could Do font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nothing+You+Could+Do + static TextTheme nothingYouCouldDoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.headline1), + headline2: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.headline2), + headline3: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.headline3), + headline4: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.headline4), + headline5: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.headline5), + headline6: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.caption), + button: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.button), + overline: GoogleFonts.nothingYouCouldDo(textStyle: textTheme.overline), + ); + } + + /// Applies the Noticia Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Noticia+Text + static TextStyle noticiaText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8aa05df6db1fd8277eb2791ce573473314c741b8b6b0779c1f5156a33c24e54c', + 82260, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'eae99ba15e584587a39b40e2c6b930d2c6da34555025ef2fcecdad8b5d1096ec', + 66644, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '16462e88dea5568eff3522e2b0e80ac4943e7ade072e98099a0ced914809837a', + 81364, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '89293c9cb0897a9fbf4e63241a6b72e62599bf45fe58a6163b953a9c980ad1f8', + 65616, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NoticiaText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Noticia Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Noticia+Text + static TextTheme noticiaTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.noticiaText(textStyle: textTheme.headline1), + headline2: GoogleFonts.noticiaText(textStyle: textTheme.headline2), + headline3: GoogleFonts.noticiaText(textStyle: textTheme.headline3), + headline4: GoogleFonts.noticiaText(textStyle: textTheme.headline4), + headline5: GoogleFonts.noticiaText(textStyle: textTheme.headline5), + headline6: GoogleFonts.noticiaText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.noticiaText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.noticiaText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.noticiaText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.noticiaText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.noticiaText(textStyle: textTheme.caption), + button: GoogleFonts.noticiaText(textStyle: textTheme.button), + overline: GoogleFonts.noticiaText(textStyle: textTheme.overline), + ); + } + + /// Applies the Noto Color Emoji Compat font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Noto+Color+Emoji+Compat + static TextStyle notoColorEmojiCompat({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91b16ef6f3c56ba2d6efbdc0ae5fcc2b585ff33e8dca237b42185a467f08ee91', + 10589920, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NotoColorEmojiCompat', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Noto Color Emoji Compat font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Noto+Color+Emoji+Compat + static TextTheme notoColorEmojiCompatTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.headline1), + headline2: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.headline2), + headline3: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.headline3), + headline4: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.headline4), + headline5: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.headline5), + headline6: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.bodyText2), + caption: GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.caption), + button: GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.button), + overline: GoogleFonts.notoColorEmojiCompat(textStyle: textTheme.overline), + ); + } + + /// Applies the Noto Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Noto+Sans + static TextStyle notoSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7ae7b625c88992d250a617f91f64e254aa6ea78ca904f1e5fc1f588f0bb9a4ef', + 310656, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3b65d8f4cdb5997c9e205e125755bec66ef6cd73fadfbf1b6b8b8592d4a952e3', + 211128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f16366c45a8cac801cadd57c692f16cf4c967e3758cf25a911f7df101c23dc11', + 307772, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2b36c5bae3f90cb9def112b8d15a224e0f0e4a0a75a5d83718690c6927872140', + 214176, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NotoSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Noto Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Noto+Sans + static TextTheme notoSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.notoSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.notoSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.notoSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.notoSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.notoSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.notoSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.notoSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.notoSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.notoSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.notoSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.notoSans(textStyle: textTheme.caption), + button: GoogleFonts.notoSans(textStyle: textTheme.button), + overline: GoogleFonts.notoSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Noto Serif font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Noto+Serif + static TextStyle notoSerif({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '756d85930a29b444fc130d6ab854e9f796a951dff740c2bedb926522aa2db185', + 219488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3a8f4b27348c68ceb866bc4d52c0eae507c8cf764c1ab8d398805aeb89e40eb6', + 220592, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b8ab5cf0042204e461a5d83a980849507daa6ef58dda05725bcfa7403675eb0d', + 220292, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fff456cbd82e58d6ca98db85fc03a22b982377a0f7e36525541d06b1eaaa1db0', + 233960, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NotoSerif', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Noto Serif font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Noto+Serif + static TextTheme notoSerifTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.notoSerif(textStyle: textTheme.headline1), + headline2: GoogleFonts.notoSerif(textStyle: textTheme.headline2), + headline3: GoogleFonts.notoSerif(textStyle: textTheme.headline3), + headline4: GoogleFonts.notoSerif(textStyle: textTheme.headline4), + headline5: GoogleFonts.notoSerif(textStyle: textTheme.headline5), + headline6: GoogleFonts.notoSerif(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.notoSerif(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.notoSerif(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.notoSerif(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.notoSerif(textStyle: textTheme.bodyText2), + caption: GoogleFonts.notoSerif(textStyle: textTheme.caption), + button: GoogleFonts.notoSerif(textStyle: textTheme.button), + overline: GoogleFonts.notoSerif(textStyle: textTheme.overline), + ); + } + + /// Applies the Nova Cut font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Cut + static TextStyle novaCut({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '543ab5f33cdf7dc59059344f4a7edc567bd3041f068be2f42c28b47d67dcd3ba', + 52852, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NovaCut', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nova Cut font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Cut + static TextTheme novaCutTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.novaCut(textStyle: textTheme.headline1), + headline2: GoogleFonts.novaCut(textStyle: textTheme.headline2), + headline3: GoogleFonts.novaCut(textStyle: textTheme.headline3), + headline4: GoogleFonts.novaCut(textStyle: textTheme.headline4), + headline5: GoogleFonts.novaCut(textStyle: textTheme.headline5), + headline6: GoogleFonts.novaCut(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.novaCut(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.novaCut(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.novaCut(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.novaCut(textStyle: textTheme.bodyText2), + caption: GoogleFonts.novaCut(textStyle: textTheme.caption), + button: GoogleFonts.novaCut(textStyle: textTheme.button), + overline: GoogleFonts.novaCut(textStyle: textTheme.overline), + ); + } + + /// Applies the Nova Flat font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Flat + static TextStyle novaFlat({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '532bddc6fc21c8561e5bcd3b4e0378be147a5f2eaff0e7e9624374551f0c4a2b', + 53976, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NovaFlat', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nova Flat font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Flat + static TextTheme novaFlatTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.novaFlat(textStyle: textTheme.headline1), + headline2: GoogleFonts.novaFlat(textStyle: textTheme.headline2), + headline3: GoogleFonts.novaFlat(textStyle: textTheme.headline3), + headline4: GoogleFonts.novaFlat(textStyle: textTheme.headline4), + headline5: GoogleFonts.novaFlat(textStyle: textTheme.headline5), + headline6: GoogleFonts.novaFlat(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.novaFlat(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.novaFlat(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.novaFlat(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.novaFlat(textStyle: textTheme.bodyText2), + caption: GoogleFonts.novaFlat(textStyle: textTheme.caption), + button: GoogleFonts.novaFlat(textStyle: textTheme.button), + overline: GoogleFonts.novaFlat(textStyle: textTheme.overline), + ); + } + + /// Applies the Nova Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Mono + static TextStyle novaMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b8d5ca79e024fdc4cd75176241d8d2b12f485ddee89219d04d8210d4f53e8919', + 156104, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NovaMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nova Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Mono + static TextTheme novaMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.novaMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.novaMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.novaMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.novaMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.novaMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.novaMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.novaMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.novaMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.novaMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.novaMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.novaMono(textStyle: textTheme.caption), + button: GoogleFonts.novaMono(textStyle: textTheme.button), + overline: GoogleFonts.novaMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Nova Oval font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Oval + static TextStyle novaOval({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '73667c60ecac141cd425d3162ed4340d8b511095054d82311ae58c07da3deba4', + 56484, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NovaOval', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nova Oval font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Oval + static TextTheme novaOvalTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.novaOval(textStyle: textTheme.headline1), + headline2: GoogleFonts.novaOval(textStyle: textTheme.headline2), + headline3: GoogleFonts.novaOval(textStyle: textTheme.headline3), + headline4: GoogleFonts.novaOval(textStyle: textTheme.headline4), + headline5: GoogleFonts.novaOval(textStyle: textTheme.headline5), + headline6: GoogleFonts.novaOval(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.novaOval(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.novaOval(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.novaOval(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.novaOval(textStyle: textTheme.bodyText2), + caption: GoogleFonts.novaOval(textStyle: textTheme.caption), + button: GoogleFonts.novaOval(textStyle: textTheme.button), + overline: GoogleFonts.novaOval(textStyle: textTheme.overline), + ); + } + + /// Applies the Nova Round font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Round + static TextStyle novaRound({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '153aad90d58ece4ea5c7af76531c3fac5f2cfd1c45563654100ee416c5250af1', + 53704, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NovaRound', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nova Round font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Round + static TextTheme novaRoundTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.novaRound(textStyle: textTheme.headline1), + headline2: GoogleFonts.novaRound(textStyle: textTheme.headline2), + headline3: GoogleFonts.novaRound(textStyle: textTheme.headline3), + headline4: GoogleFonts.novaRound(textStyle: textTheme.headline4), + headline5: GoogleFonts.novaRound(textStyle: textTheme.headline5), + headline6: GoogleFonts.novaRound(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.novaRound(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.novaRound(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.novaRound(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.novaRound(textStyle: textTheme.bodyText2), + caption: GoogleFonts.novaRound(textStyle: textTheme.caption), + button: GoogleFonts.novaRound(textStyle: textTheme.button), + overline: GoogleFonts.novaRound(textStyle: textTheme.overline), + ); + } + + /// Applies the Nova Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Script + static TextStyle novaScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9a1e6015bbc608ce441cf104443e50cf0a417624044e945f9d6f4bd0fbfd3e96', + 66560, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NovaScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nova Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Script + static TextTheme novaScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.novaScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.novaScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.novaScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.novaScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.novaScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.novaScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.novaScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.novaScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.novaScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.novaScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.novaScript(textStyle: textTheme.caption), + button: GoogleFonts.novaScript(textStyle: textTheme.button), + overline: GoogleFonts.novaScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Nova Slim font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Slim + static TextStyle novaSlim({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1b56497df8d2fd1b918c16eb9ff0e33f3d57c66a8c3b83e0d23aa0124ae67ca5', + 53708, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NovaSlim', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nova Slim font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Slim + static TextTheme novaSlimTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.novaSlim(textStyle: textTheme.headline1), + headline2: GoogleFonts.novaSlim(textStyle: textTheme.headline2), + headline3: GoogleFonts.novaSlim(textStyle: textTheme.headline3), + headline4: GoogleFonts.novaSlim(textStyle: textTheme.headline4), + headline5: GoogleFonts.novaSlim(textStyle: textTheme.headline5), + headline6: GoogleFonts.novaSlim(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.novaSlim(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.novaSlim(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.novaSlim(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.novaSlim(textStyle: textTheme.bodyText2), + caption: GoogleFonts.novaSlim(textStyle: textTheme.caption), + button: GoogleFonts.novaSlim(textStyle: textTheme.button), + overline: GoogleFonts.novaSlim(textStyle: textTheme.overline), + ); + } + + /// Applies the Nova Square font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Square + static TextStyle novaSquare({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e0a393378490eb55bf6732aca6c44a808436009d82e3d1c08bfe96e079af967c', + 49156, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NovaSquare', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nova Square font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nova+Square + static TextTheme novaSquareTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.novaSquare(textStyle: textTheme.headline1), + headline2: GoogleFonts.novaSquare(textStyle: textTheme.headline2), + headline3: GoogleFonts.novaSquare(textStyle: textTheme.headline3), + headline4: GoogleFonts.novaSquare(textStyle: textTheme.headline4), + headline5: GoogleFonts.novaSquare(textStyle: textTheme.headline5), + headline6: GoogleFonts.novaSquare(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.novaSquare(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.novaSquare(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.novaSquare(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.novaSquare(textStyle: textTheme.bodyText2), + caption: GoogleFonts.novaSquare(textStyle: textTheme.caption), + button: GoogleFonts.novaSquare(textStyle: textTheme.button), + overline: GoogleFonts.novaSquare(textStyle: textTheme.overline), + ); + } + + /// Applies the Numans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Numans + static TextStyle numans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '77ee8c9adcd406c31bd7c13355d741311f9644b995946fe712a47d15fe49907e', + 39320, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Numans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Numans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Numans + static TextTheme numansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.numans(textStyle: textTheme.headline1), + headline2: GoogleFonts.numans(textStyle: textTheme.headline2), + headline3: GoogleFonts.numans(textStyle: textTheme.headline3), + headline4: GoogleFonts.numans(textStyle: textTheme.headline4), + headline5: GoogleFonts.numans(textStyle: textTheme.headline5), + headline6: GoogleFonts.numans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.numans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.numans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.numans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.numans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.numans(textStyle: textTheme.caption), + button: GoogleFonts.numans(textStyle: textTheme.button), + overline: GoogleFonts.numans(textStyle: textTheme.overline), + ); + } + + /// Applies the Nunito font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nunito + static TextStyle nunito({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6b0fb0ec88912f1ff7a203e8c74ec905e0f2333d071fcb6aa512434f693ed426', + 84536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e542c8162e83b8b4a246d9752149784b7a910e9079625dfe29dfa33afcdacd7f', + 85516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b6d1ca92958aefa0ca13e7461a345871a0c815ceddf57dff8f143c5cefe954ac', + 84496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bac03390f60c9c7b5298d6e7849699b7c337daf835bb93fdff988865b0590410', + 85628, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '86b77a6cf443c94b0310523682920874155c008981b3bb827cff87b769309527', + 84452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8d666361a790f47bc95f249d2c144967589066f4c39f08d2d6a9afa7bf65570d', + 85404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '73212904c911defbb848aea031cf5c7bc5285462708823e12fdb1038f8488039', + 84440, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f3dd598262205c5e81b5834c0a103e1fd79a067d9fab79eee988633314bd4f91', + 85572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '443daf06190f4c7abd94b7917adb41656e6014e81c12eb036656d63f2b0c08a3', + 84332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '895450a4f7d173b7729b5b09d6b86710da891fa88870c08630abc1c3c186f8ea', + 85344, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '18790abbb2d00a39aa0f2ddf3af3a275ce1328915d899d44e31fc996c651dc5d', + 84280, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '18558eee9acc53f9de8633498a026360f25c82ef2a1e12b2ec7b9e736237be90', + 85276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '51945e9a938a0ff892a18d5e623e439bd2c363d1cf2e13251b78f545f1de1d09', + 84400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b3cebdbb4bdd22cce2495c53142cf925a2e430788ce890e6692637f5d4bb5af4', + 85376, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Nunito', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nunito font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nunito + static TextTheme nunitoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nunito(textStyle: textTheme.headline1), + headline2: GoogleFonts.nunito(textStyle: textTheme.headline2), + headline3: GoogleFonts.nunito(textStyle: textTheme.headline3), + headline4: GoogleFonts.nunito(textStyle: textTheme.headline4), + headline5: GoogleFonts.nunito(textStyle: textTheme.headline5), + headline6: GoogleFonts.nunito(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nunito(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nunito(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nunito(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nunito(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nunito(textStyle: textTheme.caption), + button: GoogleFonts.nunito(textStyle: textTheme.button), + overline: GoogleFonts.nunito(textStyle: textTheme.overline), + ); + } + + /// Applies the Nunito Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nunito+Sans + static TextStyle nunitoSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '70c2474c36bf599083e387d302c27f28e5439ccd1d15425222ba9855b31f6e11', + 72256, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c77baab8ad61508949ffaf4c0fc2381d7f31ddc2f12f24bd32fda15d0f02970a', + 73272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5af44ca8126245c16771271ce081fc4c5f5801d190ca549007575c51ec1c91da', + 71848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'acfe4eb8ed22882df2b122cfe78b0bd761d3025ed62826d5335856d565237582', + 72916, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3b369d5939d0bdfcbe583bb27259c6f6616b01b0948a86dade1dd3ec128c3898', + 71716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '988d1d496236aa9ab3e63745e0d5d82783762ea4d3a21d1940ffa2ff7111b664', + 72700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '62d9b0c17a7423bf90868c8da851ce9b40f15422fe0604d85f036703a60f6807', + 71704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '79fc6cab022106d0daaf1abc5b854c8a876df8e831445c71bc095e8be2a9bd1a', + 72760, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '471cb67b6491aee31f19c1ba10edb324872722bfd6b848706ba31614fe6e1655', + 71640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cf6f24fcf4a51b61957a7b72cb3e4c38fc3a9260e5323ee20a7b24bb2c522255', + 72560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7778244928e2e17a87dc2b7bf3a424a284ce6d4cdd2bd9a3f27fbbb31e7a1dcb', + 71468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c0bbb1deb95af6b335d94ee8dd132d4ba26aaee59cd749c84bf1c7609a164748', + 72264, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '76da9a3301eb15a1f2488e15b4385547bcde1c10b13035937296cef72d4deee6', + 71596, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1ef6bb692fd273ef402051d20962975c507172596da00ed72faf7907d1e00118', + 72484, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'NunitoSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Nunito Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Nunito+Sans + static TextTheme nunitoSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.nunitoSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.nunitoSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.nunitoSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.nunitoSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.nunitoSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.nunitoSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.nunitoSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.nunitoSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.nunitoSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.nunitoSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.nunitoSans(textStyle: textTheme.caption), + button: GoogleFonts.nunitoSans(textStyle: textTheme.button), + overline: GoogleFonts.nunitoSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Odibee Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Odibee+Sans + static TextStyle odibeeSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '60c83726ff6c690c3a0e1bcdbb9ff0e6b85667b08a959d6fcc925159de6c5122', + 28464, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OdibeeSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Odibee Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Odibee+Sans + static TextTheme odibeeSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.odibeeSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.odibeeSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.odibeeSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.odibeeSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.odibeeSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.odibeeSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.odibeeSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.odibeeSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.odibeeSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.odibeeSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.odibeeSans(textStyle: textTheme.caption), + button: GoogleFonts.odibeeSans(textStyle: textTheme.button), + overline: GoogleFonts.odibeeSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Odor Mean Chey font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Odor+Mean+Chey + static TextStyle odorMeanChey({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '50cfa9e8e065a77d82613a14408be3f61743af92c0b938b32e0fba703c21f027', + 294900, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OdorMeanChey', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Odor Mean Chey font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Odor+Mean+Chey + static TextTheme odorMeanCheyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.odorMeanChey(textStyle: textTheme.headline1), + headline2: GoogleFonts.odorMeanChey(textStyle: textTheme.headline2), + headline3: GoogleFonts.odorMeanChey(textStyle: textTheme.headline3), + headline4: GoogleFonts.odorMeanChey(textStyle: textTheme.headline4), + headline5: GoogleFonts.odorMeanChey(textStyle: textTheme.headline5), + headline6: GoogleFonts.odorMeanChey(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.odorMeanChey(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.odorMeanChey(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.odorMeanChey(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.odorMeanChey(textStyle: textTheme.bodyText2), + caption: GoogleFonts.odorMeanChey(textStyle: textTheme.caption), + button: GoogleFonts.odorMeanChey(textStyle: textTheme.button), + overline: GoogleFonts.odorMeanChey(textStyle: textTheme.overline), + ); + } + + /// Applies the Offside font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Offside + static TextStyle offside({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c98690ef66d169347f8cc0792c75158c05d2b92130f122f890ac9cbd756c13e7', + 30792, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Offside', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Offside font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Offside + static TextTheme offsideTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.offside(textStyle: textTheme.headline1), + headline2: GoogleFonts.offside(textStyle: textTheme.headline2), + headline3: GoogleFonts.offside(textStyle: textTheme.headline3), + headline4: GoogleFonts.offside(textStyle: textTheme.headline4), + headline5: GoogleFonts.offside(textStyle: textTheme.headline5), + headline6: GoogleFonts.offside(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.offside(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.offside(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.offside(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.offside(textStyle: textTheme.bodyText2), + caption: GoogleFonts.offside(textStyle: textTheme.caption), + button: GoogleFonts.offside(textStyle: textTheme.button), + overline: GoogleFonts.offside(textStyle: textTheme.overline), + ); + } + + /// Applies the Old Standard TT font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Old+Standard+TT + static TextStyle oldStandardTt({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0fc6378f19416dfb6ed096305aeb6abee213fa26cbab142c18d51d02e9eeb452', + 149944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9510de290956127c311e2965471c31d5c34905c6172d5b9af444bf336c9d956d', + 164788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '235d7e3e4dfc767cd24f3c17574e5fffc001f69a5af3942f47726c123762776a', + 149128, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OldStandardTT', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Old Standard TT font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Old+Standard+TT + static TextTheme oldStandardTtTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oldStandardTt(textStyle: textTheme.headline1), + headline2: GoogleFonts.oldStandardTt(textStyle: textTheme.headline2), + headline3: GoogleFonts.oldStandardTt(textStyle: textTheme.headline3), + headline4: GoogleFonts.oldStandardTt(textStyle: textTheme.headline4), + headline5: GoogleFonts.oldStandardTt(textStyle: textTheme.headline5), + headline6: GoogleFonts.oldStandardTt(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oldStandardTt(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oldStandardTt(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oldStandardTt(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oldStandardTt(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oldStandardTt(textStyle: textTheme.caption), + button: GoogleFonts.oldStandardTt(textStyle: textTheme.button), + overline: GoogleFonts.oldStandardTt(textStyle: textTheme.overline), + ); + } + + /// Applies the Oldenburg font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oldenburg + static TextStyle oldenburg({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f8c67d292b49c2c0beb3655aa66d9ec6090cc7c03dcfd25c4dbc5518bc9c2ba4', + 46200, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Oldenburg', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oldenburg font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oldenburg + static TextTheme oldenburgTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oldenburg(textStyle: textTheme.headline1), + headline2: GoogleFonts.oldenburg(textStyle: textTheme.headline2), + headline3: GoogleFonts.oldenburg(textStyle: textTheme.headline3), + headline4: GoogleFonts.oldenburg(textStyle: textTheme.headline4), + headline5: GoogleFonts.oldenburg(textStyle: textTheme.headline5), + headline6: GoogleFonts.oldenburg(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oldenburg(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oldenburg(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oldenburg(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oldenburg(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oldenburg(textStyle: textTheme.caption), + button: GoogleFonts.oldenburg(textStyle: textTheme.button), + overline: GoogleFonts.oldenburg(textStyle: textTheme.overline), + ); + } + + /// Applies the Oleo Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oleo+Script + static TextStyle oleoScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e45b8be9acc97bbb496e30675fa48edc79f4cfe2e8c66346914c8264acbe18b3', + 34932, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5742e5a26ecfd414f7f87868d0fb5fefead55b1227f381bfefe5243750279804', + 34580, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OleoScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oleo Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oleo+Script + static TextTheme oleoScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oleoScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.oleoScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.oleoScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.oleoScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.oleoScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.oleoScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oleoScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oleoScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oleoScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oleoScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oleoScript(textStyle: textTheme.caption), + button: GoogleFonts.oleoScript(textStyle: textTheme.button), + overline: GoogleFonts.oleoScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Oleo Script Swash Caps font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oleo+Script+Swash+Caps + static TextStyle oleoScriptSwashCaps({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9375d47eb832ce8884342c974dccc6d94746d0e57dd79232ee81a5ab8c9d36a5', + 40040, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fefbbb389f88ec3c2fdca446b6cd4543a073c75e48b59a1ca1c1fc03ef8756b1', + 39736, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OleoScriptSwashCaps', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oleo Script Swash Caps font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oleo+Script+Swash+Caps + static TextTheme oleoScriptSwashCapsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.headline1), + headline2: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.headline2), + headline3: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.headline3), + headline4: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.headline4), + headline5: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.headline5), + headline6: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.caption), + button: GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.button), + overline: GoogleFonts.oleoScriptSwashCaps(textStyle: textTheme.overline), + ); + } + + /// Applies the Open Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Open+Sans + static TextStyle openSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eacd6dddc04472f7143fcfe208f2e1bcd372f6baa8574529deaa2d5961e4d990', + 187204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '49c8ebe40f102f7ad2dd433e64a028047fc85d52d305404b99d691e7c6de6c84', + 190952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7b37b8abba9dcb01b9474da19527db14307fd9211e34e4d8a3d77dc9a19f2753', + 186620, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4d84c30311be3a86ed8993c8180488f191020fae18ee4ccbd0208384a37e5fcc', + 190900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bfdb79179948b408b6573789e358547c8b4b589b73a7eaf8781b17c452785032', + 187252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ee3556d7dd065b889a31834e7e604d8501cc86bf4d360e5e2d0291abb30c8a86', + 190272, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '39b0f5fd8bd8495e7ba04ea5bd88e0fa7ed612a5c54b6f83bc77a7715c517d88', + 187976, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6ec2660f3bd03b0f3f097fbc1c23f351f7582dc5c8859eaf84be1fd2a074089a', + 190768, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6b5975e42b3d385f32384d58429336513a51ab0845da7723ee788a0046c844a9', + 187396, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '22818920197a7a95e75e2f91378fcc7e5f802f6067e933050b85732b71e3755e', + 191556, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OpenSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Open Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Open+Sans + static TextTheme openSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.openSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.openSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.openSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.openSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.openSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.openSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.openSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.openSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.openSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.openSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.openSans(textStyle: textTheme.caption), + button: GoogleFonts.openSans(textStyle: textTheme.button), + overline: GoogleFonts.openSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Open Sans Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Open+Sans+Condensed + static TextStyle openSansCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '04a7cf776cec6c53387f15bd8878b365d22ea65c97dfd605c269b3774e4e7ed2', + 186164, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c5330d8a82169e940228bf53acb980b56a23fb1f640d6bf8b7e18a8681d67eda', + 189912, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9b8228ed1f9d087708d275dcc32be58269ffaf9cd7f8028db765305347303f88', + 229856, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OpenSansCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Open Sans Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Open+Sans+Condensed + static TextTheme openSansCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.openSansCondensed(textStyle: textTheme.headline1), + headline2: GoogleFonts.openSansCondensed(textStyle: textTheme.headline2), + headline3: GoogleFonts.openSansCondensed(textStyle: textTheme.headline3), + headline4: GoogleFonts.openSansCondensed(textStyle: textTheme.headline4), + headline5: GoogleFonts.openSansCondensed(textStyle: textTheme.headline5), + headline6: GoogleFonts.openSansCondensed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.openSansCondensed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.openSansCondensed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.openSansCondensed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.openSansCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.openSansCondensed(textStyle: textTheme.caption), + button: GoogleFonts.openSansCondensed(textStyle: textTheme.button), + overline: GoogleFonts.openSansCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Oranienbaum font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oranienbaum + static TextStyle oranienbaum({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ce3ec0eb54fc0cdef2aae64151cb3dc95720f5347739c1c1d19e6d2bb3629d6e', + 88736, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Oranienbaum', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oranienbaum font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oranienbaum + static TextTheme oranienbaumTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oranienbaum(textStyle: textTheme.headline1), + headline2: GoogleFonts.oranienbaum(textStyle: textTheme.headline2), + headline3: GoogleFonts.oranienbaum(textStyle: textTheme.headline3), + headline4: GoogleFonts.oranienbaum(textStyle: textTheme.headline4), + headline5: GoogleFonts.oranienbaum(textStyle: textTheme.headline5), + headline6: GoogleFonts.oranienbaum(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oranienbaum(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oranienbaum(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oranienbaum(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oranienbaum(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oranienbaum(textStyle: textTheme.caption), + button: GoogleFonts.oranienbaum(textStyle: textTheme.button), + overline: GoogleFonts.oranienbaum(textStyle: textTheme.overline), + ); + } + + /// Applies the Orbitron font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Orbitron + static TextStyle orbitron({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '92d53d02a61d246157ee4ac3e2668206b546a454087e25530c48918b92bfce32', + 39048, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1c174158cbedc3b8323f310b03842e82bc72c5fd2d5327ee80671506188cc6cc', + 39312, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'baf59aa462bae9b1e738270aa2b901810db31788e78774046146f315809bc1a6', + 38148, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3853d940cd873a88dc5e24918311876228ef02a6216677db898c41efccc598f0', + 37192, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Orbitron', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Orbitron font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Orbitron + static TextTheme orbitronTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.orbitron(textStyle: textTheme.headline1), + headline2: GoogleFonts.orbitron(textStyle: textTheme.headline2), + headline3: GoogleFonts.orbitron(textStyle: textTheme.headline3), + headline4: GoogleFonts.orbitron(textStyle: textTheme.headline4), + headline5: GoogleFonts.orbitron(textStyle: textTheme.headline5), + headline6: GoogleFonts.orbitron(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.orbitron(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.orbitron(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.orbitron(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.orbitron(textStyle: textTheme.bodyText2), + caption: GoogleFonts.orbitron(textStyle: textTheme.caption), + button: GoogleFonts.orbitron(textStyle: textTheme.button), + overline: GoogleFonts.orbitron(textStyle: textTheme.overline), + ); + } + + /// Applies the Oregano font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oregano + static TextStyle oregano({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e94ad5230aca64ae37dfe726233d5567a0743967af08b68b44f81d2b3da30d36', + 79904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'afbb45b2855b15596c6f30346e28c0c3cfb2145954f5abfaf9bf3b9f0b8e2f1d', + 86584, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Oregano', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oregano font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oregano + static TextTheme oreganoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oregano(textStyle: textTheme.headline1), + headline2: GoogleFonts.oregano(textStyle: textTheme.headline2), + headline3: GoogleFonts.oregano(textStyle: textTheme.headline3), + headline4: GoogleFonts.oregano(textStyle: textTheme.headline4), + headline5: GoogleFonts.oregano(textStyle: textTheme.headline5), + headline6: GoogleFonts.oregano(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oregano(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oregano(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oregano(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oregano(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oregano(textStyle: textTheme.caption), + button: GoogleFonts.oregano(textStyle: textTheme.button), + overline: GoogleFonts.oregano(textStyle: textTheme.overline), + ); + } + + /// Applies the Orienta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Orienta + static TextStyle orienta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6d087fac0635ed6186f7b55f474c1522ed229582419b850a3f77f333d9b0a355', + 25648, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Orienta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Orienta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Orienta + static TextTheme orientaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.orienta(textStyle: textTheme.headline1), + headline2: GoogleFonts.orienta(textStyle: textTheme.headline2), + headline3: GoogleFonts.orienta(textStyle: textTheme.headline3), + headline4: GoogleFonts.orienta(textStyle: textTheme.headline4), + headline5: GoogleFonts.orienta(textStyle: textTheme.headline5), + headline6: GoogleFonts.orienta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.orienta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.orienta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.orienta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.orienta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.orienta(textStyle: textTheme.caption), + button: GoogleFonts.orienta(textStyle: textTheme.button), + overline: GoogleFonts.orienta(textStyle: textTheme.overline), + ); + } + + /// Applies the Original Surfer font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Original+Surfer + static TextStyle originalSurfer({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '433a93a4934c3d3f80f80041f426946c8347e4e210da65e9a8adff9d70180e23', + 57376, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OriginalSurfer', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Original Surfer font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Original+Surfer + static TextTheme originalSurferTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.originalSurfer(textStyle: textTheme.headline1), + headline2: GoogleFonts.originalSurfer(textStyle: textTheme.headline2), + headline3: GoogleFonts.originalSurfer(textStyle: textTheme.headline3), + headline4: GoogleFonts.originalSurfer(textStyle: textTheme.headline4), + headline5: GoogleFonts.originalSurfer(textStyle: textTheme.headline5), + headline6: GoogleFonts.originalSurfer(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.originalSurfer(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.originalSurfer(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.originalSurfer(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.originalSurfer(textStyle: textTheme.bodyText2), + caption: GoogleFonts.originalSurfer(textStyle: textTheme.caption), + button: GoogleFonts.originalSurfer(textStyle: textTheme.button), + overline: GoogleFonts.originalSurfer(textStyle: textTheme.overline), + ); + } + + /// Applies the Oswald font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oswald + static TextStyle oswald({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '73cf9867fcced84ac0fd26238bf74e4e1f69dcbefc5ff327c2a69f6c5c107e5d', + 65000, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f10d40bae3fb58ed7a554af7cb46beca6d4f2866de12223b8e349f1b30c76968', + 64960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9dc4929f8d8935621ca4717817eb3167fc881d03d496c6dca51ff292f730c873', + 64572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f59f85cc613954e6acc66c7f89abe9b46c1add1b2236d5bee71f4a71a7769402', + 65536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c0d6ab388b1c3537b78f8976a204a6dc2c5d62b73ae37506d1c93575e52420f2', + 65388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a11b684909ba0ee2b2c493e89626c6fa9df02e25dec537e42127fa0b1a4e5e92', + 65232, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Oswald', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oswald font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oswald + static TextTheme oswaldTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oswald(textStyle: textTheme.headline1), + headline2: GoogleFonts.oswald(textStyle: textTheme.headline2), + headline3: GoogleFonts.oswald(textStyle: textTheme.headline3), + headline4: GoogleFonts.oswald(textStyle: textTheme.headline4), + headline5: GoogleFonts.oswald(textStyle: textTheme.headline5), + headline6: GoogleFonts.oswald(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oswald(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oswald(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oswald(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oswald(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oswald(textStyle: textTheme.caption), + button: GoogleFonts.oswald(textStyle: textTheme.button), + overline: GoogleFonts.oswald(textStyle: textTheme.overline), + ); + } + + /// Applies the Over the Rainbow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Over+the+Rainbow + static TextStyle overTheRainbow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3bbe72603fa8df4b1b63a308cd07fb091054678395faeddc3fc2388f614bbd29', + 45732, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OvertheRainbow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Over the Rainbow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Over+the+Rainbow + static TextTheme overTheRainbowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.overTheRainbow(textStyle: textTheme.headline1), + headline2: GoogleFonts.overTheRainbow(textStyle: textTheme.headline2), + headline3: GoogleFonts.overTheRainbow(textStyle: textTheme.headline3), + headline4: GoogleFonts.overTheRainbow(textStyle: textTheme.headline4), + headline5: GoogleFonts.overTheRainbow(textStyle: textTheme.headline5), + headline6: GoogleFonts.overTheRainbow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.overTheRainbow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.overTheRainbow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.overTheRainbow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.overTheRainbow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.overTheRainbow(textStyle: textTheme.caption), + button: GoogleFonts.overTheRainbow(textStyle: textTheme.button), + overline: GoogleFonts.overTheRainbow(textStyle: textTheme.overline), + ); + } + + /// Applies the Overlock font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Overlock + static TextStyle overlock({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f4eb336168d4c74d8a4795ef601c2c88a8c6e58cc2029bb029abde86dba8de8d', + 49100, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '862e0a21cd810bed2e0c1809a8799cab17a8a9c3a1b24486e797286d12bd47e0', + 43720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c181ce17a8b786d224bdfb18e0b0fd345243fcdf4fcdd4a301a6b68c6898e1bc', + 41936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ac1a5a813f6667fe8e4a60d3450a57e9e8dcbb9beaa2619a979bafcf0261698f', + 45416, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2f8bded0796145dd91249b13aecd8e185ea1d9222a3846c3873ad486679f5524', + 42788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dd19e6be709bf9ee365d90ee333b1766e7714578cd954bb3b5dcb1fae2e2022a', + 43736, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Overlock', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Overlock font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Overlock + static TextTheme overlockTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.overlock(textStyle: textTheme.headline1), + headline2: GoogleFonts.overlock(textStyle: textTheme.headline2), + headline3: GoogleFonts.overlock(textStyle: textTheme.headline3), + headline4: GoogleFonts.overlock(textStyle: textTheme.headline4), + headline5: GoogleFonts.overlock(textStyle: textTheme.headline5), + headline6: GoogleFonts.overlock(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.overlock(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.overlock(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.overlock(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.overlock(textStyle: textTheme.bodyText2), + caption: GoogleFonts.overlock(textStyle: textTheme.caption), + button: GoogleFonts.overlock(textStyle: textTheme.button), + overline: GoogleFonts.overlock(textStyle: textTheme.overline), + ); + } + + /// Applies the Overlock SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Overlock+SC + static TextStyle overlockSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3d11bc0fe1ba6d164281473c9b2a0321ffa27975909e1a6ce39c31f5d16b2372', + 36592, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OverlockSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Overlock SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Overlock+SC + static TextTheme overlockScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.overlockSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.overlockSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.overlockSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.overlockSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.overlockSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.overlockSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.overlockSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.overlockSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.overlockSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.overlockSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.overlockSc(textStyle: textTheme.caption), + button: GoogleFonts.overlockSc(textStyle: textTheme.button), + overline: GoogleFonts.overlockSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Overpass font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Overpass + static TextStyle overpass({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c5a2c38a969c611bc238e0242455585ccfc48cf11fc9cd85063641ab4b2d7bb9', + 82300, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8ecef7f4baf8bb9d34f1619e0a9ee510cf744ff855c5d5b856e508d1b2af0b81', + 87368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '54947a66287be19cdb01fbceed60457202e90bdf36580195800894eb70d641ff', + 83236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4ddb32270da20661fabc6aa1e944e280881d9603059b11da50ca0b655b159bfe', + 87320, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba40f1801228e6e65c3d4a8e7ba94d86c2855de57d4193bf93aaaf65d91138bb', + 82468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b2c69aa4282875efbbd517f89eb8a9a2ff7ff6523948bec58365e27a992e2474', + 87092, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a5d3ea903c065a7e458256aedede6ee1b27ab4b67c6af46c31eee97fcf66108e', + 82184, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '89e039660730531554ae5f96a9ea3faae03107ccb63ca23fff3acebd28ca7dce', + 86832, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c474f4f6c3a2d86f49aadc0cd3d5bfb14968ecdc2509b30baad6c0ce881bddb6', + 78972, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8a01f2c08d4b650cb7c597e094ff0db9cb4ae6b1bfc79ad9af8a20ba275a567d', + 85736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '43a5239e32a28e8d1efbf2a9b8922042b98e6310bb1ebf89af5a86bdfb35d997', + 80524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '06068d83442ba5f4324460ab2602523f4b89643f8afa4440fa2051e47a16e95f', + 85472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '894fdd41407a09bc7c4336dc3462d749cd7381ab80e320fa78a0475311e9ac69', + 78216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'aa9e63cded98890be1bc09083dcb64378b7f35f4af84f43e9635e50d404cdb53', + 85280, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '59f5ad4bb5b4469f7c3079f4bd6b3996a5c81d01f9f4311c74d68e9411f66c51', + 80720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a9e3b080c9a28d813d94e69fea3eb65560b09cefb4e4653b4baa47a7d95be402', + 85204, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Overpass', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Overpass font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Overpass + static TextTheme overpassTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.overpass(textStyle: textTheme.headline1), + headline2: GoogleFonts.overpass(textStyle: textTheme.headline2), + headline3: GoogleFonts.overpass(textStyle: textTheme.headline3), + headline4: GoogleFonts.overpass(textStyle: textTheme.headline4), + headline5: GoogleFonts.overpass(textStyle: textTheme.headline5), + headline6: GoogleFonts.overpass(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.overpass(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.overpass(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.overpass(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.overpass(textStyle: textTheme.bodyText2), + caption: GoogleFonts.overpass(textStyle: textTheme.caption), + button: GoogleFonts.overpass(textStyle: textTheme.button), + overline: GoogleFonts.overpass(textStyle: textTheme.overline), + ); + } + + /// Applies the Overpass Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Overpass+Mono + static TextStyle overpassMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a46cc06eb5b5001bdf1404b0e24fb82ee14159aca202af7094984ff4d48896dd', + 118416, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd3a8c0a4613ebae3d21471198e12e57aa70e9f051f7592e3942953e2c36bd190', + 118208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f6b8f8180ef4c0f650402aa53effdd61f2d9771c4973d07f722d14ebd60e59da', + 117696, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd8f645bd2f708d8127ab1d3078ae22195543fbe52abee9362a8ed5a980cb1648', + 117800, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OverpassMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Overpass Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Overpass+Mono + static TextTheme overpassMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.overpassMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.overpassMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.overpassMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.overpassMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.overpassMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.overpassMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.overpassMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.overpassMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.overpassMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.overpassMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.overpassMono(textStyle: textTheme.caption), + button: GoogleFonts.overpassMono(textStyle: textTheme.button), + overline: GoogleFonts.overpassMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Ovo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ovo + static TextStyle ovo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '50e634088f389dcf2f463aa182c8ccb9d19042decdd216fed34fa70b5dfb49fd', + 50840, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ovo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ovo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ovo + static TextTheme ovoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ovo(textStyle: textTheme.headline1), + headline2: GoogleFonts.ovo(textStyle: textTheme.headline2), + headline3: GoogleFonts.ovo(textStyle: textTheme.headline3), + headline4: GoogleFonts.ovo(textStyle: textTheme.headline4), + headline5: GoogleFonts.ovo(textStyle: textTheme.headline5), + headline6: GoogleFonts.ovo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ovo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ovo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ovo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ovo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ovo(textStyle: textTheme.caption), + button: GoogleFonts.ovo(textStyle: textTheme.button), + overline: GoogleFonts.ovo(textStyle: textTheme.overline), + ); + } + + /// Applies the Oxanium font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oxanium + static TextStyle oxanium({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '89daee61e7358c34dbacac977e9f2c92221971ab81d9345af9d294687a538ace', + 24156, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fef895a1cf0e2e0ea02299a10df50702cff292d28fd9fba618f118b9d7f1cc70', + 24092, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '09fedc2fbf2c81af9711328c3b1fe1bf632512d8714d254cafe53fd7c9e23ebe', + 24072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f15be0f59920c03bbe89ad1bb66c9df4b660acb2c329f30e1d75e846e10e30d2', + 24076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c3a19352e2ab05f91352b26d6eeef4d8b57575350956c0a8d99d7824bfea43c6', + 24076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '02e5724444f1a7053fc3043649b8c5b76a2f698757d9c678cc2e80dbaa8a221a', + 24044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d805023212166271a84af73c8e13073ce5a29746483c5fa3ae9941eaa7577c8', + 24036, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Oxanium', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oxanium font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oxanium + static TextTheme oxaniumTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oxanium(textStyle: textTheme.headline1), + headline2: GoogleFonts.oxanium(textStyle: textTheme.headline2), + headline3: GoogleFonts.oxanium(textStyle: textTheme.headline3), + headline4: GoogleFonts.oxanium(textStyle: textTheme.headline4), + headline5: GoogleFonts.oxanium(textStyle: textTheme.headline5), + headline6: GoogleFonts.oxanium(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oxanium(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oxanium(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oxanium(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oxanium(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oxanium(textStyle: textTheme.caption), + button: GoogleFonts.oxanium(textStyle: textTheme.button), + overline: GoogleFonts.oxanium(textStyle: textTheme.overline), + ); + } + + /// Applies the Oxygen font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oxygen + static TextStyle oxygen({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7e1244b4a11ee9f21f86e2f25d7dd963f8e8f93d7b8e411620c959f4cf66fa2', + 27560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f6497c6c0bb7a884669e84095f3e56550bd7c0ccba79656b0af00d8b3200d790', + 29168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4bccf594c248e25c3da7e37b9dc5e9cddfcf3bc405504b7d15f4523358d81f76', + 30052, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Oxygen', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oxygen font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oxygen + static TextTheme oxygenTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oxygen(textStyle: textTheme.headline1), + headline2: GoogleFonts.oxygen(textStyle: textTheme.headline2), + headline3: GoogleFonts.oxygen(textStyle: textTheme.headline3), + headline4: GoogleFonts.oxygen(textStyle: textTheme.headline4), + headline5: GoogleFonts.oxygen(textStyle: textTheme.headline5), + headline6: GoogleFonts.oxygen(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oxygen(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oxygen(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oxygen(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oxygen(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oxygen(textStyle: textTheme.caption), + button: GoogleFonts.oxygen(textStyle: textTheme.button), + overline: GoogleFonts.oxygen(textStyle: textTheme.overline), + ); + } + + /// Applies the Oxygen Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oxygen+Mono + static TextStyle oxygenMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a8f20c04bb875a24603d2f13aa59fa112316075b0d8531e06a1212759450a20', + 28468, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'OxygenMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Oxygen Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Oxygen+Mono + static TextTheme oxygenMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.oxygenMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.oxygenMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.oxygenMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.oxygenMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.oxygenMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.oxygenMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.oxygenMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.oxygenMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.oxygenMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.oxygenMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.oxygenMono(textStyle: textTheme.caption), + button: GoogleFonts.oxygenMono(textStyle: textTheme.button), + overline: GoogleFonts.oxygenMono(textStyle: textTheme.overline), + ); + } + + /// Applies the PT Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Mono + static TextStyle ptMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '76d11b0f53258fdd742b27fc7e194046840c2fc0cafe1246aa0c27718a5f031a', + 84568, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PTMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the PT Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Mono + static TextTheme ptMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ptMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.ptMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.ptMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.ptMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.ptMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.ptMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ptMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ptMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ptMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ptMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ptMono(textStyle: textTheme.caption), + button: GoogleFonts.ptMono(textStyle: textTheme.button), + overline: GoogleFonts.ptMono(textStyle: textTheme.overline), + ); + } + + /// Applies the PT Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Sans + static TextStyle ptSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8a587dc4260abac4008021f8b9302115ee0f9616aee70d95d4d49f447f4df0f9', + 272864, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6de2d3f34e12548006ef800234119a1b1d90bba33fb1d33f5bf41577bc954338', + 276952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2a88a8de5aeccdc3e4febba14c9ade00ec49e16f2718050be6bc3f4f37e8ff0b', + 291536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a37694659d53ae08c11bf532f8871e90b911f61967c3e23f456e59e7c55b33e6', + 270132, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PTSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the PT Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Sans + static TextTheme ptSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ptSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.ptSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.ptSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.ptSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.ptSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.ptSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ptSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ptSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ptSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ptSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ptSans(textStyle: textTheme.caption), + button: GoogleFonts.ptSans(textStyle: textTheme.button), + overline: GoogleFonts.ptSans(textStyle: textTheme.overline), + ); + } + + /// Applies the PT Sans Caption font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Sans+Caption + static TextStyle ptSansCaption({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1245ca967adbb79f480b169e92cf44a71ae4cb8571b9847ceb3de43e7235361c', + 260480, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f47afcc4feb502bfa6ca192ad230e0d743be26deb97832412722544b223ed461', + 291560, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PTSansCaption', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the PT Sans Caption font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Sans+Caption + static TextTheme ptSansCaptionTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ptSansCaption(textStyle: textTheme.headline1), + headline2: GoogleFonts.ptSansCaption(textStyle: textTheme.headline2), + headline3: GoogleFonts.ptSansCaption(textStyle: textTheme.headline3), + headline4: GoogleFonts.ptSansCaption(textStyle: textTheme.headline4), + headline5: GoogleFonts.ptSansCaption(textStyle: textTheme.headline5), + headline6: GoogleFonts.ptSansCaption(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ptSansCaption(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ptSansCaption(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ptSansCaption(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ptSansCaption(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ptSansCaption(textStyle: textTheme.caption), + button: GoogleFonts.ptSansCaption(textStyle: textTheme.button), + overline: GoogleFonts.ptSansCaption(textStyle: textTheme.overline), + ); + } + + /// Applies the PT Sans Narrow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Sans+Narrow + static TextStyle ptSansNarrow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d184233e6f48f81c6e510a1067d4f632052f899bf2f2bef4a69ab709bfe45a5', + 268240, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a16a62299cf1143c59a4ec676c956c6831a90698fd830de4c85632a83c56d52c', + 278220, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PTSansNarrow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the PT Sans Narrow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Sans+Narrow + static TextTheme ptSansNarrowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ptSansNarrow(textStyle: textTheme.headline1), + headline2: GoogleFonts.ptSansNarrow(textStyle: textTheme.headline2), + headline3: GoogleFonts.ptSansNarrow(textStyle: textTheme.headline3), + headline4: GoogleFonts.ptSansNarrow(textStyle: textTheme.headline4), + headline5: GoogleFonts.ptSansNarrow(textStyle: textTheme.headline5), + headline6: GoogleFonts.ptSansNarrow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ptSansNarrow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ptSansNarrow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ptSansNarrow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ptSansNarrow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ptSansNarrow(textStyle: textTheme.caption), + button: GoogleFonts.ptSansNarrow(textStyle: textTheme.button), + overline: GoogleFonts.ptSansNarrow(textStyle: textTheme.overline), + ); + } + + /// Applies the PT Serif font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Serif + static TextStyle ptSerif({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '77cd8f3a9ae2f3546135a48656a468afd4312d1ebf5720bb967ebe3a43291fa8', + 260788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c623ffd63812daa5b0776e75e7a99de63340eb1fa6d3d5692c27a5fe30e21c22', + 263700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8945a761fd4a69fd6eb9b058e025925dd964c9b2cf5cc02b14290746f6aaf356', + 261928, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ab351a82c9e93d363fcb9525df6f6d111fc14e15c3cf0d5e125e77ef0ddf5fd0', + 265096, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PTSerif', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the PT Serif font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Serif + static TextTheme ptSerifTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ptSerif(textStyle: textTheme.headline1), + headline2: GoogleFonts.ptSerif(textStyle: textTheme.headline2), + headline3: GoogleFonts.ptSerif(textStyle: textTheme.headline3), + headline4: GoogleFonts.ptSerif(textStyle: textTheme.headline4), + headline5: GoogleFonts.ptSerif(textStyle: textTheme.headline5), + headline6: GoogleFonts.ptSerif(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ptSerif(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ptSerif(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ptSerif(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ptSerif(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ptSerif(textStyle: textTheme.caption), + button: GoogleFonts.ptSerif(textStyle: textTheme.button), + overline: GoogleFonts.ptSerif(textStyle: textTheme.overline), + ); + } + + /// Applies the PT Serif Caption font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Serif+Caption + static TextStyle ptSerifCaption({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fa2de071d21315555c75861f438b09fdfc9205ed9845c49d401903c6db245582', + 255368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0d238ee69704d0810493bff87f27c3236c6c9b81abda84fba39091e70f47eb26', + 259580, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PTSerifCaption', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the PT Serif Caption font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/PT+Serif+Caption + static TextTheme ptSerifCaptionTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ptSerifCaption(textStyle: textTheme.headline1), + headline2: GoogleFonts.ptSerifCaption(textStyle: textTheme.headline2), + headline3: GoogleFonts.ptSerifCaption(textStyle: textTheme.headline3), + headline4: GoogleFonts.ptSerifCaption(textStyle: textTheme.headline4), + headline5: GoogleFonts.ptSerifCaption(textStyle: textTheme.headline5), + headline6: GoogleFonts.ptSerifCaption(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ptSerifCaption(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ptSerifCaption(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ptSerifCaption(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ptSerifCaption(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ptSerifCaption(textStyle: textTheme.caption), + button: GoogleFonts.ptSerifCaption(textStyle: textTheme.button), + overline: GoogleFonts.ptSerifCaption(textStyle: textTheme.overline), + ); + } + + /// Applies the Pacifico font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pacifico + static TextStyle pacifico({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '03452c0b90c71f4088222325620904576503c4d5a3a6c563ee22d1e896788d3e', + 143508, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Pacifico', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pacifico font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pacifico + static TextTheme pacificoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pacifico(textStyle: textTheme.headline1), + headline2: GoogleFonts.pacifico(textStyle: textTheme.headline2), + headline3: GoogleFonts.pacifico(textStyle: textTheme.headline3), + headline4: GoogleFonts.pacifico(textStyle: textTheme.headline4), + headline5: GoogleFonts.pacifico(textStyle: textTheme.headline5), + headline6: GoogleFonts.pacifico(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pacifico(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pacifico(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pacifico(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pacifico(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pacifico(textStyle: textTheme.caption), + button: GoogleFonts.pacifico(textStyle: textTheme.button), + overline: GoogleFonts.pacifico(textStyle: textTheme.overline), + ); + } + + /// Applies the Padauk font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Padauk + static TextStyle padauk({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5326568d3a2c4690b03acaafdf444cd2e52712e7a16d96a3639b40f17fcfe8b0', + 408956, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a3054832e288beedeba883a9477e908a910c186e002a455277fb4c54e37518f6', + 416804, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Padauk', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Padauk font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Padauk + static TextTheme padaukTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.padauk(textStyle: textTheme.headline1), + headline2: GoogleFonts.padauk(textStyle: textTheme.headline2), + headline3: GoogleFonts.padauk(textStyle: textTheme.headline3), + headline4: GoogleFonts.padauk(textStyle: textTheme.headline4), + headline5: GoogleFonts.padauk(textStyle: textTheme.headline5), + headline6: GoogleFonts.padauk(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.padauk(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.padauk(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.padauk(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.padauk(textStyle: textTheme.bodyText2), + caption: GoogleFonts.padauk(textStyle: textTheme.caption), + button: GoogleFonts.padauk(textStyle: textTheme.button), + overline: GoogleFonts.padauk(textStyle: textTheme.overline), + ); + } + + /// Applies the Palanquin font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Palanquin + static TextStyle palanquin({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c2f2587b9d7e9715b99bbe03f6115a2dcf52f8cb016c7e31f06e26561f3f13bb', + 273560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e3ae6db39173fbbc643b90005a108980c36ea6111e91516ed3e754cd247f965d', + 275156, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '94dbed29146fdc39c8979eff474e5210368a5276c9c7b55706418b745036a240', + 276496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a3fd79ddbba4270727bcb4649e1015a2726418eef7abd8cb984139bca11f5df5', + 284496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c027a6ee638527b57eed686cb93382141e9da3ad55c331614b735f4b26dfe2f9', + 283708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e342fbd31bc4d7a837724b2e51ac0c6e4057d44809e8e984d2c72c0b0a3dc48a', + 283824, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a1812757fe429bab601701c1010e05f49540ea857170789a8ee91e0fe1d5e9d2', + 272160, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Palanquin', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Palanquin font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Palanquin + static TextTheme palanquinTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.palanquin(textStyle: textTheme.headline1), + headline2: GoogleFonts.palanquin(textStyle: textTheme.headline2), + headline3: GoogleFonts.palanquin(textStyle: textTheme.headline3), + headline4: GoogleFonts.palanquin(textStyle: textTheme.headline4), + headline5: GoogleFonts.palanquin(textStyle: textTheme.headline5), + headline6: GoogleFonts.palanquin(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.palanquin(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.palanquin(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.palanquin(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.palanquin(textStyle: textTheme.bodyText2), + caption: GoogleFonts.palanquin(textStyle: textTheme.caption), + button: GoogleFonts.palanquin(textStyle: textTheme.button), + overline: GoogleFonts.palanquin(textStyle: textTheme.overline), + ); + } + + /// Applies the Palanquin Dark font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Palanquin+Dark + static TextStyle palanquinDark({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2a564d738b34f664cbdc4ec631b53907f90205b8dd0e177be158ebc30b67182a', + 265580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2741c907db3e5853a79489713ec11a8669cff876897076b98d70d302086296c9', + 273044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ee40721d326a2509669e0c3f41d846f48e353b774b15fb78426c4e812aadf4e9', + 274468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3f46195270b56b1dd32d5f48a0bb546a30e424b9d30ff4daabe395c2257a157e', + 265000, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PalanquinDark', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Palanquin Dark font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Palanquin+Dark + static TextTheme palanquinDarkTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.palanquinDark(textStyle: textTheme.headline1), + headline2: GoogleFonts.palanquinDark(textStyle: textTheme.headline2), + headline3: GoogleFonts.palanquinDark(textStyle: textTheme.headline3), + headline4: GoogleFonts.palanquinDark(textStyle: textTheme.headline4), + headline5: GoogleFonts.palanquinDark(textStyle: textTheme.headline5), + headline6: GoogleFonts.palanquinDark(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.palanquinDark(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.palanquinDark(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.palanquinDark(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.palanquinDark(textStyle: textTheme.bodyText2), + caption: GoogleFonts.palanquinDark(textStyle: textTheme.caption), + button: GoogleFonts.palanquinDark(textStyle: textTheme.button), + overline: GoogleFonts.palanquinDark(textStyle: textTheme.overline), + ); + } + + /// Applies the Pangolin font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pangolin + static TextStyle pangolin({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9da3dcb4b5f7ae5a76923e77c68da25e9539a3dcdcad7fd654387974f9ff89f4', + 238600, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Pangolin', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pangolin font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pangolin + static TextTheme pangolinTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pangolin(textStyle: textTheme.headline1), + headline2: GoogleFonts.pangolin(textStyle: textTheme.headline2), + headline3: GoogleFonts.pangolin(textStyle: textTheme.headline3), + headline4: GoogleFonts.pangolin(textStyle: textTheme.headline4), + headline5: GoogleFonts.pangolin(textStyle: textTheme.headline5), + headline6: GoogleFonts.pangolin(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pangolin(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pangolin(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pangolin(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pangolin(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pangolin(textStyle: textTheme.caption), + button: GoogleFonts.pangolin(textStyle: textTheme.button), + overline: GoogleFonts.pangolin(textStyle: textTheme.overline), + ); + } + + /// Applies the Paprika font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Paprika + static TextStyle paprika({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3611025b91e6a3a1daf2e78541775555d832ba6b4f010ae8b4553d5d5be2bac6', + 42292, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Paprika', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Paprika font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Paprika + static TextTheme paprikaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.paprika(textStyle: textTheme.headline1), + headline2: GoogleFonts.paprika(textStyle: textTheme.headline2), + headline3: GoogleFonts.paprika(textStyle: textTheme.headline3), + headline4: GoogleFonts.paprika(textStyle: textTheme.headline4), + headline5: GoogleFonts.paprika(textStyle: textTheme.headline5), + headline6: GoogleFonts.paprika(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.paprika(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.paprika(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.paprika(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.paprika(textStyle: textTheme.bodyText2), + caption: GoogleFonts.paprika(textStyle: textTheme.caption), + button: GoogleFonts.paprika(textStyle: textTheme.button), + overline: GoogleFonts.paprika(textStyle: textTheme.overline), + ); + } + + /// Applies the Parisienne font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Parisienne + static TextStyle parisienne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b6fdb3a0ca128ad6afbc6c8892193cc2a122e6934dc75c4644f8819ca09b7042', + 60832, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Parisienne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Parisienne font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Parisienne + static TextTheme parisienneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.parisienne(textStyle: textTheme.headline1), + headline2: GoogleFonts.parisienne(textStyle: textTheme.headline2), + headline3: GoogleFonts.parisienne(textStyle: textTheme.headline3), + headline4: GoogleFonts.parisienne(textStyle: textTheme.headline4), + headline5: GoogleFonts.parisienne(textStyle: textTheme.headline5), + headline6: GoogleFonts.parisienne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.parisienne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.parisienne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.parisienne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.parisienne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.parisienne(textStyle: textTheme.caption), + button: GoogleFonts.parisienne(textStyle: textTheme.button), + overline: GoogleFonts.parisienne(textStyle: textTheme.overline), + ); + } + + /// Applies the Passero One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Passero+One + static TextStyle passeroOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b2d19067da678681f5952e5350d1924a2ac5a8a03eda9d27347e43a3ce35f8ad', + 33600, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PasseroOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Passero One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Passero+One + static TextTheme passeroOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.passeroOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.passeroOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.passeroOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.passeroOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.passeroOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.passeroOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.passeroOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.passeroOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.passeroOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.passeroOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.passeroOne(textStyle: textTheme.caption), + button: GoogleFonts.passeroOne(textStyle: textTheme.button), + overline: GoogleFonts.passeroOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Passion One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Passion+One + static TextStyle passionOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1f9e3f81509fa1087e3a4636d898f6ce048f4953bf6c06a6d79d9cb78115c03d', + 24640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '567181e9763fb8cb33a51945378a8a2756c423cb05608d37fdc2e0d8ff170fa1', + 24420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '351dd38c35e67c20b4ae84db1964391fd924cd245611616eacaf6b9e63113442', + 23980, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PassionOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Passion One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Passion+One + static TextTheme passionOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.passionOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.passionOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.passionOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.passionOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.passionOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.passionOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.passionOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.passionOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.passionOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.passionOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.passionOne(textStyle: textTheme.caption), + button: GoogleFonts.passionOne(textStyle: textTheme.button), + overline: GoogleFonts.passionOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Pathway Gothic One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pathway+Gothic+One + static TextStyle pathwayGothicOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '39c8099ef615de3477faab7247ffd06193e4c4244406f6a3d888c1e1763a01cd', + 25172, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PathwayGothicOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pathway Gothic One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pathway+Gothic+One + static TextTheme pathwayGothicOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pathwayGothicOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.pathwayGothicOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.pathwayGothicOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.pathwayGothicOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.pathwayGothicOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.pathwayGothicOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pathwayGothicOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pathwayGothicOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pathwayGothicOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pathwayGothicOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pathwayGothicOne(textStyle: textTheme.caption), + button: GoogleFonts.pathwayGothicOne(textStyle: textTheme.button), + overline: GoogleFonts.pathwayGothicOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Patrick Hand font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Patrick+Hand + static TextStyle patrickHand({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b63c9a7041a5fc7005d8f0580dd04bf71c5eed9b4b6d843857ccb8f2485ebbf6', + 122740, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PatrickHand', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Patrick Hand font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Patrick+Hand + static TextTheme patrickHandTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.patrickHand(textStyle: textTheme.headline1), + headline2: GoogleFonts.patrickHand(textStyle: textTheme.headline2), + headline3: GoogleFonts.patrickHand(textStyle: textTheme.headline3), + headline4: GoogleFonts.patrickHand(textStyle: textTheme.headline4), + headline5: GoogleFonts.patrickHand(textStyle: textTheme.headline5), + headline6: GoogleFonts.patrickHand(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.patrickHand(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.patrickHand(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.patrickHand(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.patrickHand(textStyle: textTheme.bodyText2), + caption: GoogleFonts.patrickHand(textStyle: textTheme.caption), + button: GoogleFonts.patrickHand(textStyle: textTheme.button), + overline: GoogleFonts.patrickHand(textStyle: textTheme.overline), + ); + } + + /// Applies the Patrick Hand SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Patrick+Hand+SC + static TextStyle patrickHandSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '73b9443b6806844f52e636b33036ac9bba72136e16d3e10e7fc43d906509238c', + 89760, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PatrickHandSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Patrick Hand SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Patrick+Hand+SC + static TextTheme patrickHandScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.patrickHandSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.patrickHandSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.patrickHandSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.patrickHandSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.patrickHandSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.patrickHandSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.patrickHandSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.patrickHandSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.patrickHandSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.patrickHandSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.patrickHandSc(textStyle: textTheme.caption), + button: GoogleFonts.patrickHandSc(textStyle: textTheme.button), + overline: GoogleFonts.patrickHandSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Pattaya font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pattaya + static TextStyle pattaya({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '041d4a84883eccfdd46adb393da062a32f3b3c0deafbd5431c6fb5e6c2669c7c', + 282908, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Pattaya', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pattaya font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pattaya + static TextTheme pattayaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pattaya(textStyle: textTheme.headline1), + headline2: GoogleFonts.pattaya(textStyle: textTheme.headline2), + headline3: GoogleFonts.pattaya(textStyle: textTheme.headline3), + headline4: GoogleFonts.pattaya(textStyle: textTheme.headline4), + headline5: GoogleFonts.pattaya(textStyle: textTheme.headline5), + headline6: GoogleFonts.pattaya(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pattaya(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pattaya(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pattaya(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pattaya(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pattaya(textStyle: textTheme.caption), + button: GoogleFonts.pattaya(textStyle: textTheme.button), + overline: GoogleFonts.pattaya(textStyle: textTheme.overline), + ); + } + + /// Applies the Patua One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Patua+One + static TextStyle patuaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b23d7030cb223723e1ea6fe64ca5799ae86a5c9c7d7343dfce539e574a5004d0', + 35576, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PatuaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Patua One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Patua+One + static TextTheme patuaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.patuaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.patuaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.patuaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.patuaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.patuaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.patuaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.patuaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.patuaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.patuaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.patuaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.patuaOne(textStyle: textTheme.caption), + button: GoogleFonts.patuaOne(textStyle: textTheme.button), + overline: GoogleFonts.patuaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Pavanam font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pavanam + static TextStyle pavanam({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '177d645082f388adf4ae3cf8413e270d77cbb5f7b24b7d521cce366a857de30a', + 48596, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Pavanam', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pavanam font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pavanam + static TextTheme pavanamTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pavanam(textStyle: textTheme.headline1), + headline2: GoogleFonts.pavanam(textStyle: textTheme.headline2), + headline3: GoogleFonts.pavanam(textStyle: textTheme.headline3), + headline4: GoogleFonts.pavanam(textStyle: textTheme.headline4), + headline5: GoogleFonts.pavanam(textStyle: textTheme.headline5), + headline6: GoogleFonts.pavanam(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pavanam(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pavanam(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pavanam(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pavanam(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pavanam(textStyle: textTheme.caption), + button: GoogleFonts.pavanam(textStyle: textTheme.button), + overline: GoogleFonts.pavanam(textStyle: textTheme.overline), + ); + } + + /// Applies the Paytone One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Paytone+One + static TextStyle paytoneOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b6fb867bea8e0668b3117749a0c761f24623a872f905f98462fb83791b88b00', + 187580, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PaytoneOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Paytone One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Paytone+One + static TextTheme paytoneOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.paytoneOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.paytoneOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.paytoneOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.paytoneOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.paytoneOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.paytoneOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.paytoneOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.paytoneOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.paytoneOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.paytoneOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.paytoneOne(textStyle: textTheme.caption), + button: GoogleFonts.paytoneOne(textStyle: textTheme.button), + overline: GoogleFonts.paytoneOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Peddana font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Peddana + static TextStyle peddana({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4c066d855b7652305b1b9d3d0308b0c71161bd1e83a7b4a8bdebadd005f749b6', + 492376, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Peddana', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Peddana font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Peddana + static TextTheme peddanaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.peddana(textStyle: textTheme.headline1), + headline2: GoogleFonts.peddana(textStyle: textTheme.headline2), + headline3: GoogleFonts.peddana(textStyle: textTheme.headline3), + headline4: GoogleFonts.peddana(textStyle: textTheme.headline4), + headline5: GoogleFonts.peddana(textStyle: textTheme.headline5), + headline6: GoogleFonts.peddana(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.peddana(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.peddana(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.peddana(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.peddana(textStyle: textTheme.bodyText2), + caption: GoogleFonts.peddana(textStyle: textTheme.caption), + button: GoogleFonts.peddana(textStyle: textTheme.button), + overline: GoogleFonts.peddana(textStyle: textTheme.overline), + ); + } + + /// Applies the Peralta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Peralta + static TextStyle peralta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '28a0d3b695c9ecde1fe0ab5e4dceac96b21749fe6a3df062847e363b47af3360', + 59184, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Peralta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Peralta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Peralta + static TextTheme peraltaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.peralta(textStyle: textTheme.headline1), + headline2: GoogleFonts.peralta(textStyle: textTheme.headline2), + headline3: GoogleFonts.peralta(textStyle: textTheme.headline3), + headline4: GoogleFonts.peralta(textStyle: textTheme.headline4), + headline5: GoogleFonts.peralta(textStyle: textTheme.headline5), + headline6: GoogleFonts.peralta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.peralta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.peralta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.peralta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.peralta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.peralta(textStyle: textTheme.caption), + button: GoogleFonts.peralta(textStyle: textTheme.button), + overline: GoogleFonts.peralta(textStyle: textTheme.overline), + ); + } + + /// Applies the Permanent Marker font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Permanent+Marker + static TextStyle permanentMarker({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b256508a46019a9b82045efd1b32fea49660231fc60b1b4bd43585c2808cf128', + 74216, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PermanentMarker', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Permanent Marker font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Permanent+Marker + static TextTheme permanentMarkerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.permanentMarker(textStyle: textTheme.headline1), + headline2: GoogleFonts.permanentMarker(textStyle: textTheme.headline2), + headline3: GoogleFonts.permanentMarker(textStyle: textTheme.headline3), + headline4: GoogleFonts.permanentMarker(textStyle: textTheme.headline4), + headline5: GoogleFonts.permanentMarker(textStyle: textTheme.headline5), + headline6: GoogleFonts.permanentMarker(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.permanentMarker(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.permanentMarker(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.permanentMarker(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.permanentMarker(textStyle: textTheme.bodyText2), + caption: GoogleFonts.permanentMarker(textStyle: textTheme.caption), + button: GoogleFonts.permanentMarker(textStyle: textTheme.button), + overline: GoogleFonts.permanentMarker(textStyle: textTheme.overline), + ); + } + + /// Applies the Petit Formal Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Petit+Formal+Script + static TextStyle petitFormalScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '60b5efe480f0bafdd5de13f5786bc9017ffcddab4de13ece1ee542791fe4eba2', + 120832, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PetitFormalScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Petit Formal Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Petit+Formal+Script + static TextTheme petitFormalScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.petitFormalScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.petitFormalScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.petitFormalScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.petitFormalScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.petitFormalScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.petitFormalScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.petitFormalScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.petitFormalScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.petitFormalScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.petitFormalScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.petitFormalScript(textStyle: textTheme.caption), + button: GoogleFonts.petitFormalScript(textStyle: textTheme.button), + overline: GoogleFonts.petitFormalScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Petrona font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Petrona + static TextStyle petrona({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd80f7ebf1277bc91932826582e099143b69fb77dc61f1259d442558087cc2714', + 80736, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Petrona', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Petrona font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Petrona + static TextTheme petronaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.petrona(textStyle: textTheme.headline1), + headline2: GoogleFonts.petrona(textStyle: textTheme.headline2), + headline3: GoogleFonts.petrona(textStyle: textTheme.headline3), + headline4: GoogleFonts.petrona(textStyle: textTheme.headline4), + headline5: GoogleFonts.petrona(textStyle: textTheme.headline5), + headline6: GoogleFonts.petrona(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.petrona(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.petrona(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.petrona(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.petrona(textStyle: textTheme.bodyText2), + caption: GoogleFonts.petrona(textStyle: textTheme.caption), + button: GoogleFonts.petrona(textStyle: textTheme.button), + overline: GoogleFonts.petrona(textStyle: textTheme.overline), + ); + } + + /// Applies the Philosopher font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Philosopher + static TextStyle philosopher({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '51b0e57bc81490c490b7400858499b5823a13926de953476e8d40730ab9fc02f', + 74064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '32aafaf60ca199b7f91291e6aa9e68b91df4b48f53246f454e7eddf8e25ff50c', + 73948, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '174ba5b59df6e5bdec8e23657ecdf679226b3b6f23f5625fa814540e88b30628', + 73580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'aed7000bdaef8a04be340ee51e9ff7157c538442a3fda8daeee40a849eaf33cb', + 74272, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Philosopher', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Philosopher font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Philosopher + static TextTheme philosopherTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.philosopher(textStyle: textTheme.headline1), + headline2: GoogleFonts.philosopher(textStyle: textTheme.headline2), + headline3: GoogleFonts.philosopher(textStyle: textTheme.headline3), + headline4: GoogleFonts.philosopher(textStyle: textTheme.headline4), + headline5: GoogleFonts.philosopher(textStyle: textTheme.headline5), + headline6: GoogleFonts.philosopher(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.philosopher(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.philosopher(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.philosopher(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.philosopher(textStyle: textTheme.bodyText2), + caption: GoogleFonts.philosopher(textStyle: textTheme.caption), + button: GoogleFonts.philosopher(textStyle: textTheme.button), + overline: GoogleFonts.philosopher(textStyle: textTheme.overline), + ); + } + + /// Applies the Piazzolla font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Piazzolla + static TextStyle piazzolla({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '853bced8b15b4dac1826650854c71cd8768f3f17492865bbd87527322ac07997', + 122204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '12e6ee6c72b71f1cec3046f5202f32326bdeedc1d99eba4e2a959302c7b95d8c', + 122292, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1db122cbdeb9ecae7425cb66d950048a8ebb3514958c02750b42b342d32aa3ff', + 122300, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ac4e7964cbc511d29ef648da51186bef1cb533bb0c51a05f914177cc78db20d6', + 122336, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c12af6331700aca9a9ae4213fc8d9dafff7bad454d208fc8d69872eee8c08386', + 122420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d96e29c9bb1c8c5c98c18420a84efc14960d1028c7f0ba0cf8ef3a685315596', + 122508, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f81540363cf6ba6fd3a6b271f2c91e8dd246fd22bc513e69e2eb18b91222ab00', + 122544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9997d5c8c01dcaa3d884beb7575564aedc5c048a4df9e8dcc16aa425be26c5ec', + 122688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '876ac0f870cd43d375383de91157d5afa87d6ab46c69db29fe06eebc70f277dd', + 122736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0ce1c16e7786a82b37c31b73324f97dd5673c1b508a3c0fa10c951a984bd0882', + 124876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dd21ee34892172c0e0ca6a13bcbc80c0745d9936ee536b5c95c41fd0b1737fc1', + 125024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0afba99a98a8ba9511665bad6711b19933daf6cfc71752362247d287af610b89', + 125024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2a326a8fa339a54db374a2868e50ea10f8d94bc9f98f4cfb8ea82db180b32f87', + 124940, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8aab5a4c7dfa4e0b43104ad463e1c0fa78d54c8b7116c8c3bc36acb75d3cb30a', + 125116, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'bd992effa8448c4cd917c9a45d384396019b442df8266af0d5cde06e88e1b400', + 125184, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7febcdb00d6f588c3152ee01de7ea04f9baf7ec0e261ff0dea723b809e9bead5', + 125216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c33ba0247044ea9d88b9a81c0c0ec8d6b31b43534856567a32f010d9fad3868e', + 125300, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '07ae846598d075d2908961487ede708db0f1d372009edffa72e49cb73ebaf559', + 125256, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Piazzolla', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Piazzolla font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Piazzolla + static TextTheme piazzollaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.piazzolla(textStyle: textTheme.headline1), + headline2: GoogleFonts.piazzolla(textStyle: textTheme.headline2), + headline3: GoogleFonts.piazzolla(textStyle: textTheme.headline3), + headline4: GoogleFonts.piazzolla(textStyle: textTheme.headline4), + headline5: GoogleFonts.piazzolla(textStyle: textTheme.headline5), + headline6: GoogleFonts.piazzolla(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.piazzolla(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.piazzolla(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.piazzolla(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.piazzolla(textStyle: textTheme.bodyText2), + caption: GoogleFonts.piazzolla(textStyle: textTheme.caption), + button: GoogleFonts.piazzolla(textStyle: textTheme.button), + overline: GoogleFonts.piazzolla(textStyle: textTheme.overline), + ); + } + + /// Applies the Piedra font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Piedra + static TextStyle piedra({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '44d0853d7548f46be84298314d45874783d3dfd1459f5286f1426fb025483348', + 75936, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Piedra', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Piedra font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Piedra + static TextTheme piedraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.piedra(textStyle: textTheme.headline1), + headline2: GoogleFonts.piedra(textStyle: textTheme.headline2), + headline3: GoogleFonts.piedra(textStyle: textTheme.headline3), + headline4: GoogleFonts.piedra(textStyle: textTheme.headline4), + headline5: GoogleFonts.piedra(textStyle: textTheme.headline5), + headline6: GoogleFonts.piedra(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.piedra(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.piedra(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.piedra(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.piedra(textStyle: textTheme.bodyText2), + caption: GoogleFonts.piedra(textStyle: textTheme.caption), + button: GoogleFonts.piedra(textStyle: textTheme.button), + overline: GoogleFonts.piedra(textStyle: textTheme.overline), + ); + } + + /// Applies the Pinyon Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pinyon+Script + static TextStyle pinyonScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '76a6132a59fff29721156baa5452296b0cf50a435c5bdba96e8bda980999341b', + 62100, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PinyonScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pinyon Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pinyon+Script + static TextTheme pinyonScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pinyonScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.pinyonScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.pinyonScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.pinyonScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.pinyonScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.pinyonScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pinyonScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pinyonScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pinyonScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pinyonScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pinyonScript(textStyle: textTheme.caption), + button: GoogleFonts.pinyonScript(textStyle: textTheme.button), + overline: GoogleFonts.pinyonScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Pirata One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pirata+One + static TextStyle pirataOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5fb40958eab064bad8294b018f0eff54a3deb5dcb3717eecc9dd41e8db217618', + 56268, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PirataOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pirata One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pirata+One + static TextTheme pirataOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pirataOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.pirataOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.pirataOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.pirataOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.pirataOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.pirataOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pirataOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pirataOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pirataOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pirataOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pirataOne(textStyle: textTheme.caption), + button: GoogleFonts.pirataOne(textStyle: textTheme.button), + overline: GoogleFonts.pirataOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Plaster font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Plaster + static TextStyle plaster({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '075c37d102ea4665ad52b444dd9ccf8c06ebd6d7125c8cf59644c1b1653abe6d', + 30672, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Plaster', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Plaster font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Plaster + static TextTheme plasterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.plaster(textStyle: textTheme.headline1), + headline2: GoogleFonts.plaster(textStyle: textTheme.headline2), + headline3: GoogleFonts.plaster(textStyle: textTheme.headline3), + headline4: GoogleFonts.plaster(textStyle: textTheme.headline4), + headline5: GoogleFonts.plaster(textStyle: textTheme.headline5), + headline6: GoogleFonts.plaster(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.plaster(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.plaster(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.plaster(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.plaster(textStyle: textTheme.bodyText2), + caption: GoogleFonts.plaster(textStyle: textTheme.caption), + button: GoogleFonts.plaster(textStyle: textTheme.button), + overline: GoogleFonts.plaster(textStyle: textTheme.overline), + ); + } + + /// Applies the Play font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Play + static TextStyle play({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e198eae88b87f9891da54cbb4e5b631b4f8e8af961970b14082506c5c1bd3183', + 123764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '46b28c6395256a72fe1900fc5218c9ef0c78153157532b0ebc6b6859696d717d', + 125468, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Play', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Play font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Play + static TextTheme playTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.play(textStyle: textTheme.headline1), + headline2: GoogleFonts.play(textStyle: textTheme.headline2), + headline3: GoogleFonts.play(textStyle: textTheme.headline3), + headline4: GoogleFonts.play(textStyle: textTheme.headline4), + headline5: GoogleFonts.play(textStyle: textTheme.headline5), + headline6: GoogleFonts.play(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.play(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.play(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.play(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.play(textStyle: textTheme.bodyText2), + caption: GoogleFonts.play(textStyle: textTheme.caption), + button: GoogleFonts.play(textStyle: textTheme.button), + overline: GoogleFonts.play(textStyle: textTheme.overline), + ); + } + + /// Applies the Playball font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Playball + static TextStyle playball({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '73b95f0b1cd341f32c0f20d1fda10e035733b1906538a749d3fc06d9402c8f2f', + 42772, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Playball', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Playball font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Playball + static TextTheme playballTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.playball(textStyle: textTheme.headline1), + headline2: GoogleFonts.playball(textStyle: textTheme.headline2), + headline3: GoogleFonts.playball(textStyle: textTheme.headline3), + headline4: GoogleFonts.playball(textStyle: textTheme.headline4), + headline5: GoogleFonts.playball(textStyle: textTheme.headline5), + headline6: GoogleFonts.playball(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.playball(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.playball(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.playball(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.playball(textStyle: textTheme.bodyText2), + caption: GoogleFonts.playball(textStyle: textTheme.caption), + button: GoogleFonts.playball(textStyle: textTheme.button), + overline: GoogleFonts.playball(textStyle: textTheme.overline), + ); + } + + /// Applies the Playfair Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Playfair+Display + static TextStyle playfairDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '924bc8e9d64e8b2f2cb789375461b2d504e9975b6f77da5ffc252ddc8a3aac57', + 157252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '548814592545ef5a92d9c32a90d369cc51da8a75c2a9397c3f8b64550d64f723', + 144588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e5f443f351dd32a170af092c9d5509a205b292561fff1cc93c7a775be1508529', + 162776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b30290eb18fd60330cbcf52d5f3cfdb174100195152ee6c527c286b01155a193', + 151536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b6c0ff8733004f8c2f6cf42f45af14fbd569ba824fb2843b3db4f3e15616cedd', + 159648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '19e0ceccbc574b8a28fe94bd62388dc4dd8dbb00da8fda92003d293ff75bf9ed', + 146708, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PlayfairDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Playfair Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Playfair+Display + static TextTheme playfairDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.playfairDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.playfairDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.playfairDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.playfairDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.playfairDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.playfairDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.playfairDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.playfairDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.playfairDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.playfairDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.playfairDisplay(textStyle: textTheme.caption), + button: GoogleFonts.playfairDisplay(textStyle: textTheme.button), + overline: GoogleFonts.playfairDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Playfair Display SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Playfair+Display+SC + static TextStyle playfairDisplaySc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b4e28ec5aef07315383b9ec24d14cafd9f9e82652f0907ffa96bc78936a2bcf3', + 108552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fdba2100fec23dad94f0b77ea42bd7fe1e70cb13c977ff4097bee8f4a5d3deb2', + 102356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6e248f16fb366b22ece90b547726b0fa0844647d39802ca9bf4509e2c994973e', + 112728, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '40348910c72e109930f4b7b7beac71da6dbd2154ab6e19342f6403cfb39799b8', + 106904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '76b7867b75532041e0acff80523482c84138383984e6e03047bbcdf82664edaf', + 110508, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2bd6dd3db89e38a5d8e179e638978bc19492a6891d5a77a39f9391d18b2d35d7', + 108044, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PlayfairDisplaySC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Playfair Display SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Playfair+Display+SC + static TextTheme playfairDisplayScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.playfairDisplaySc(textStyle: textTheme.headline1), + headline2: GoogleFonts.playfairDisplaySc(textStyle: textTheme.headline2), + headline3: GoogleFonts.playfairDisplaySc(textStyle: textTheme.headline3), + headline4: GoogleFonts.playfairDisplaySc(textStyle: textTheme.headline4), + headline5: GoogleFonts.playfairDisplaySc(textStyle: textTheme.headline5), + headline6: GoogleFonts.playfairDisplaySc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.playfairDisplaySc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.playfairDisplaySc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.playfairDisplaySc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.playfairDisplaySc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.playfairDisplaySc(textStyle: textTheme.caption), + button: GoogleFonts.playfairDisplaySc(textStyle: textTheme.button), + overline: GoogleFonts.playfairDisplaySc(textStyle: textTheme.overline), + ); + } + + /// Applies the Podkova font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Podkova + static TextStyle podkova({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0add25e02638273bd9b4fcf35c8b76256a3a4e03952c161c48592fae22c5fc34', + 107676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3f02b4ccaed0ce6f2b29a1a9a6a7d4277651708435bc6f85466d43b1f7946980', + 107876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0cc312c8ebd6612b3c99e662d435f1299506dd87fe2eda68b3a99a77910ff84b', + 107768, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '18a450ac10399ddda8864f93d96f61b5d636d2d450b6ce5b67ed4247c24b8fb4', + 107696, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f608ec4d8cd807e20ea8e24c392d1d2a7480b32148f5ad72b5c133b6f630b8f6', + 106876, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Podkova', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Podkova font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Podkova + static TextTheme podkovaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.podkova(textStyle: textTheme.headline1), + headline2: GoogleFonts.podkova(textStyle: textTheme.headline2), + headline3: GoogleFonts.podkova(textStyle: textTheme.headline3), + headline4: GoogleFonts.podkova(textStyle: textTheme.headline4), + headline5: GoogleFonts.podkova(textStyle: textTheme.headline5), + headline6: GoogleFonts.podkova(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.podkova(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.podkova(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.podkova(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.podkova(textStyle: textTheme.bodyText2), + caption: GoogleFonts.podkova(textStyle: textTheme.caption), + button: GoogleFonts.podkova(textStyle: textTheme.button), + overline: GoogleFonts.podkova(textStyle: textTheme.overline), + ); + } + + /// Applies the Poiret One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poiret+One + static TextStyle poiretOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '67bb327af0416e138d92e1fea7c569a19a5c981b0997edee4464ad15cd4ce9f7', + 47660, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PoiretOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Poiret One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poiret+One + static TextTheme poiretOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.poiretOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.poiretOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.poiretOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.poiretOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.poiretOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.poiretOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.poiretOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.poiretOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.poiretOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.poiretOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.poiretOne(textStyle: textTheme.caption), + button: GoogleFonts.poiretOne(textStyle: textTheme.button), + overline: GoogleFonts.poiretOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Poller One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poller+One + static TextStyle pollerOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8000b5517c4c1c62df73fa743687dad6e25276b2caea09a6ff237f0c19f9128d', + 31540, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PollerOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Poller One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poller+One + static TextTheme pollerOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pollerOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.pollerOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.pollerOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.pollerOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.pollerOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.pollerOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pollerOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pollerOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pollerOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pollerOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pollerOne(textStyle: textTheme.caption), + button: GoogleFonts.pollerOne(textStyle: textTheme.button), + overline: GoogleFonts.pollerOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Poly font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poly + static TextStyle poly({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25d6b0314754bfa56533ecd2bf390f3f2108e60043db13b206cca5e0a900f857', + 76776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cc94a04fc599f53d7e32be6f932b998f8229d4e0462ebb808d61554abb4f0dbc', + 74188, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Poly', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Poly font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poly + static TextTheme polyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.poly(textStyle: textTheme.headline1), + headline2: GoogleFonts.poly(textStyle: textTheme.headline2), + headline3: GoogleFonts.poly(textStyle: textTheme.headline3), + headline4: GoogleFonts.poly(textStyle: textTheme.headline4), + headline5: GoogleFonts.poly(textStyle: textTheme.headline5), + headline6: GoogleFonts.poly(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.poly(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.poly(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.poly(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.poly(textStyle: textTheme.bodyText2), + caption: GoogleFonts.poly(textStyle: textTheme.caption), + button: GoogleFonts.poly(textStyle: textTheme.button), + overline: GoogleFonts.poly(textStyle: textTheme.overline), + ); + } + + /// Applies the Pompiere font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pompiere + static TextStyle pompiere({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '938a73a33e8b01f6bd94758995b7e75a9f06dd9d7cc1977ef653cb5f0368004c', + 36692, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Pompiere', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pompiere font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pompiere + static TextTheme pompiereTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pompiere(textStyle: textTheme.headline1), + headline2: GoogleFonts.pompiere(textStyle: textTheme.headline2), + headline3: GoogleFonts.pompiere(textStyle: textTheme.headline3), + headline4: GoogleFonts.pompiere(textStyle: textTheme.headline4), + headline5: GoogleFonts.pompiere(textStyle: textTheme.headline5), + headline6: GoogleFonts.pompiere(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pompiere(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pompiere(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pompiere(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pompiere(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pompiere(textStyle: textTheme.caption), + button: GoogleFonts.pompiere(textStyle: textTheme.button), + overline: GoogleFonts.pompiere(textStyle: textTheme.overline), + ); + } + + /// Applies the Pontano Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pontano+Sans + static TextStyle pontanoSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5642e38228ac272d77222d1b2150dd461c55d090beba64bbb9f11d169e573589', + 28232, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PontanoSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pontano Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pontano+Sans + static TextTheme pontanoSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pontanoSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.pontanoSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.pontanoSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.pontanoSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.pontanoSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.pontanoSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pontanoSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pontanoSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pontanoSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pontanoSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pontanoSans(textStyle: textTheme.caption), + button: GoogleFonts.pontanoSans(textStyle: textTheme.button), + overline: GoogleFonts.pontanoSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Poor Story font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poor+Story + static TextStyle poorStory({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a915416edf6eea5c6eb16e098a45ee910564e4d15dfba8a3136e293e2f2d8a67', + 1802972, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PoorStory', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Poor Story font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poor+Story + static TextTheme poorStoryTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.poorStory(textStyle: textTheme.headline1), + headline2: GoogleFonts.poorStory(textStyle: textTheme.headline2), + headline3: GoogleFonts.poorStory(textStyle: textTheme.headline3), + headline4: GoogleFonts.poorStory(textStyle: textTheme.headline4), + headline5: GoogleFonts.poorStory(textStyle: textTheme.headline5), + headline6: GoogleFonts.poorStory(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.poorStory(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.poorStory(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.poorStory(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.poorStory(textStyle: textTheme.bodyText2), + caption: GoogleFonts.poorStory(textStyle: textTheme.caption), + button: GoogleFonts.poorStory(textStyle: textTheme.button), + overline: GoogleFonts.poorStory(textStyle: textTheme.overline), + ); + } + + /// Applies the Poppins font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poppins + static TextStyle poppins({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '609ae3f057d392507fed90188cf6f9d5f85bb59f613c0decb2ecc9f51312a5cd', + 148976, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4a2e8bca7b027b0f8cc0218b80ec9823ca3b98d4a06f17651337b01fb85f8ede', + 172308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2a489fff366883b0e5df107f6f4d5af2554723b61495c5509d4c3f62e038bc47', + 147952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e331f856e52ddab916a83bea449fda91561fab22bef776c8a817bcd9871ce0c9', + 170912, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7f15d9a49bc6ca8b49ac995bbc36065b4bab0ed9f6d394a4c49d8f9ac85672c2', + 146472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2d4fb2fa8e59703eaf3fd748fdba32ff276e881015912154d7ffd5c24ba0afd6', + 168944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2425ebbc021bfdd18fe55edbeeb1539d22a217212c14430a7d4d75266a333bbc', + 145312, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f058c785d855d5a6020eee6962eba4a653a871e6f07cabe930504e857b76ccb7', + 167140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '45870260a29fa7d3e0eff8cdd91993fb4a9ce4cced3d7b72c3ef7d24380bfc2d', + 143516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '231c5c16820cd2507d24716e41bce0bafafe7175410e6197b5621c9cedaf84ff', + 165512, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d665d5b75a9500040b2cc201c2b07af5faca7228372dc6f4572d2d5b2291097', + 142148, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cb112397951c33d64e908cec5cf9f34d1ecc2c13f047f98061f834fc4a96e490', + 161896, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '210933fb1bb4e846d37ef00c92cae636ac35633132cf2157c7ac879f27f82068', + 141260, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '478ff165d4f208b41963f9774fda29358a902ad29026d486a94a50bb2e9b7a05', + 160224, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9599edf36a7c40e752cd1fbc308f5351c59aae0b3bd6fa5bfbdaa61c16f8cee1', + 140220, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '230e076f3eaab8aa5b295152336dd453ac731569b1f72b4aa836f0edd6cdfe74', + 158708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2535406edd2aa55242329705ca9418a07d3a51ae28cadca3ee5becae61aa8987', + 139056, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '82eaa315798c980852cb782b3dc81adeb39c16903a1a46d96e5917f79266929d', + 155956, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Poppins', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Poppins font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Poppins + static TextTheme poppinsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.poppins(textStyle: textTheme.headline1), + headline2: GoogleFonts.poppins(textStyle: textTheme.headline2), + headline3: GoogleFonts.poppins(textStyle: textTheme.headline3), + headline4: GoogleFonts.poppins(textStyle: textTheme.headline4), + headline5: GoogleFonts.poppins(textStyle: textTheme.headline5), + headline6: GoogleFonts.poppins(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.poppins(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.poppins(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.poppins(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.poppins(textStyle: textTheme.bodyText2), + caption: GoogleFonts.poppins(textStyle: textTheme.caption), + button: GoogleFonts.poppins(textStyle: textTheme.button), + overline: GoogleFonts.poppins(textStyle: textTheme.overline), + ); + } + + /// Applies the Port Lligat Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Port+Lligat+Sans + static TextStyle portLligatSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '84c1f23904d96ac1b51af7e38d0892c88f5a84b7bdd1c30685b9cb4d2213706d', + 34340, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PortLligatSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Port Lligat Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Port+Lligat+Sans + static TextTheme portLligatSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.portLligatSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.portLligatSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.portLligatSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.portLligatSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.portLligatSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.portLligatSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.portLligatSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.portLligatSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.portLligatSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.portLligatSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.portLligatSans(textStyle: textTheme.caption), + button: GoogleFonts.portLligatSans(textStyle: textTheme.button), + overline: GoogleFonts.portLligatSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Port Lligat Slab font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Port+Lligat+Slab + static TextStyle portLligatSlab({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '14a5e5dd29e0381386f5b0417b504bb1aadd724682e7f07cd5d09f95b4c9cc99', + 38112, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PortLligatSlab', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Port Lligat Slab font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Port+Lligat+Slab + static TextTheme portLligatSlabTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.portLligatSlab(textStyle: textTheme.headline1), + headline2: GoogleFonts.portLligatSlab(textStyle: textTheme.headline2), + headline3: GoogleFonts.portLligatSlab(textStyle: textTheme.headline3), + headline4: GoogleFonts.portLligatSlab(textStyle: textTheme.headline4), + headline5: GoogleFonts.portLligatSlab(textStyle: textTheme.headline5), + headline6: GoogleFonts.portLligatSlab(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.portLligatSlab(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.portLligatSlab(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.portLligatSlab(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.portLligatSlab(textStyle: textTheme.bodyText2), + caption: GoogleFonts.portLligatSlab(textStyle: textTheme.caption), + button: GoogleFonts.portLligatSlab(textStyle: textTheme.button), + overline: GoogleFonts.portLligatSlab(textStyle: textTheme.overline), + ); + } + + /// Applies the Potta One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Potta+One + static TextStyle pottaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '56773288a5bd09c28d1bbaceb69bc83dc390929b2f9a8742525d71eabca3e15d', + 4911480, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PottaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Potta One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Potta+One + static TextTheme pottaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pottaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.pottaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.pottaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.pottaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.pottaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.pottaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pottaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pottaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pottaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pottaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pottaOne(textStyle: textTheme.caption), + button: GoogleFonts.pottaOne(textStyle: textTheme.button), + overline: GoogleFonts.pottaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Pragati Narrow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pragati+Narrow + static TextStyle pragatiNarrow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1778fbb91f3825af5daf5dfe6d44737ee48e6c63a95f25348b39ccb9fcda8fb6', + 229548, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e7b8eb47eaef49ea50a19115bddfaf35aebf2f4577f8a3b9cab531595bc97ef', + 228640, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PragatiNarrow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pragati Narrow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pragati+Narrow + static TextTheme pragatiNarrowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pragatiNarrow(textStyle: textTheme.headline1), + headline2: GoogleFonts.pragatiNarrow(textStyle: textTheme.headline2), + headline3: GoogleFonts.pragatiNarrow(textStyle: textTheme.headline3), + headline4: GoogleFonts.pragatiNarrow(textStyle: textTheme.headline4), + headline5: GoogleFonts.pragatiNarrow(textStyle: textTheme.headline5), + headline6: GoogleFonts.pragatiNarrow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pragatiNarrow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pragatiNarrow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pragatiNarrow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pragatiNarrow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pragatiNarrow(textStyle: textTheme.caption), + button: GoogleFonts.pragatiNarrow(textStyle: textTheme.button), + overline: GoogleFonts.pragatiNarrow(textStyle: textTheme.overline), + ); + } + + /// Applies the Prata font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Prata + static TextStyle prata({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dae0ecee4b97ae6292786b6e9e7efc1c63cf85f8beaef215151813c08fd2aa02', + 65088, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Prata', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Prata font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Prata + static TextTheme prataTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.prata(textStyle: textTheme.headline1), + headline2: GoogleFonts.prata(textStyle: textTheme.headline2), + headline3: GoogleFonts.prata(textStyle: textTheme.headline3), + headline4: GoogleFonts.prata(textStyle: textTheme.headline4), + headline5: GoogleFonts.prata(textStyle: textTheme.headline5), + headline6: GoogleFonts.prata(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.prata(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.prata(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.prata(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.prata(textStyle: textTheme.bodyText2), + caption: GoogleFonts.prata(textStyle: textTheme.caption), + button: GoogleFonts.prata(textStyle: textTheme.button), + overline: GoogleFonts.prata(textStyle: textTheme.overline), + ); + } + + /// Applies the Press Start 2P font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Press+Start+2P + static TextStyle pressStart2p({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba4683bc76380100a5f8e7fae42dd03216a17bd62025a4f24d933df65845a9ac', + 57416, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PressStart2P', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Press Start 2P font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Press+Start+2P + static TextTheme pressStart2pTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pressStart2p(textStyle: textTheme.headline1), + headline2: GoogleFonts.pressStart2p(textStyle: textTheme.headline2), + headline3: GoogleFonts.pressStart2p(textStyle: textTheme.headline3), + headline4: GoogleFonts.pressStart2p(textStyle: textTheme.headline4), + headline5: GoogleFonts.pressStart2p(textStyle: textTheme.headline5), + headline6: GoogleFonts.pressStart2p(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pressStart2p(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pressStart2p(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pressStart2p(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pressStart2p(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pressStart2p(textStyle: textTheme.caption), + button: GoogleFonts.pressStart2p(textStyle: textTheme.button), + overline: GoogleFonts.pressStart2p(textStyle: textTheme.overline), + ); + } + + /// Applies the Pridi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pridi + static TextStyle pridi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25767951345549f712ecc99e7f7e0ed309d7e3b707e8f82ac578dea2843ee338', + 120664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '418f1e97f68102aa823ef64c5f96fbcec3fb67597331f6b65bbff28c82031fed', + 141312, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '33f3b1e354916fe8ce1a179c631238fdc60f52a959f39a02efbd3f8023bfbbda', + 141904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b57f641bac735f6cd44057a11cbabb787cbc33d1c8270040dc7d1cb6c4563858', + 137940, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8847f26d3d388eb8a757c857d14058773c4f265b29fe5ef2da5da9132fb2924a', + 118788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '26c0c1d38bb9f9387d48474dd1abf32af18563e40fa1067abcfa242e8870cf6b', + 117864, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Pridi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Pridi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Pridi + static TextTheme pridiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.pridi(textStyle: textTheme.headline1), + headline2: GoogleFonts.pridi(textStyle: textTheme.headline2), + headline3: GoogleFonts.pridi(textStyle: textTheme.headline3), + headline4: GoogleFonts.pridi(textStyle: textTheme.headline4), + headline5: GoogleFonts.pridi(textStyle: textTheme.headline5), + headline6: GoogleFonts.pridi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.pridi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.pridi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.pridi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.pridi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.pridi(textStyle: textTheme.caption), + button: GoogleFonts.pridi(textStyle: textTheme.button), + overline: GoogleFonts.pridi(textStyle: textTheme.overline), + ); + } + + /// Applies the Princess Sofia font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Princess+Sofia + static TextStyle princessSofia({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9f20c793c38b666148e6b2cb5b5303d48501b0f54d45aac73f3b59a495c7cdc0', + 272212, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PrincessSofia', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Princess Sofia font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Princess+Sofia + static TextTheme princessSofiaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.princessSofia(textStyle: textTheme.headline1), + headline2: GoogleFonts.princessSofia(textStyle: textTheme.headline2), + headline3: GoogleFonts.princessSofia(textStyle: textTheme.headline3), + headline4: GoogleFonts.princessSofia(textStyle: textTheme.headline4), + headline5: GoogleFonts.princessSofia(textStyle: textTheme.headline5), + headline6: GoogleFonts.princessSofia(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.princessSofia(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.princessSofia(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.princessSofia(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.princessSofia(textStyle: textTheme.bodyText2), + caption: GoogleFonts.princessSofia(textStyle: textTheme.caption), + button: GoogleFonts.princessSofia(textStyle: textTheme.button), + overline: GoogleFonts.princessSofia(textStyle: textTheme.overline), + ); + } + + /// Applies the Prociono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Prociono + static TextStyle prociono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '61f885124a2a2bbcb15f757f4ac96bf9509c0c1869f1efaa3c4cc6ce99d01f16', + 31088, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Prociono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Prociono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Prociono + static TextTheme procionoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.prociono(textStyle: textTheme.headline1), + headline2: GoogleFonts.prociono(textStyle: textTheme.headline2), + headline3: GoogleFonts.prociono(textStyle: textTheme.headline3), + headline4: GoogleFonts.prociono(textStyle: textTheme.headline4), + headline5: GoogleFonts.prociono(textStyle: textTheme.headline5), + headline6: GoogleFonts.prociono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.prociono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.prociono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.prociono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.prociono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.prociono(textStyle: textTheme.caption), + button: GoogleFonts.prociono(textStyle: textTheme.button), + overline: GoogleFonts.prociono(textStyle: textTheme.overline), + ); + } + + /// Applies the Prompt font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Prompt + static TextStyle prompt({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '48988c00dff9e5346bafb0230e233cc244d06d53de9a8c7b1c5ae95b508878d9', + 106868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fa017c19d47d8c1de3c967302dc49e99d37de71795dfb971c06ce63c31a2b230', + 116584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'be13887c30cb0eb82b46627a8d18c34490049df205c234b3d27d8c3efbfeacec', + 106872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2ac60a88dbbd5f9ae43c89ce90966920480aa263c9c157da76a8f51c68efebc6', + 116628, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3e355dba756f556f47a7a9d99fe46cfa2d2676c6937bb2af9f39e84bf13ba0a8', + 106216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'cdbdb3675fcbe7c22771818e356aaca5f5bfbd59635b7223dff98a1ef9843b4b', + 115964, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a26fa613f518a56e8d6ab2da471f1a74fde4a5fd95552a539694b777832f2627', + 106060, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2ac0428ddf82e1d43425e6afb249d0000b0f3eed6e8583cd6712f53f585f33fa', + 114924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '627e26dc44fbd7d87a3300a5ddb700b5d169b5cee2c915f78085ced694f0ef98', + 106100, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c455330873fbc77aaf5958ea7fe12fc7af2325446a34440ebaf090775b7a2f4f', + 114748, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5be3aa9ccbda532fccad8b87b6e554f0403860f32b4499ea56228ecc81246e5d', + 104076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '692795800d326358c0dfeb443453d36353284ee31c283cfde37df17258f6f2bc', + 114500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a3f1635714fe8861ed1027027e0e34183db3b1197ebfba3c2283739950e1fc7', + 105580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '46317d49f08a684dff0cd9a335124eba5f1feebc850ab74ab6a023096f224c4f', + 114080, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '79977c86dc67cc15e7cce3392fd9a3b9bfcaf261c5bf48de9820fb6b9cf8dd5a', + 105156, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1bd02cc605f0e4ec0c90fa33ee5726bd1679d6a36c64f1779de4aee232e8a88a', + 113996, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5f0519c649be920aec99489ffcd76b23ec686b254b28fe9cffdd6e5690280c41', + 104892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9390dbb38f163bec75f6d6682ae93a821e776cd9bed89bf402c7104d295dca25', + 127800, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Prompt', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Prompt font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Prompt + static TextTheme promptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.prompt(textStyle: textTheme.headline1), + headline2: GoogleFonts.prompt(textStyle: textTheme.headline2), + headline3: GoogleFonts.prompt(textStyle: textTheme.headline3), + headline4: GoogleFonts.prompt(textStyle: textTheme.headline4), + headline5: GoogleFonts.prompt(textStyle: textTheme.headline5), + headline6: GoogleFonts.prompt(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.prompt(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.prompt(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.prompt(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.prompt(textStyle: textTheme.bodyText2), + caption: GoogleFonts.prompt(textStyle: textTheme.caption), + button: GoogleFonts.prompt(textStyle: textTheme.button), + overline: GoogleFonts.prompt(textStyle: textTheme.overline), + ); + } + + /// Applies the Prosto One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Prosto+One + static TextStyle prostoOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '48e9abcc05d19f1dfd678d55c8747ed931282ea5b332f232e7fe90254af60f9a', + 69248, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ProstoOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Prosto One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Prosto+One + static TextTheme prostoOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.prostoOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.prostoOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.prostoOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.prostoOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.prostoOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.prostoOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.prostoOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.prostoOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.prostoOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.prostoOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.prostoOne(textStyle: textTheme.caption), + button: GoogleFonts.prostoOne(textStyle: textTheme.button), + overline: GoogleFonts.prostoOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Proza Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Proza+Libre + static TextStyle prozaLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9b6195e0fb14a5155dc5f1e836d174961876e69e0c471b7ab8357696acb1d404', + 77600, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '79a33a14fa8f5bd86b8bd985de9a92647b0d6b62085299ae05b0c4f2cbf98bc8', + 77756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ac113922a0dc8f8533dcac9f1f9ec44f777502e94608291bd50da0fa981083d6', + 77960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a6506ab9342408e2f16f5991f7f13117f9c080dfb34c268e4378f507d01fe3b8', + 78168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1e1b5cd4d00344b8bbbb015679e9bd7cc5e99a2fa3d6eb18b4f1303c90c3e68e', + 96824, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '522e6755ed4fd909ed6968fa89460d7eb69e6b90fb0124f5fec6dfadb7dd5dac', + 78188, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '14701643695bd3fb18b0e9f16049cd1caa35acee12446ecf10b0a179697f7748', + 77756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '176582be0d8f918514d1f30bb1cfea4729cbd968974eced79e977378653c62c9', + 77952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6d37a997a436ffd489943e8d33d8917c4eac47e1c20959ae0cd68f6470e932bb', + 91092, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e5a8cfe2f4e6f80f7a40d647e5ca78ffe1df63c22c413d962ce2f937a8ce34e2', + 90644, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ProzaLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Proza Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Proza+Libre + static TextTheme prozaLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.prozaLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.prozaLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.prozaLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.prozaLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.prozaLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.prozaLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.prozaLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.prozaLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.prozaLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.prozaLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.prozaLibre(textStyle: textTheme.caption), + button: GoogleFonts.prozaLibre(textStyle: textTheme.button), + overline: GoogleFonts.prozaLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Public Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Public+Sans + static TextStyle publicSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bbeb9408fbfe9d5d9ce8fbafbfc03c6b6cdf568002d0617c5ba2e7a7ed4e2927', + 47064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c5315eae10703301b7f62e88a7de796fcf6d0e22ce0484906b2a75717045d602', + 47172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c24444db34cbde1fe26eee9e01a5aeecaa2d5d04d760b016effb1efaaeca1eab', + 47136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a43ba20728262f80018c0f9cb41348b11a7a0f7ce4cec9524908f09a1ba9fc10', + 47124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3bd3b338d1c2daf799f2856f74a39cee09cfc8dd65a08a77dae77e3fdcee5516', + 47156, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1ba049c8f5505f644eeedde917f31244fbce5797f1daa0bc6ad7dee626cdd493', + 47240, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b64cde6ef854e50377acd226084a3b56da54c708c4b6b56b0e6efdbd6725e2eb', + 47276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a88f82d3a4c9ff1ef0ddd06d1f62a10636942fb2461837a8555c5a0c6c362c84', + 47420, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd59239c8e796e666d395620e22b7a4456496e2593b03448fca6ea8d8fc7697df', + 47392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b7e9ab1ba3ba765f5775306a4f4f66df2fc253782bdca66c44b36e09b4a65ced', + 47388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ce8d4637dcc7693ff3984ca3de2859af73e35a18142f87dff9fb8c3e2f9e8fa3', + 47468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1c6bac423bb2503db975062139990578c28e1b744fdf169b762f0ae69e4f5ad2', + 47408, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ed1d4975a041ddce0d086e9b30feb0d85236d1e95edeed6848841f480af24a49', + 47296, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a66352215ff1f71f3e0c04d07175608a1992529cf83d389cea2e601a72d4e90f', + 47424, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b2bdd1391e967996ae11ed929fa55e3811b4928bcdd356295d10ae67cef03949', + 47488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '056bab577fca8b802ca1629b53e48d0b66c5e0d7568553c4c85bc0107d87c865', + 47544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9e40fa8d8ef6e8979ff49e3f9220489c0961ca308a318f3400b176a6594877e9', + 47736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0b536907db7c2710ae92a77a16a1a413f3527e60b0fcc442d4f74513b6249e69', + 47740, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PublicSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Public Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Public+Sans + static TextTheme publicSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.publicSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.publicSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.publicSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.publicSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.publicSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.publicSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.publicSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.publicSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.publicSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.publicSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.publicSans(textStyle: textTheme.caption), + button: GoogleFonts.publicSans(textStyle: textTheme.button), + overline: GoogleFonts.publicSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Puritan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Puritan + static TextStyle puritan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '53c4e62f0ae59849064a30afb5f388987e173b8699d99efa7364a1b99c16385d', + 36476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '28385ca71871b908d353e761320647ac350dc310f04d767c54ffa33c5bb0e846', + 37752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a044a29b77d5907eb6eb71d1e7955016b52b63e928f6a1381bda726cb81317a', + 36232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '792b0deaf812e2c13a119b6c56f14b2c25e985edc90ba79c34dfe61c0d28db06', + 37656, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Puritan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Puritan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Puritan + static TextTheme puritanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.puritan(textStyle: textTheme.headline1), + headline2: GoogleFonts.puritan(textStyle: textTheme.headline2), + headline3: GoogleFonts.puritan(textStyle: textTheme.headline3), + headline4: GoogleFonts.puritan(textStyle: textTheme.headline4), + headline5: GoogleFonts.puritan(textStyle: textTheme.headline5), + headline6: GoogleFonts.puritan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.puritan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.puritan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.puritan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.puritan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.puritan(textStyle: textTheme.caption), + button: GoogleFonts.puritan(textStyle: textTheme.button), + overline: GoogleFonts.puritan(textStyle: textTheme.overline), + ); + } + + /// Applies the Purple Purse font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Purple+Purse + static TextStyle purplePurse({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5653d111577461c5bb526447a3f51696f803a7e41f0e5d379ae3a558f69927e0', + 62452, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'PurplePurse', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Purple Purse font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Purple+Purse + static TextTheme purplePurseTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.purplePurse(textStyle: textTheme.headline1), + headline2: GoogleFonts.purplePurse(textStyle: textTheme.headline2), + headline3: GoogleFonts.purplePurse(textStyle: textTheme.headline3), + headline4: GoogleFonts.purplePurse(textStyle: textTheme.headline4), + headline5: GoogleFonts.purplePurse(textStyle: textTheme.headline5), + headline6: GoogleFonts.purplePurse(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.purplePurse(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.purplePurse(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.purplePurse(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.purplePurse(textStyle: textTheme.bodyText2), + caption: GoogleFonts.purplePurse(textStyle: textTheme.caption), + button: GoogleFonts.purplePurse(textStyle: textTheme.button), + overline: GoogleFonts.purplePurse(textStyle: textTheme.overline), + ); + } + + /// Applies the Quando font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quando + static TextStyle quando({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2a8053aa17f88c09896da7eb7b6ee5d1652eaec863ae13d59efd1a763afcdb2a', + 49748, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Quando', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Quando font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quando + static TextTheme quandoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.quando(textStyle: textTheme.headline1), + headline2: GoogleFonts.quando(textStyle: textTheme.headline2), + headline3: GoogleFonts.quando(textStyle: textTheme.headline3), + headline4: GoogleFonts.quando(textStyle: textTheme.headline4), + headline5: GoogleFonts.quando(textStyle: textTheme.headline5), + headline6: GoogleFonts.quando(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.quando(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.quando(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.quando(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.quando(textStyle: textTheme.bodyText2), + caption: GoogleFonts.quando(textStyle: textTheme.caption), + button: GoogleFonts.quando(textStyle: textTheme.button), + overline: GoogleFonts.quando(textStyle: textTheme.overline), + ); + } + + /// Applies the Quantico font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quantico + static TextStyle quantico({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c0e68a0bf4434bcaf5078482638325be95f9ff8d23e161320e71396c3bac24db', + 20892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8dc51f4e759adff1e4ef04d9489decee6534f253a8c586119e29e6ac5d4ba3e8', + 22120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '893455159a698723c49ac3c7b21b2eab8d58a8ae07a566c4b1aa1d49d301b100', + 20872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1021a5020ebf627e4f792a27cf1af37913a9f7f26454ac4cc914f0f78b08df22', + 20636, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Quantico', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Quantico font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quantico + static TextTheme quanticoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.quantico(textStyle: textTheme.headline1), + headline2: GoogleFonts.quantico(textStyle: textTheme.headline2), + headline3: GoogleFonts.quantico(textStyle: textTheme.headline3), + headline4: GoogleFonts.quantico(textStyle: textTheme.headline4), + headline5: GoogleFonts.quantico(textStyle: textTheme.headline5), + headline6: GoogleFonts.quantico(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.quantico(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.quantico(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.quantico(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.quantico(textStyle: textTheme.bodyText2), + caption: GoogleFonts.quantico(textStyle: textTheme.caption), + button: GoogleFonts.quantico(textStyle: textTheme.button), + overline: GoogleFonts.quantico(textStyle: textTheme.overline), + ); + } + + /// Applies the Quattrocento font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quattrocento + static TextStyle quattrocento({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5889732ed96c5175bebb886a2f99f90cbf93d54ad643f7cf5376b4532c385aaa', + 79000, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '72919cef5349b9fa016e032e20becd479cf50e5b1a159f0b68747631e333ae6c', + 80100, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Quattrocento', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Quattrocento font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quattrocento + static TextTheme quattrocentoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.quattrocento(textStyle: textTheme.headline1), + headline2: GoogleFonts.quattrocento(textStyle: textTheme.headline2), + headline3: GoogleFonts.quattrocento(textStyle: textTheme.headline3), + headline4: GoogleFonts.quattrocento(textStyle: textTheme.headline4), + headline5: GoogleFonts.quattrocento(textStyle: textTheme.headline5), + headline6: GoogleFonts.quattrocento(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.quattrocento(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.quattrocento(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.quattrocento(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.quattrocento(textStyle: textTheme.bodyText2), + caption: GoogleFonts.quattrocento(textStyle: textTheme.caption), + button: GoogleFonts.quattrocento(textStyle: textTheme.button), + overline: GoogleFonts.quattrocento(textStyle: textTheme.overline), + ); + } + + /// Applies the Quattrocento Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quattrocento+Sans + static TextStyle quattrocentoSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '114280821a2f8698d737c5c9bcbc986cf36a4dbd9fa7c58e448b35520a6053ec', + 48788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c933f0ba971f5573109a7674a40f980252c7f3c810a75f9ff29c016102118e85', + 61236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a542b5aa650f5ce3fa5e6b692feef037c10962d8ae63545c47fdf964e5b3e26', + 48324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'edadcb4799c44215ae17124bc3eac621aef5a4348743df4d74ff83fd09a601a4', + 49520, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'QuattrocentoSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Quattrocento Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quattrocento+Sans + static TextTheme quattrocentoSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.quattrocentoSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.quattrocentoSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.quattrocentoSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.quattrocentoSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.quattrocentoSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.quattrocentoSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.quattrocentoSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.quattrocentoSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.quattrocentoSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.quattrocentoSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.quattrocentoSans(textStyle: textTheme.caption), + button: GoogleFonts.quattrocentoSans(textStyle: textTheme.button), + overline: GoogleFonts.quattrocentoSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Questrial font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Questrial + static TextStyle questrial({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ad815e7b1e7fe3c135b94c7241340918c62215027afaf848638e71f9ba75125a', + 64528, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Questrial', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Questrial font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Questrial + static TextTheme questrialTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.questrial(textStyle: textTheme.headline1), + headline2: GoogleFonts.questrial(textStyle: textTheme.headline2), + headline3: GoogleFonts.questrial(textStyle: textTheme.headline3), + headline4: GoogleFonts.questrial(textStyle: textTheme.headline4), + headline5: GoogleFonts.questrial(textStyle: textTheme.headline5), + headline6: GoogleFonts.questrial(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.questrial(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.questrial(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.questrial(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.questrial(textStyle: textTheme.bodyText2), + caption: GoogleFonts.questrial(textStyle: textTheme.caption), + button: GoogleFonts.questrial(textStyle: textTheme.button), + overline: GoogleFonts.questrial(textStyle: textTheme.overline), + ); + } + + /// Applies the Quicksand font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quicksand + static TextStyle quicksand({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d9cb44be0f4a238981aae2eb07e9157e00c48fae09163bea0866e136d1c3f1f', + 82640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0f408f35c3679417b5580701f3ac08830ce36535af5a643a2ef5b59e91c3c6b7', + 81668, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '76d743f0975259e38b62a1b671044d0a6584e7ae0a8389a9dca5d6d7e5e24031', + 81400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6bb475d143c61221c4ea174d3c51728268e58b12dbc14600d59020ef8deaaead', + 82168, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Quicksand', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Quicksand font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quicksand + static TextTheme quicksandTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.quicksand(textStyle: textTheme.headline1), + headline2: GoogleFonts.quicksand(textStyle: textTheme.headline2), + headline3: GoogleFonts.quicksand(textStyle: textTheme.headline3), + headline4: GoogleFonts.quicksand(textStyle: textTheme.headline4), + headline5: GoogleFonts.quicksand(textStyle: textTheme.headline5), + headline6: GoogleFonts.quicksand(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.quicksand(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.quicksand(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.quicksand(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.quicksand(textStyle: textTheme.bodyText2), + caption: GoogleFonts.quicksand(textStyle: textTheme.caption), + button: GoogleFonts.quicksand(textStyle: textTheme.button), + overline: GoogleFonts.quicksand(textStyle: textTheme.overline), + ); + } + + /// Applies the Quintessential font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quintessential + static TextStyle quintessential({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '030ff82f2f4a02d56504ed9191c94412439e0fc2bb5ea13d563ecc793620de06', + 73476, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Quintessential', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Quintessential font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Quintessential + static TextTheme quintessentialTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.quintessential(textStyle: textTheme.headline1), + headline2: GoogleFonts.quintessential(textStyle: textTheme.headline2), + headline3: GoogleFonts.quintessential(textStyle: textTheme.headline3), + headline4: GoogleFonts.quintessential(textStyle: textTheme.headline4), + headline5: GoogleFonts.quintessential(textStyle: textTheme.headline5), + headline6: GoogleFonts.quintessential(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.quintessential(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.quintessential(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.quintessential(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.quintessential(textStyle: textTheme.bodyText2), + caption: GoogleFonts.quintessential(textStyle: textTheme.caption), + button: GoogleFonts.quintessential(textStyle: textTheme.button), + overline: GoogleFonts.quintessential(textStyle: textTheme.overline), + ); + } + + /// Applies the Qwigley font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Qwigley + static TextStyle qwigley({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9e8fd5b41b64bfc84fd94dd67445892d8149c004a0054984f37eb95effb71095', + 40404, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Qwigley', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Qwigley font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Qwigley + static TextTheme qwigleyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.qwigley(textStyle: textTheme.headline1), + headline2: GoogleFonts.qwigley(textStyle: textTheme.headline2), + headline3: GoogleFonts.qwigley(textStyle: textTheme.headline3), + headline4: GoogleFonts.qwigley(textStyle: textTheme.headline4), + headline5: GoogleFonts.qwigley(textStyle: textTheme.headline5), + headline6: GoogleFonts.qwigley(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.qwigley(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.qwigley(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.qwigley(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.qwigley(textStyle: textTheme.bodyText2), + caption: GoogleFonts.qwigley(textStyle: textTheme.caption), + button: GoogleFonts.qwigley(textStyle: textTheme.button), + overline: GoogleFonts.qwigley(textStyle: textTheme.overline), + ); + } + + /// Applies the Racing Sans One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Racing+Sans+One + static TextStyle racingSansOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd832218eb9f68c818398e21dff506b95b27cf9a0830a3866a204eb2d2044027a', + 96960, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RacingSansOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Racing Sans One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Racing+Sans+One + static TextTheme racingSansOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.racingSansOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.racingSansOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.racingSansOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.racingSansOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.racingSansOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.racingSansOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.racingSansOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.racingSansOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.racingSansOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.racingSansOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.racingSansOne(textStyle: textTheme.caption), + button: GoogleFonts.racingSansOne(textStyle: textTheme.button), + overline: GoogleFonts.racingSansOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Radley font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Radley + static TextStyle radley({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6793fc8150706eb473a493107e09c2e519147ccf8d28dea89f49427c0dca0481', + 47660, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd01dd3f7b9c28e1f719a10c2a9dc88cd2827fcc64c09173e01e8b397f7615442', + 40760, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Radley', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Radley font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Radley + static TextTheme radleyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.radley(textStyle: textTheme.headline1), + headline2: GoogleFonts.radley(textStyle: textTheme.headline2), + headline3: GoogleFonts.radley(textStyle: textTheme.headline3), + headline4: GoogleFonts.radley(textStyle: textTheme.headline4), + headline5: GoogleFonts.radley(textStyle: textTheme.headline5), + headline6: GoogleFonts.radley(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.radley(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.radley(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.radley(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.radley(textStyle: textTheme.bodyText2), + caption: GoogleFonts.radley(textStyle: textTheme.caption), + button: GoogleFonts.radley(textStyle: textTheme.button), + overline: GoogleFonts.radley(textStyle: textTheme.overline), + ); + } + + /// Applies the Rajdhani font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rajdhani + static TextStyle rajdhani({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5d3e322fc971c11dc62d2cb01d49ffb76c16b801c7811493250d84aa8f12fa3f', + 235652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '28d153f34f1ea3bd1abf9d6639f49ee9ee3b8b01badde2e32892146d8196b19a', + 234648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd0e11c0858bfd9226f322293328602ca2c5a89cec03fd80c333f933e0b26e653', + 232788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2ab7a240fa08011c00222b91e955d71588ccf8d82ed43833580bf8a20082c836', + 232244, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '01025724bc7898c86c82d19ae1779cb44ca7492a947094eb0249653e3d26850a', + 234596, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rajdhani', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rajdhani font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rajdhani + static TextTheme rajdhaniTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rajdhani(textStyle: textTheme.headline1), + headline2: GoogleFonts.rajdhani(textStyle: textTheme.headline2), + headline3: GoogleFonts.rajdhani(textStyle: textTheme.headline3), + headline4: GoogleFonts.rajdhani(textStyle: textTheme.headline4), + headline5: GoogleFonts.rajdhani(textStyle: textTheme.headline5), + headline6: GoogleFonts.rajdhani(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rajdhani(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rajdhani(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rajdhani(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rajdhani(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rajdhani(textStyle: textTheme.caption), + button: GoogleFonts.rajdhani(textStyle: textTheme.button), + overline: GoogleFonts.rajdhani(textStyle: textTheme.overline), + ); + } + + /// Applies the Rakkas font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rakkas + static TextStyle rakkas({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b55368f62b7541a21f5f2e81100067268567c036b1f9f1b1435d7f856475a9f5', + 91160, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rakkas', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rakkas font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rakkas + static TextTheme rakkasTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rakkas(textStyle: textTheme.headline1), + headline2: GoogleFonts.rakkas(textStyle: textTheme.headline2), + headline3: GoogleFonts.rakkas(textStyle: textTheme.headline3), + headline4: GoogleFonts.rakkas(textStyle: textTheme.headline4), + headline5: GoogleFonts.rakkas(textStyle: textTheme.headline5), + headline6: GoogleFonts.rakkas(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rakkas(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rakkas(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rakkas(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rakkas(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rakkas(textStyle: textTheme.caption), + button: GoogleFonts.rakkas(textStyle: textTheme.button), + overline: GoogleFonts.rakkas(textStyle: textTheme.overline), + ); + } + + /// Applies the Raleway font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Raleway + static TextStyle raleway({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8df4e8d960459bd5865f3570b57e6df699c766519716eef5e7875dfc55f60f8', + 132996, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9593117176336e51cd9d5e6beece2916b11b6dd91127af0ec0e8c61360e1825d', + 105072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9fd54bfbbfe5b0f9225c616bfaf9b554e22453bccec74ff721bfa2e156349515', + 133284, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '020054507630a95da95e3be3a49fc214dbcfaf24390608c7a2b3d7f50f92d5d1', + 104972, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7404c4efdcd985236d209c5c0c5e33de959f635b2c6e360941ba22f8753d88dc', + 133000, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '66dc7bf66966029a73a06e1220a824348a0d1fced869b33b94384866a907b404', + 104376, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1aec65f5e5dca3ec9f8719936af31f54336bb5d99f25bf343ff25e009d5e569d', + 132488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7f67d86f99756ac80abbf4a03a41535ed9d8b077f56460fb30a9cd45ca561a22', + 103996, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4c263e938d69d7fcfb458613f3f273780c02bda6d38090fc8cb2244c06d0b0a3', + 133172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f794d63e5851c970d1f8527131022b8779e7f1aa8b8a974dcd0fdb49cd74270a', + 104476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '626bb691bbecebb8a239831c605068f546cdb97ae010463f2da45417e1741d82', + 131884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2884ba45cbb9cb0d03e03d9ff7ddaa586469062b6a0c7d9eedce5c300a8874b7', + 103200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0d65094ca3a50e3e3078a2e46a4229f4552983b5f75ca1375acc7e5846dc40fb', + 131004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0d7f50973be9d011396bc034d6db727bd7c8bd04c394b691aae038666b286658', + 102236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8051619be163d93f0ff326ee63a4aed4a38042fb23c4b565f5e87408bb6948f5', + 130004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7da482be71166cee8c0006906b0e930f45a5c8d6e5324b479edde0024dee23bd', + 101848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5302665d52f11188ff3c3008199ce8ca17835eb68c7c7bbbff6175e39879178a', + 131992, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8a5faa87c4f12461b775bf2c6693db562a932328b199affc9c16ea56206f534d', + 101876, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Raleway', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Raleway font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Raleway + static TextTheme ralewayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.raleway(textStyle: textTheme.headline1), + headline2: GoogleFonts.raleway(textStyle: textTheme.headline2), + headline3: GoogleFonts.raleway(textStyle: textTheme.headline3), + headline4: GoogleFonts.raleway(textStyle: textTheme.headline4), + headline5: GoogleFonts.raleway(textStyle: textTheme.headline5), + headline6: GoogleFonts.raleway(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.raleway(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.raleway(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.raleway(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.raleway(textStyle: textTheme.bodyText2), + caption: GoogleFonts.raleway(textStyle: textTheme.caption), + button: GoogleFonts.raleway(textStyle: textTheme.button), + overline: GoogleFonts.raleway(textStyle: textTheme.overline), + ); + } + + /// Applies the Raleway Dots font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Raleway+Dots + static TextStyle ralewayDots({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4b4b8ff2afb81e87d73fd84bb88f05e768029ed7d4f839078f82d515111ba83b', + 254512, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RalewayDots', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Raleway Dots font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Raleway+Dots + static TextTheme ralewayDotsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ralewayDots(textStyle: textTheme.headline1), + headline2: GoogleFonts.ralewayDots(textStyle: textTheme.headline2), + headline3: GoogleFonts.ralewayDots(textStyle: textTheme.headline3), + headline4: GoogleFonts.ralewayDots(textStyle: textTheme.headline4), + headline5: GoogleFonts.ralewayDots(textStyle: textTheme.headline5), + headline6: GoogleFonts.ralewayDots(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ralewayDots(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ralewayDots(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ralewayDots(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ralewayDots(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ralewayDots(textStyle: textTheme.caption), + button: GoogleFonts.ralewayDots(textStyle: textTheme.button), + overline: GoogleFonts.ralewayDots(textStyle: textTheme.overline), + ); + } + + /// Applies the Ramabhadra font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ramabhadra + static TextStyle ramabhadra({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f8ceda8c345cda5342d5ed25537f3c2a16bf4548f447746c5d7553cff470362c', + 329608, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ramabhadra', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ramabhadra font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ramabhadra + static TextTheme ramabhadraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ramabhadra(textStyle: textTheme.headline1), + headline2: GoogleFonts.ramabhadra(textStyle: textTheme.headline2), + headline3: GoogleFonts.ramabhadra(textStyle: textTheme.headline3), + headline4: GoogleFonts.ramabhadra(textStyle: textTheme.headline4), + headline5: GoogleFonts.ramabhadra(textStyle: textTheme.headline5), + headline6: GoogleFonts.ramabhadra(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ramabhadra(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ramabhadra(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ramabhadra(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ramabhadra(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ramabhadra(textStyle: textTheme.caption), + button: GoogleFonts.ramabhadra(textStyle: textTheme.button), + overline: GoogleFonts.ramabhadra(textStyle: textTheme.overline), + ); + } + + /// Applies the Ramaraja font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ramaraja + static TextStyle ramaraja({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2d2ad7c6159f41c62bfca6dcad8df09173bd8915c107915bc3f035cedc1d00a6', + 496892, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ramaraja', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ramaraja font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ramaraja + static TextTheme ramarajaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ramaraja(textStyle: textTheme.headline1), + headline2: GoogleFonts.ramaraja(textStyle: textTheme.headline2), + headline3: GoogleFonts.ramaraja(textStyle: textTheme.headline3), + headline4: GoogleFonts.ramaraja(textStyle: textTheme.headline4), + headline5: GoogleFonts.ramaraja(textStyle: textTheme.headline5), + headline6: GoogleFonts.ramaraja(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ramaraja(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ramaraja(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ramaraja(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ramaraja(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ramaraja(textStyle: textTheme.caption), + button: GoogleFonts.ramaraja(textStyle: textTheme.button), + overline: GoogleFonts.ramaraja(textStyle: textTheme.overline), + ); + } + + /// Applies the Rambla font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rambla + static TextStyle rambla({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8cc56fcd2e3777d5c3699b8db651965ee39a057e20813adb1a07b181a8511e65', + 34284, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6486467dd0269443e3b474df8d13f8a02e42791674f0fcf5964b9ee8419cdbae', + 37096, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3c855f5e3c26200aeb6e55a7d0bbf80b16fceb67ab65b97d50a788c68d315379', + 34640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f20b77570105aff68e4179538c4243221228d9f13bc6eb988847fdf6800b97b4', + 37324, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rambla', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rambla font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rambla + static TextTheme ramblaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rambla(textStyle: textTheme.headline1), + headline2: GoogleFonts.rambla(textStyle: textTheme.headline2), + headline3: GoogleFonts.rambla(textStyle: textTheme.headline3), + headline4: GoogleFonts.rambla(textStyle: textTheme.headline4), + headline5: GoogleFonts.rambla(textStyle: textTheme.headline5), + headline6: GoogleFonts.rambla(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rambla(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rambla(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rambla(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rambla(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rambla(textStyle: textTheme.caption), + button: GoogleFonts.rambla(textStyle: textTheme.button), + overline: GoogleFonts.rambla(textStyle: textTheme.overline), + ); + } + + /// Applies the Rammetto One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rammetto+One + static TextStyle rammettoOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c98688de086da1f823bad61e527562aacacdd41a5cf8072e7c7d6c4fe3718dc6', + 30372, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RammettoOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rammetto One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rammetto+One + static TextTheme rammettoOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rammettoOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.rammettoOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.rammettoOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.rammettoOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.rammettoOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.rammettoOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rammettoOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rammettoOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rammettoOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rammettoOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rammettoOne(textStyle: textTheme.caption), + button: GoogleFonts.rammettoOne(textStyle: textTheme.button), + overline: GoogleFonts.rammettoOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Ranchers font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ranchers + static TextStyle ranchers({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ee03833b1756509c106b58261df85478f7bd82ff2fd7ca6b4d5890de33cae655', + 121636, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ranchers', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ranchers font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ranchers + static TextTheme ranchersTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ranchers(textStyle: textTheme.headline1), + headline2: GoogleFonts.ranchers(textStyle: textTheme.headline2), + headline3: GoogleFonts.ranchers(textStyle: textTheme.headline3), + headline4: GoogleFonts.ranchers(textStyle: textTheme.headline4), + headline5: GoogleFonts.ranchers(textStyle: textTheme.headline5), + headline6: GoogleFonts.ranchers(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ranchers(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ranchers(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ranchers(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ranchers(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ranchers(textStyle: textTheme.caption), + button: GoogleFonts.ranchers(textStyle: textTheme.button), + overline: GoogleFonts.ranchers(textStyle: textTheme.overline), + ); + } + + /// Applies the Rancho font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rancho + static TextStyle rancho({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2691ae7a785afc3443c02c1383179f3e510bbcbe3015a78c6b04b9a2ce719ea2', + 44424, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rancho', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rancho font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rancho + static TextTheme ranchoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rancho(textStyle: textTheme.headline1), + headline2: GoogleFonts.rancho(textStyle: textTheme.headline2), + headline3: GoogleFonts.rancho(textStyle: textTheme.headline3), + headline4: GoogleFonts.rancho(textStyle: textTheme.headline4), + headline5: GoogleFonts.rancho(textStyle: textTheme.headline5), + headline6: GoogleFonts.rancho(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rancho(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rancho(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rancho(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rancho(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rancho(textStyle: textTheme.caption), + button: GoogleFonts.rancho(textStyle: textTheme.button), + overline: GoogleFonts.rancho(textStyle: textTheme.overline), + ); + } + + /// Applies the Ranga font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ranga + static TextStyle ranga({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e51a6898e34d12bd9b9057002e645f176d30f5e821bfaa1ccc4e56294af7099a', + 119128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c5c763628e805a2af3c9deb68abd0b70227a98911f7ba56f4f8c2a3e8c286b96', + 127288, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ranga', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ranga font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ranga + static TextTheme rangaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ranga(textStyle: textTheme.headline1), + headline2: GoogleFonts.ranga(textStyle: textTheme.headline2), + headline3: GoogleFonts.ranga(textStyle: textTheme.headline3), + headline4: GoogleFonts.ranga(textStyle: textTheme.headline4), + headline5: GoogleFonts.ranga(textStyle: textTheme.headline5), + headline6: GoogleFonts.ranga(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ranga(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ranga(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ranga(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ranga(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ranga(textStyle: textTheme.caption), + button: GoogleFonts.ranga(textStyle: textTheme.button), + overline: GoogleFonts.ranga(textStyle: textTheme.overline), + ); + } + + /// Applies the Rasa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rasa + static TextStyle rasa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6d1458902052379a4c442fe3c08dfb90a878e6187abc480b52afc11943431dd3', + 192536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd5a933545a7d1e9a3ce0493c853f75c27dc067506d4c32398c0f724f726435cb', + 194280, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f5a6e10ca22dc5d39cb49a70330bb3f3b7dc5361feb0b59693284816acf3dc6d', + 193900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0ce2031b3cd5dd01a2d4c96225c44fa6813df124cbf2f4f078c859e4e0abdd6d', + 194140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f756b8a84bfdccc709dbc00ba23c8852f077e23210d148b4a158e4feb7c1901e', + 193644, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rasa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rasa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rasa + static TextTheme rasaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rasa(textStyle: textTheme.headline1), + headline2: GoogleFonts.rasa(textStyle: textTheme.headline2), + headline3: GoogleFonts.rasa(textStyle: textTheme.headline3), + headline4: GoogleFonts.rasa(textStyle: textTheme.headline4), + headline5: GoogleFonts.rasa(textStyle: textTheme.headline5), + headline6: GoogleFonts.rasa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rasa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rasa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rasa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rasa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rasa(textStyle: textTheme.caption), + button: GoogleFonts.rasa(textStyle: textTheme.button), + overline: GoogleFonts.rasa(textStyle: textTheme.overline), + ); + } + + /// Applies the Rationale font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rationale + static TextStyle rationale({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'be5538f847ecbac23916ea02bdabf914bbcb6d6d35c8ad538b227d6ab3efffee', + 44712, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rationale', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rationale font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rationale + static TextTheme rationaleTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rationale(textStyle: textTheme.headline1), + headline2: GoogleFonts.rationale(textStyle: textTheme.headline2), + headline3: GoogleFonts.rationale(textStyle: textTheme.headline3), + headline4: GoogleFonts.rationale(textStyle: textTheme.headline4), + headline5: GoogleFonts.rationale(textStyle: textTheme.headline5), + headline6: GoogleFonts.rationale(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rationale(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rationale(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rationale(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rationale(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rationale(textStyle: textTheme.caption), + button: GoogleFonts.rationale(textStyle: textTheme.button), + overline: GoogleFonts.rationale(textStyle: textTheme.overline), + ); + } + + /// Applies the Ravi Prakash font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ravi+Prakash + static TextStyle raviPrakash({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e1c97910a94c8297b0463611bff91a4178d5e555acd6915846dc0d34b7da5221', + 231772, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RaviPrakash', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ravi Prakash font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ravi+Prakash + static TextTheme raviPrakashTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.raviPrakash(textStyle: textTheme.headline1), + headline2: GoogleFonts.raviPrakash(textStyle: textTheme.headline2), + headline3: GoogleFonts.raviPrakash(textStyle: textTheme.headline3), + headline4: GoogleFonts.raviPrakash(textStyle: textTheme.headline4), + headline5: GoogleFonts.raviPrakash(textStyle: textTheme.headline5), + headline6: GoogleFonts.raviPrakash(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.raviPrakash(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.raviPrakash(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.raviPrakash(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.raviPrakash(textStyle: textTheme.bodyText2), + caption: GoogleFonts.raviPrakash(textStyle: textTheme.caption), + button: GoogleFonts.raviPrakash(textStyle: textTheme.button), + overline: GoogleFonts.raviPrakash(textStyle: textTheme.overline), + ); + } + + /// Applies the Recursive font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Recursive + static TextStyle recursive({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c0847d0ce19141b62404037e0e538fa4188b661e8f713e7e6fbd0e43b5659d2b', + 109496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8ddab815f7bb04362f167840c2e94628e2a2353e7c2d01ac761e1b66731423c0', + 109588, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a14d6b88d6c6a0a0cb04cada3bcc337d4ceb2b27aa3b619ca1b5ef2628f5277', + 109576, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '77d39252fcfe666b638bbd040852805d82047fb2fc9748fdc4f9edd3ebb81854', + 109616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd091e69dc6d59217184d52e679acf2a566d8d83717fa05f0d13942f64051c85d', + 109516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7212a09cda61d996e3c5d2c4b08fd097d1fd0ac10597b533197f251ad4f3085a', + 109544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a704e1c9c987cd117cb0878ca3f9895235fd16eace4859f428b8da348516211', + 109628, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Recursive', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Recursive font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Recursive + static TextTheme recursiveTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.recursive(textStyle: textTheme.headline1), + headline2: GoogleFonts.recursive(textStyle: textTheme.headline2), + headline3: GoogleFonts.recursive(textStyle: textTheme.headline3), + headline4: GoogleFonts.recursive(textStyle: textTheme.headline4), + headline5: GoogleFonts.recursive(textStyle: textTheme.headline5), + headline6: GoogleFonts.recursive(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.recursive(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.recursive(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.recursive(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.recursive(textStyle: textTheme.bodyText2), + caption: GoogleFonts.recursive(textStyle: textTheme.caption), + button: GoogleFonts.recursive(textStyle: textTheme.button), + overline: GoogleFonts.recursive(textStyle: textTheme.overline), + ); + } + + /// Applies the Red Hat Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Red+Hat+Display + static TextStyle redHatDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '675f7abfa369dc6992d9baf79751a6887711f613b7b4783502dbc42d135ad755', + 36544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2e8b90fd9cbce501f652d35b743083be439853e2ee98669ec4885ca518c7fb30', + 36960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '93f27cfcf7823481e7194e5feb84bb5724ae4d872ae2d45469fe2732eb1ffbba', + 36388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'fde77be04a3ff0a0162557ffb4a34ea35bfc2b6d6221ea52f4784ee861d23115', + 37004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7897d54780c1af5e3be81c46c850d6cf5cab921a6d3b9b6f01bc53832a8fba74', + 36436, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7d663aae94b1599f6acc3c66f68bd11753c1f0065a6dfd808229663939991c88', + 36884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f3fa64617097c3954eacdd21e4502eb79d00053e29ca37b5e0047cf0e3d49aaa', + 36364, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ea4b150dc2f0ba9a550b1a93217bc8dd275a6534aca092096abff10a4751dab1', + 36832, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RedHatDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Red Hat Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Red+Hat+Display + static TextTheme redHatDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.redHatDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.redHatDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.redHatDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.redHatDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.redHatDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.redHatDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.redHatDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.redHatDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.redHatDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.redHatDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.redHatDisplay(textStyle: textTheme.caption), + button: GoogleFonts.redHatDisplay(textStyle: textTheme.button), + overline: GoogleFonts.redHatDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Red Hat Text font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Red+Hat+Text + static TextStyle redHatText({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0d9ffb6cd7ed3ba3a171dc3f14fc4f0ee80d0bcc276de998f2d1856e2e4c46bc', + 36580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c25033ec3d2ae9b4a79da58b3a841070303dba586f0797ab0d60afcd8d5e6708', + 37152, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8e6613e0c2b79e3e7adfce20e339e92aa65b3b932d8daed7102603d8a7e05352', + 36568, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '492f537d5c3ba80c637f66cd970d7ab47e7cdf85b3daa0783ae5b96ea8a95770', + 37092, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0ed0cf791ad1be4c2b900b22803db61988f37e96e044682319e45bce7a859b91', + 36524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'be2de719ea5a677cf21fed0bf32ac84f816db39db4d91e04de07bd8bfcf2d8d7', + 36912, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RedHatText', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Red Hat Text font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Red+Hat+Text + static TextTheme redHatTextTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.redHatText(textStyle: textTheme.headline1), + headline2: GoogleFonts.redHatText(textStyle: textTheme.headline2), + headline3: GoogleFonts.redHatText(textStyle: textTheme.headline3), + headline4: GoogleFonts.redHatText(textStyle: textTheme.headline4), + headline5: GoogleFonts.redHatText(textStyle: textTheme.headline5), + headline6: GoogleFonts.redHatText(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.redHatText(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.redHatText(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.redHatText(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.redHatText(textStyle: textTheme.bodyText2), + caption: GoogleFonts.redHatText(textStyle: textTheme.caption), + button: GoogleFonts.redHatText(textStyle: textTheme.button), + overline: GoogleFonts.redHatText(textStyle: textTheme.overline), + ); + } + + /// Applies the Red Rose font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Red+Rose + static TextStyle redRose({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c2043da6d63c0299d2d8ccc4aec25f1f3a80e1db46d3736df80c20d134f760db', + 57608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1540a59bbedb077165aecc6d9b229fec9477b8a2274795dca54587304d9d525c', + 57568, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ad118319928f083841c48d97b66f1df3e2c733f9278f06ca9d1665c9155b1fc4', + 57552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '11c8e1caee1164b286a7c7899bd6c0cc8947757b96aa7752783d78b7f0a7dbc1', + 57560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c8dde6b08d14342f87332f1f35153250826cf1fae75cbea3d51fe11137dcf822', + 57524, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RedRose', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Red Rose font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Red+Rose + static TextTheme redRoseTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.redRose(textStyle: textTheme.headline1), + headline2: GoogleFonts.redRose(textStyle: textTheme.headline2), + headline3: GoogleFonts.redRose(textStyle: textTheme.headline3), + headline4: GoogleFonts.redRose(textStyle: textTheme.headline4), + headline5: GoogleFonts.redRose(textStyle: textTheme.headline5), + headline6: GoogleFonts.redRose(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.redRose(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.redRose(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.redRose(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.redRose(textStyle: textTheme.bodyText2), + caption: GoogleFonts.redRose(textStyle: textTheme.caption), + button: GoogleFonts.redRose(textStyle: textTheme.button), + overline: GoogleFonts.redRose(textStyle: textTheme.overline), + ); + } + + /// Applies the Redressed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Redressed + static TextStyle redressed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b7da182df7a86a14b448d200c3efd866dca0885111c28fce6449cf8aef103e77', + 78804, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Redressed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Redressed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Redressed + static TextTheme redressedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.redressed(textStyle: textTheme.headline1), + headline2: GoogleFonts.redressed(textStyle: textTheme.headline2), + headline3: GoogleFonts.redressed(textStyle: textTheme.headline3), + headline4: GoogleFonts.redressed(textStyle: textTheme.headline4), + headline5: GoogleFonts.redressed(textStyle: textTheme.headline5), + headline6: GoogleFonts.redressed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.redressed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.redressed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.redressed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.redressed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.redressed(textStyle: textTheme.caption), + button: GoogleFonts.redressed(textStyle: textTheme.button), + overline: GoogleFonts.redressed(textStyle: textTheme.overline), + ); + } + + /// Applies the Reem Kufi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Reem+Kufi + static TextStyle reemKufi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ea139970598b2fe720c5ddab2a0e2483460759bc626931104aa1adb9c4ef6b9a', + 58312, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ReemKufi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Reem Kufi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Reem+Kufi + static TextTheme reemKufiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.reemKufi(textStyle: textTheme.headline1), + headline2: GoogleFonts.reemKufi(textStyle: textTheme.headline2), + headline3: GoogleFonts.reemKufi(textStyle: textTheme.headline3), + headline4: GoogleFonts.reemKufi(textStyle: textTheme.headline4), + headline5: GoogleFonts.reemKufi(textStyle: textTheme.headline5), + headline6: GoogleFonts.reemKufi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.reemKufi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.reemKufi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.reemKufi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.reemKufi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.reemKufi(textStyle: textTheme.caption), + button: GoogleFonts.reemKufi(textStyle: textTheme.button), + overline: GoogleFonts.reemKufi(textStyle: textTheme.overline), + ); + } + + /// Applies the Reenie Beanie font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Reenie+Beanie + static TextStyle reenieBeanie({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3bc036be5570dcb23bf8f01f888f56bc55c5e3606875bdd2bb8afd3ebb48d2a6', + 88956, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ReenieBeanie', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Reenie Beanie font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Reenie+Beanie + static TextTheme reenieBeanieTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.reenieBeanie(textStyle: textTheme.headline1), + headline2: GoogleFonts.reenieBeanie(textStyle: textTheme.headline2), + headline3: GoogleFonts.reenieBeanie(textStyle: textTheme.headline3), + headline4: GoogleFonts.reenieBeanie(textStyle: textTheme.headline4), + headline5: GoogleFonts.reenieBeanie(textStyle: textTheme.headline5), + headline6: GoogleFonts.reenieBeanie(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.reenieBeanie(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.reenieBeanie(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.reenieBeanie(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.reenieBeanie(textStyle: textTheme.bodyText2), + caption: GoogleFonts.reenieBeanie(textStyle: textTheme.caption), + button: GoogleFonts.reenieBeanie(textStyle: textTheme.button), + overline: GoogleFonts.reenieBeanie(textStyle: textTheme.overline), + ); + } + + /// Applies the Revalia font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Revalia + static TextStyle revalia({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b093f6aebb81a6ee15d476875815645a7d5544b359370f2565d91a77dfa8d3e6', + 34108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Revalia', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Revalia font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Revalia + static TextTheme revaliaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.revalia(textStyle: textTheme.headline1), + headline2: GoogleFonts.revalia(textStyle: textTheme.headline2), + headline3: GoogleFonts.revalia(textStyle: textTheme.headline3), + headline4: GoogleFonts.revalia(textStyle: textTheme.headline4), + headline5: GoogleFonts.revalia(textStyle: textTheme.headline5), + headline6: GoogleFonts.revalia(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.revalia(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.revalia(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.revalia(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.revalia(textStyle: textTheme.bodyText2), + caption: GoogleFonts.revalia(textStyle: textTheme.caption), + button: GoogleFonts.revalia(textStyle: textTheme.button), + overline: GoogleFonts.revalia(textStyle: textTheme.overline), + ); + } + + /// Applies the Rhodium Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rhodium+Libre + static TextStyle rhodiumLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9c5b10db8b1e6bcf720d3a76cdf51a5dc63ec9f1a7115e777e07921fa2b738e6', + 154452, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RhodiumLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rhodium Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rhodium+Libre + static TextTheme rhodiumLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rhodiumLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.rhodiumLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.rhodiumLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.rhodiumLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.rhodiumLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.rhodiumLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rhodiumLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rhodiumLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rhodiumLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rhodiumLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rhodiumLibre(textStyle: textTheme.caption), + button: GoogleFonts.rhodiumLibre(textStyle: textTheme.button), + overline: GoogleFonts.rhodiumLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Ribeye font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ribeye + static TextStyle ribeye({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9fe858f86a4e9a56b2a520c8f615ee7dd682f4a2fed5b8033405258755e1105e', + 78076, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ribeye', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ribeye font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ribeye + static TextTheme ribeyeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ribeye(textStyle: textTheme.headline1), + headline2: GoogleFonts.ribeye(textStyle: textTheme.headline2), + headline3: GoogleFonts.ribeye(textStyle: textTheme.headline3), + headline4: GoogleFonts.ribeye(textStyle: textTheme.headline4), + headline5: GoogleFonts.ribeye(textStyle: textTheme.headline5), + headline6: GoogleFonts.ribeye(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ribeye(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ribeye(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ribeye(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ribeye(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ribeye(textStyle: textTheme.caption), + button: GoogleFonts.ribeye(textStyle: textTheme.button), + overline: GoogleFonts.ribeye(textStyle: textTheme.overline), + ); + } + + /// Applies the Ribeye Marrow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ribeye+Marrow + static TextStyle ribeyeMarrow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c246f9f2e382d8da82319762b401df8a1426fa767b74d168f0d1abca33fdd43d', + 84848, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RibeyeMarrow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ribeye Marrow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ribeye+Marrow + static TextTheme ribeyeMarrowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ribeyeMarrow(textStyle: textTheme.headline1), + headline2: GoogleFonts.ribeyeMarrow(textStyle: textTheme.headline2), + headline3: GoogleFonts.ribeyeMarrow(textStyle: textTheme.headline3), + headline4: GoogleFonts.ribeyeMarrow(textStyle: textTheme.headline4), + headline5: GoogleFonts.ribeyeMarrow(textStyle: textTheme.headline5), + headline6: GoogleFonts.ribeyeMarrow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ribeyeMarrow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ribeyeMarrow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ribeyeMarrow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ribeyeMarrow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ribeyeMarrow(textStyle: textTheme.caption), + button: GoogleFonts.ribeyeMarrow(textStyle: textTheme.button), + overline: GoogleFonts.ribeyeMarrow(textStyle: textTheme.overline), + ); + } + + /// Applies the Righteous font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Righteous + static TextStyle righteous({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b40fb221f7d3d9f9d2681d60785245f09112b91485a2380235241e647b852428', + 43104, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Righteous', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Righteous font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Righteous + static TextTheme righteousTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.righteous(textStyle: textTheme.headline1), + headline2: GoogleFonts.righteous(textStyle: textTheme.headline2), + headline3: GoogleFonts.righteous(textStyle: textTheme.headline3), + headline4: GoogleFonts.righteous(textStyle: textTheme.headline4), + headline5: GoogleFonts.righteous(textStyle: textTheme.headline5), + headline6: GoogleFonts.righteous(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.righteous(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.righteous(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.righteous(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.righteous(textStyle: textTheme.bodyText2), + caption: GoogleFonts.righteous(textStyle: textTheme.caption), + button: GoogleFonts.righteous(textStyle: textTheme.button), + overline: GoogleFonts.righteous(textStyle: textTheme.overline), + ); + } + + /// Applies the Risque font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Risque + static TextStyle risque({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5f8b847245100d0b265af4b51f5155b82e072ba6124a272762a8868071c2e9a8', + 58976, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Risque', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Risque font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Risque + static TextTheme risqueTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.risque(textStyle: textTheme.headline1), + headline2: GoogleFonts.risque(textStyle: textTheme.headline2), + headline3: GoogleFonts.risque(textStyle: textTheme.headline3), + headline4: GoogleFonts.risque(textStyle: textTheme.headline4), + headline5: GoogleFonts.risque(textStyle: textTheme.headline5), + headline6: GoogleFonts.risque(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.risque(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.risque(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.risque(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.risque(textStyle: textTheme.bodyText2), + caption: GoogleFonts.risque(textStyle: textTheme.caption), + button: GoogleFonts.risque(textStyle: textTheme.button), + overline: GoogleFonts.risque(textStyle: textTheme.overline), + ); + } + + /// Applies the Roboto font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Roboto + static TextStyle roboto({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e735762739638d19335103f8e7a343545560f4b2265fd35a4f0f516f512a7760', + 109484, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'aece4c53901fff188a2cb1aab1024ea53b459e2181d47d9b3700c13d33ade89e', + 116036, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d1bd6e2cc14a33517018f1bbfdc878cb18e7894f39fc7c36436ae18440621e7', + 108652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0810007c837dfd034071c166e5f3ed111b0180b2f6af17a5c14e006a8e05784f', + 115656, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '030868028bda24a27a45e0be44c8ae15544762b94f80da746c8b8a1c05f8e952', + 107800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6a79346603274d80f27fb4de32a0e7a60f62c53c8069df2750e79b8f10e30649', + 114644, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '388ace661d10e5756d4de58035d6687cf35c0b11c8185b098468741ca2e8a6d4', + 109344, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '257c7750d0c1570dc2324571f2998d43e18649848595361a6b136bb0d3d2efb2', + 116372, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba3855457bdc103784c39219f0ce666683084df07dbd7eb7d8c35a40cf8f1c8b', + 109712, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8c9936227e9fe936594819bbf4aa9a26d9b044f0b440800a4ade3e3e749f54aa', + 116424, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a1ba74d13db1b16771b1d8e705e4c9282ef1d09492783304ebc025adb6ba1914', + 109832, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a4c423dcbda812fa36cb0325f3aad0fd9847e8a5b0a26f31094db0666e721c8c', + 116668, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Roboto', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Roboto font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Roboto + static TextTheme robotoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.roboto(textStyle: textTheme.headline1), + headline2: GoogleFonts.roboto(textStyle: textTheme.headline2), + headline3: GoogleFonts.roboto(textStyle: textTheme.headline3), + headline4: GoogleFonts.roboto(textStyle: textTheme.headline4), + headline5: GoogleFonts.roboto(textStyle: textTheme.headline5), + headline6: GoogleFonts.roboto(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.roboto(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.roboto(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.roboto(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.roboto(textStyle: textTheme.bodyText2), + caption: GoogleFonts.roboto(textStyle: textTheme.caption), + button: GoogleFonts.roboto(textStyle: textTheme.button), + overline: GoogleFonts.roboto(textStyle: textTheme.overline), + ); + } + + /// Applies the Roboto Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Roboto+Condensed + static TextStyle robotoCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '779b7e4fc31ca5d743e125a1799e9c79dc6ac4ec6e87ca8668ddbe5a157114d7', + 107676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f3f74b2f03d3c52f24982b0c06b087165cebeeff210f3db18314a3cede24d9c5', + 115124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a0e62c76df9173512c94484b3994d83d2b4648dadb8ea6104f3656a3b60f25bc', + 106992, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '271bd0834c4b4fdb5c9c023bbb4067bb29b29e248cd45f845be792f649d30934', + 114324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '75a8116fe33c85a153cc824951286cc88ea5c5278e72f1ad56bf94693e9302e7', + 108832, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6aeda8628b19ddf4671e2e3710998ea138a2cd845f54640bb82f89acad0bbaf6', + 115668, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RobotoCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Roboto Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Roboto+Condensed + static TextTheme robotoCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.robotoCondensed(textStyle: textTheme.headline1), + headline2: GoogleFonts.robotoCondensed(textStyle: textTheme.headline2), + headline3: GoogleFonts.robotoCondensed(textStyle: textTheme.headline3), + headline4: GoogleFonts.robotoCondensed(textStyle: textTheme.headline4), + headline5: GoogleFonts.robotoCondensed(textStyle: textTheme.headline5), + headline6: GoogleFonts.robotoCondensed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.robotoCondensed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.robotoCondensed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.robotoCondensed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.robotoCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.robotoCondensed(textStyle: textTheme.caption), + button: GoogleFonts.robotoCondensed(textStyle: textTheme.button), + overline: GoogleFonts.robotoCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Roboto Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Roboto+Mono + static TextStyle robotoMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e54b0e2606a8e454e92c100a791d8b71811e052d42fe4b32896466b8f0be270e', + 85128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3eb07be624d5ec7a80bcb5820f19fe80008142212ee07cfa2bf9a5b70f94a6a2', + 87936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1c9d3d466aab107a76ff737ac20edaf327476dbcc6c6dbd77a00094bc79727bf', + 82784, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0f72866d63d772ac722b847dfc2d8ae72d00e74b69f1b95374f6f71677a4cb05', + 87832, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e3284818a33743fb9474240557d229c111ec2b584d14913e5d32af7b74487458', + 80684, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3d8daba697d824c67c2e385af80a546763d80262785e6adb2e681c714782fb22', + 86816, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c451bd3c919883e57c526d2c2bfa3e98dfd63411a8b872828891908ba78ad63b', + 80120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e78535fb7ee0b0f96d74454e5c73e28c62d48423449a97f0d749ec7c920fa921', + 86724, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '107b5dac259223182470928048382c0cef0d4b668d0775ac03c0a44c847ea2c7', + 80304, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6551cac967c818689406cd0ca591d8a251a88cbff6790b5ea3c0e3aa2f541668', + 86788, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RobotoMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Roboto Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Roboto+Mono + static TextTheme robotoMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.robotoMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.robotoMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.robotoMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.robotoMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.robotoMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.robotoMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.robotoMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.robotoMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.robotoMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.robotoMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.robotoMono(textStyle: textTheme.caption), + button: GoogleFonts.robotoMono(textStyle: textTheme.button), + overline: GoogleFonts.robotoMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Roboto Slab font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Roboto+Slab + static TextStyle robotoSlab({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '39d17021e49dab28b629d9c337f6d659da0a8b37bbfb8ae5ccfe9ee8f8d16878', + 109020, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5b6bad2cf6f07f140e117c46893165483ad9dd034a75a4a090f1d9825992210e', + 109636, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '89c16ab4d99ac752daea2ecf31af3aae669305b909e558170bafd48dc9b8b9aa', + 107180, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e87e906df2d8d66b24a131bef23415760d6d2afee657275eb91f1a3a5e5dcb5e', + 108520, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RobotoSlab', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Roboto Slab font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Roboto+Slab + static TextTheme robotoSlabTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.robotoSlab(textStyle: textTheme.headline1), + headline2: GoogleFonts.robotoSlab(textStyle: textTheme.headline2), + headline3: GoogleFonts.robotoSlab(textStyle: textTheme.headline3), + headline4: GoogleFonts.robotoSlab(textStyle: textTheme.headline4), + headline5: GoogleFonts.robotoSlab(textStyle: textTheme.headline5), + headline6: GoogleFonts.robotoSlab(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.robotoSlab(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.robotoSlab(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.robotoSlab(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.robotoSlab(textStyle: textTheme.bodyText2), + caption: GoogleFonts.robotoSlab(textStyle: textTheme.caption), + button: GoogleFonts.robotoSlab(textStyle: textTheme.button), + overline: GoogleFonts.robotoSlab(textStyle: textTheme.overline), + ); + } + + /// Applies the Rochester font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rochester + static TextStyle rochester({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3497dd76e37f779c2ea2d2d0ae96b0cbf2170cec9ad27c806d0b3b31c859ee13', + 37824, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rochester', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rochester font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rochester + static TextTheme rochesterTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rochester(textStyle: textTheme.headline1), + headline2: GoogleFonts.rochester(textStyle: textTheme.headline2), + headline3: GoogleFonts.rochester(textStyle: textTheme.headline3), + headline4: GoogleFonts.rochester(textStyle: textTheme.headline4), + headline5: GoogleFonts.rochester(textStyle: textTheme.headline5), + headline6: GoogleFonts.rochester(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rochester(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rochester(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rochester(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rochester(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rochester(textStyle: textTheme.caption), + button: GoogleFonts.rochester(textStyle: textTheme.button), + overline: GoogleFonts.rochester(textStyle: textTheme.overline), + ); + } + + /// Applies the Rock Salt font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rock+Salt + static TextStyle rockSalt({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f806681f8229dcdbd4eecfbadbbba02c5db0e98796d6996917c01a006376910f', + 117412, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RockSalt', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rock Salt font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rock+Salt + static TextTheme rockSaltTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rockSalt(textStyle: textTheme.headline1), + headline2: GoogleFonts.rockSalt(textStyle: textTheme.headline2), + headline3: GoogleFonts.rockSalt(textStyle: textTheme.headline3), + headline4: GoogleFonts.rockSalt(textStyle: textTheme.headline4), + headline5: GoogleFonts.rockSalt(textStyle: textTheme.headline5), + headline6: GoogleFonts.rockSalt(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rockSalt(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rockSalt(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rockSalt(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rockSalt(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rockSalt(textStyle: textTheme.caption), + button: GoogleFonts.rockSalt(textStyle: textTheme.button), + overline: GoogleFonts.rockSalt(textStyle: textTheme.overline), + ); + } + + /// Applies the Rokkitt font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rokkitt + static TextStyle rokkitt({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9a0a1b138370aa3841a848edde26bd7045ac2a5a0f13a513b247417c3489811c', + 59248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '840d357a7d06133d859000a071917c4ea92f02d0f001f247137046392166ff1b', + 59120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '19b250411cba0e1bc39378cf1e47ecbd217b7b52e845159655611f9cce3f016f', + 58996, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd605b424de78054bd585518d8a4e136ab863ab5f3110ee43cb0745bca0f94eb3', + 59040, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c3ce457383a5f17f5736ecff7d423f0d5e1f10ba000e7a78145fef0d293439c7', + 58848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '710018ab00f1b7534021eb425d0afa5cd1ccc82a3d91a174d7f359afac93f384', + 58800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '76808b96844704a6d75bee1943315ea236557fc6fb1a239ec5fcee6f9c5fcd58', + 58648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1e99689267ca0778d003215820f88badff6b9986410c8b9d07d2c857c6e04beb', + 58464, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a8cf419d654432575866170e1d718f434f7f5cfa52673194ae8fc3d08cbefe92', + 58212, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rokkitt', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rokkitt font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rokkitt + static TextTheme rokkittTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rokkitt(textStyle: textTheme.headline1), + headline2: GoogleFonts.rokkitt(textStyle: textTheme.headline2), + headline3: GoogleFonts.rokkitt(textStyle: textTheme.headline3), + headline4: GoogleFonts.rokkitt(textStyle: textTheme.headline4), + headline5: GoogleFonts.rokkitt(textStyle: textTheme.headline5), + headline6: GoogleFonts.rokkitt(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rokkitt(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rokkitt(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rokkitt(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rokkitt(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rokkitt(textStyle: textTheme.caption), + button: GoogleFonts.rokkitt(textStyle: textTheme.button), + overline: GoogleFonts.rokkitt(textStyle: textTheme.overline), + ); + } + + /// Applies the Romanesco font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Romanesco + static TextStyle romanesco({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8d69cd23e2f9e72bfe24b40e81d3301f35d942aa11864ee86d116da929e93a27', + 52112, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Romanesco', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Romanesco font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Romanesco + static TextTheme romanescoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.romanesco(textStyle: textTheme.headline1), + headline2: GoogleFonts.romanesco(textStyle: textTheme.headline2), + headline3: GoogleFonts.romanesco(textStyle: textTheme.headline3), + headline4: GoogleFonts.romanesco(textStyle: textTheme.headline4), + headline5: GoogleFonts.romanesco(textStyle: textTheme.headline5), + headline6: GoogleFonts.romanesco(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.romanesco(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.romanesco(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.romanesco(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.romanesco(textStyle: textTheme.bodyText2), + caption: GoogleFonts.romanesco(textStyle: textTheme.caption), + button: GoogleFonts.romanesco(textStyle: textTheme.button), + overline: GoogleFonts.romanesco(textStyle: textTheme.overline), + ); + } + + /// Applies the Ropa Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ropa+Sans + static TextStyle ropaSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ded2bcc06059fc1d86ad77aedff4ca5827287da7e5d969867d190f24ce2c5916', + 39140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0fc33e982fa4003ec3947ef040bddfed3e33ad447086af587ee5ed6cc4ef4fac', + 41796, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RopaSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ropa Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ropa+Sans + static TextTheme ropaSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ropaSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.ropaSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.ropaSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.ropaSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.ropaSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.ropaSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ropaSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ropaSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ropaSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ropaSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ropaSans(textStyle: textTheme.caption), + button: GoogleFonts.ropaSans(textStyle: textTheme.button), + overline: GoogleFonts.ropaSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Rosario font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rosario + static TextStyle rosario({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dc6413573a989dcba9ee4d0b7670f9eb53c458ddefc205ef6e0bd1e1c0be395e', + 44412, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f099b91c7f453830c2471e0be3a576f1f58943f343e98b2d994a8f195364e51f', + 44488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eba2172f0e05afe4e99a14d3a265d3f334e6110105c10842f43387dc99341df6', + 25204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2fde400ab1655e1710a53bca2ab413a1504a54748fcac3b8ffea6135f4b8aabb', + 45640, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rosario', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rosario font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rosario + static TextTheme rosarioTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rosario(textStyle: textTheme.headline1), + headline2: GoogleFonts.rosario(textStyle: textTheme.headline2), + headline3: GoogleFonts.rosario(textStyle: textTheme.headline3), + headline4: GoogleFonts.rosario(textStyle: textTheme.headline4), + headline5: GoogleFonts.rosario(textStyle: textTheme.headline5), + headline6: GoogleFonts.rosario(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rosario(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rosario(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rosario(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rosario(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rosario(textStyle: textTheme.caption), + button: GoogleFonts.rosario(textStyle: textTheme.button), + overline: GoogleFonts.rosario(textStyle: textTheme.overline), + ); + } + + /// Applies the Rosarivo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rosarivo + static TextStyle rosarivo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd5878b2fc902263df1fa49b327526cf9d20d935600e9d19b05ed00453639dd2e', + 41296, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0decb12337d01f7da972a8999c759b44d150a6b4da6f78459c1fc7732df0e5ea', + 39196, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rosarivo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rosarivo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rosarivo + static TextTheme rosarivoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rosarivo(textStyle: textTheme.headline1), + headline2: GoogleFonts.rosarivo(textStyle: textTheme.headline2), + headline3: GoogleFonts.rosarivo(textStyle: textTheme.headline3), + headline4: GoogleFonts.rosarivo(textStyle: textTheme.headline4), + headline5: GoogleFonts.rosarivo(textStyle: textTheme.headline5), + headline6: GoogleFonts.rosarivo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rosarivo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rosarivo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rosarivo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rosarivo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rosarivo(textStyle: textTheme.caption), + button: GoogleFonts.rosarivo(textStyle: textTheme.button), + overline: GoogleFonts.rosarivo(textStyle: textTheme.overline), + ); + } + + /// Applies the Rouge Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rouge+Script + static TextStyle rougeScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fda390dca3b917e1245ea6c06da950ec2a4d3ee0f5b6d3c128c0049f2a6bc5bd', + 46704, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RougeScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rouge Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rouge+Script + static TextTheme rougeScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rougeScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.rougeScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.rougeScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.rougeScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.rougeScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.rougeScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rougeScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rougeScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rougeScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rougeScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rougeScript(textStyle: textTheme.caption), + button: GoogleFonts.rougeScript(textStyle: textTheme.button), + overline: GoogleFonts.rougeScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Rowdies font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rowdies + static TextStyle rowdies({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '521cbb7d3827c8c6e287e95b4ebc5245d0f619161ff0340a8cb75f6dfeb5c925', + 50616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '38dce656a3831d089bb60fd9bbc7938c4c224edc533369ed23fbbdb9c565039f', + 50336, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '935ab7e6d8f6852bf5576b7bc790b61b094794be5975bb6bdfe28c2222216217', + 50268, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rowdies', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rowdies font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rowdies + static TextTheme rowdiesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rowdies(textStyle: textTheme.headline1), + headline2: GoogleFonts.rowdies(textStyle: textTheme.headline2), + headline3: GoogleFonts.rowdies(textStyle: textTheme.headline3), + headline4: GoogleFonts.rowdies(textStyle: textTheme.headline4), + headline5: GoogleFonts.rowdies(textStyle: textTheme.headline5), + headline6: GoogleFonts.rowdies(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rowdies(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rowdies(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rowdies(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rowdies(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rowdies(textStyle: textTheme.caption), + button: GoogleFonts.rowdies(textStyle: textTheme.button), + overline: GoogleFonts.rowdies(textStyle: textTheme.overline), + ); + } + + /// Applies the Rozha One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rozha+One + static TextStyle rozhaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f19c35bdc6cdb6ad7f6251e42e4bd0c4e43757cb71b9ecd26421f1fac039d1ef', + 197988, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RozhaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rozha One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rozha+One + static TextTheme rozhaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rozhaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.rozhaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.rozhaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.rozhaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.rozhaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.rozhaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rozhaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rozhaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rozhaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rozhaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rozhaOne(textStyle: textTheme.caption), + button: GoogleFonts.rozhaOne(textStyle: textTheme.button), + overline: GoogleFonts.rozhaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Rubik font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rubik + static TextStyle rubik({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd06ee1ddd9a38ecea7c204c94d69e670e155c7e5f6b9ca5bdbbc851871397569', + 106476, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '39eb0e8cc0f4f0f949cd7ab1192004ad43fa616ab0ba09ba2f1c5e975b6ed29f', + 109452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1441b864d5f661c6ad072120b1ee340e6c799fab34f7d408ec3fbf11f41f3ea0', + 110876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1daca2e29940a75b3f1d4f3d7bb0356f63332d3013133093e3a75295dcdaf781', + 113204, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '334711470701a9df2e7c93bcc418d6d16e8844ed0bf4ae4411f588cdb913869a', + 110968, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '131d5d182158888dbccfcf0de7726b6a878bdb7eb60bbc96fb8a42561abc6b8c', + 113252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '395804d64aff5eda80de3c9e8fc2ffe482af2f6483707546f9fb8c3b14e747d9', + 110580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7dc9a621668992ae25fd33cb83bc658c0bd8e2068c92524544164c3ba79737b6', + 113060, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f660cd5e361c3f00ea913d713f53325c9248887d961ee7a130335fc796750fff', + 108720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1e373f9418d94e2ae6e4b31972520bf13c7b93e0811f8621d0ce8d72e0576c9b', + 111512, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rubik', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rubik font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rubik + static TextTheme rubikTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rubik(textStyle: textTheme.headline1), + headline2: GoogleFonts.rubik(textStyle: textTheme.headline2), + headline3: GoogleFonts.rubik(textStyle: textTheme.headline3), + headline4: GoogleFonts.rubik(textStyle: textTheme.headline4), + headline5: GoogleFonts.rubik(textStyle: textTheme.headline5), + headline6: GoogleFonts.rubik(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rubik(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rubik(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rubik(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rubik(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rubik(textStyle: textTheme.caption), + button: GoogleFonts.rubik(textStyle: textTheme.button), + overline: GoogleFonts.rubik(textStyle: textTheme.overline), + ); + } + + /// Applies the Rubik Mono One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rubik+Mono+One + static TextStyle rubikMonoOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e7309c62b1b75116a4ed60639db8643e8bf50f3f4ed2f798823b2eb3b1f2a225', + 76472, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RubikMonoOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rubik Mono One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rubik+Mono+One + static TextTheme rubikMonoOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rubikMonoOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.rubikMonoOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.rubikMonoOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.rubikMonoOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.rubikMonoOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.rubikMonoOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rubikMonoOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rubikMonoOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rubikMonoOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rubikMonoOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rubikMonoOne(textStyle: textTheme.caption), + button: GoogleFonts.rubikMonoOne(textStyle: textTheme.button), + overline: GoogleFonts.rubikMonoOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Ruda font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruda + static TextStyle ruda({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a254aa475c3646075b11d4e1a7db06d96c2f16a001e31943133c66d6bbe7558d', + 24500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'af38ec0bb3b6d599d8ad3f56b0f6f3fb81bd7dfd3234fd8f9dbaaf5029c0b2ab', + 24336, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0a25461d4ccbfb0f3a77a33f66143f8474a3eccfbee06850f5e778bf29216894', + 24284, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ruda', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ruda font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruda + static TextTheme rudaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ruda(textStyle: textTheme.headline1), + headline2: GoogleFonts.ruda(textStyle: textTheme.headline2), + headline3: GoogleFonts.ruda(textStyle: textTheme.headline3), + headline4: GoogleFonts.ruda(textStyle: textTheme.headline4), + headline5: GoogleFonts.ruda(textStyle: textTheme.headline5), + headline6: GoogleFonts.ruda(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ruda(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ruda(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ruda(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ruda(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ruda(textStyle: textTheme.caption), + button: GoogleFonts.ruda(textStyle: textTheme.button), + overline: GoogleFonts.ruda(textStyle: textTheme.overline), + ); + } + + /// Applies the Rufina font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rufina + static TextStyle rufina({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '13bca1c6fdd801a76033b1400e39b72e91e0afb66bbfe9c7949ba573a2fef8dd', + 39992, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dde1bdffc799ca56ee0f9a9f0386b734acc2abff4459d9ac91da48b589078fb6', + 40008, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rufina', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rufina font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rufina + static TextTheme rufinaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rufina(textStyle: textTheme.headline1), + headline2: GoogleFonts.rufina(textStyle: textTheme.headline2), + headline3: GoogleFonts.rufina(textStyle: textTheme.headline3), + headline4: GoogleFonts.rufina(textStyle: textTheme.headline4), + headline5: GoogleFonts.rufina(textStyle: textTheme.headline5), + headline6: GoogleFonts.rufina(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rufina(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rufina(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rufina(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rufina(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rufina(textStyle: textTheme.caption), + button: GoogleFonts.rufina(textStyle: textTheme.button), + overline: GoogleFonts.rufina(textStyle: textTheme.overline), + ); + } + + /// Applies the Ruge Boogie font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruge+Boogie + static TextStyle rugeBoogie({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91717da896d2b742035d5a0b0ba8e6e4eb616fa3040d3ba55be14c2e92b1aa8f', + 63488, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RugeBoogie', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ruge Boogie font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruge+Boogie + static TextTheme rugeBoogieTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rugeBoogie(textStyle: textTheme.headline1), + headline2: GoogleFonts.rugeBoogie(textStyle: textTheme.headline2), + headline3: GoogleFonts.rugeBoogie(textStyle: textTheme.headline3), + headline4: GoogleFonts.rugeBoogie(textStyle: textTheme.headline4), + headline5: GoogleFonts.rugeBoogie(textStyle: textTheme.headline5), + headline6: GoogleFonts.rugeBoogie(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rugeBoogie(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rugeBoogie(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rugeBoogie(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rugeBoogie(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rugeBoogie(textStyle: textTheme.caption), + button: GoogleFonts.rugeBoogie(textStyle: textTheme.button), + overline: GoogleFonts.rugeBoogie(textStyle: textTheme.overline), + ); + } + + /// Applies the Ruluko font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruluko + static TextStyle ruluko({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '518872494d9916ac67c11f0d33a4e68e70201fcd2c5edc6925985bfb1a22a9c4', + 27388, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ruluko', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ruluko font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruluko + static TextTheme rulukoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ruluko(textStyle: textTheme.headline1), + headline2: GoogleFonts.ruluko(textStyle: textTheme.headline2), + headline3: GoogleFonts.ruluko(textStyle: textTheme.headline3), + headline4: GoogleFonts.ruluko(textStyle: textTheme.headline4), + headline5: GoogleFonts.ruluko(textStyle: textTheme.headline5), + headline6: GoogleFonts.ruluko(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ruluko(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ruluko(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ruluko(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ruluko(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ruluko(textStyle: textTheme.caption), + button: GoogleFonts.ruluko(textStyle: textTheme.button), + overline: GoogleFonts.ruluko(textStyle: textTheme.overline), + ); + } + + /// Applies the Rum Raisin font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rum+Raisin + static TextStyle rumRaisin({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '15dd5f0a1c1162127387747b68fb4d16c6eebbc6ee30b8af755f7898ea9494fa', + 61396, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RumRaisin', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rum Raisin font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rum+Raisin + static TextTheme rumRaisinTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rumRaisin(textStyle: textTheme.headline1), + headline2: GoogleFonts.rumRaisin(textStyle: textTheme.headline2), + headline3: GoogleFonts.rumRaisin(textStyle: textTheme.headline3), + headline4: GoogleFonts.rumRaisin(textStyle: textTheme.headline4), + headline5: GoogleFonts.rumRaisin(textStyle: textTheme.headline5), + headline6: GoogleFonts.rumRaisin(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rumRaisin(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rumRaisin(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rumRaisin(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rumRaisin(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rumRaisin(textStyle: textTheme.caption), + button: GoogleFonts.rumRaisin(textStyle: textTheme.button), + overline: GoogleFonts.rumRaisin(textStyle: textTheme.overline), + ); + } + + /// Applies the Ruslan Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruslan+Display + static TextStyle ruslanDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ed18797941421375fffab1522b84e81a16d399abe36964f4f3278683b1dc29f', + 57264, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RuslanDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ruslan Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruslan+Display + static TextTheme ruslanDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ruslanDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.ruslanDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.ruslanDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.ruslanDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.ruslanDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.ruslanDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ruslanDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ruslanDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ruslanDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ruslanDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ruslanDisplay(textStyle: textTheme.caption), + button: GoogleFonts.ruslanDisplay(textStyle: textTheme.button), + overline: GoogleFonts.ruslanDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Russo One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Russo+One + static TextStyle russoOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '42938246c94ba396145f46606ca60fd6409d6626953609dbd587a50757963337', + 38636, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'RussoOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Russo One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Russo+One + static TextTheme russoOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.russoOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.russoOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.russoOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.russoOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.russoOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.russoOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.russoOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.russoOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.russoOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.russoOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.russoOne(textStyle: textTheme.caption), + button: GoogleFonts.russoOne(textStyle: textTheme.button), + overline: GoogleFonts.russoOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Ruthie font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruthie + static TextStyle ruthie({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '07b0c223b1890d96133629bd33f84988e27371098aac4a68a738cb05f15ce183', + 57160, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ruthie', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ruthie font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ruthie + static TextTheme ruthieTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ruthie(textStyle: textTheme.headline1), + headline2: GoogleFonts.ruthie(textStyle: textTheme.headline2), + headline3: GoogleFonts.ruthie(textStyle: textTheme.headline3), + headline4: GoogleFonts.ruthie(textStyle: textTheme.headline4), + headline5: GoogleFonts.ruthie(textStyle: textTheme.headline5), + headline6: GoogleFonts.ruthie(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ruthie(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ruthie(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ruthie(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ruthie(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ruthie(textStyle: textTheme.caption), + button: GoogleFonts.ruthie(textStyle: textTheme.button), + overline: GoogleFonts.ruthie(textStyle: textTheme.overline), + ); + } + + /// Applies the Rye font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rye + static TextStyle rye({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '925017b50d3328d30961faf597e0912d32371e48a76c36b3d89fa06e538003bc', + 86244, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Rye', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Rye font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Rye + static TextTheme ryeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.rye(textStyle: textTheme.headline1), + headline2: GoogleFonts.rye(textStyle: textTheme.headline2), + headline3: GoogleFonts.rye(textStyle: textTheme.headline3), + headline4: GoogleFonts.rye(textStyle: textTheme.headline4), + headline5: GoogleFonts.rye(textStyle: textTheme.headline5), + headline6: GoogleFonts.rye(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.rye(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.rye(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.rye(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.rye(textStyle: textTheme.bodyText2), + caption: GoogleFonts.rye(textStyle: textTheme.caption), + button: GoogleFonts.rye(textStyle: textTheme.button), + overline: GoogleFonts.rye(textStyle: textTheme.overline), + ); + } + + /// Applies the Sacramento font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sacramento + static TextStyle sacramento({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3063956ef6275e1b23cf8ab5ce022e853414c069af3d200d3cdad4924c5f6eb5', + 79268, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sacramento', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sacramento font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sacramento + static TextTheme sacramentoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sacramento(textStyle: textTheme.headline1), + headline2: GoogleFonts.sacramento(textStyle: textTheme.headline2), + headline3: GoogleFonts.sacramento(textStyle: textTheme.headline3), + headline4: GoogleFonts.sacramento(textStyle: textTheme.headline4), + headline5: GoogleFonts.sacramento(textStyle: textTheme.headline5), + headline6: GoogleFonts.sacramento(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sacramento(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sacramento(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sacramento(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sacramento(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sacramento(textStyle: textTheme.caption), + button: GoogleFonts.sacramento(textStyle: textTheme.button), + overline: GoogleFonts.sacramento(textStyle: textTheme.overline), + ); + } + + /// Applies the Sahitya font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sahitya + static TextStyle sahitya({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '54146b1b18bccc5173c7f1cc478fd450cfb721e1b3d40df0ebd3dcf6711c6c48', + 186736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '14383134c508c525e61d88a045189d98b08191a7cadfada9c90a82eea5d88ee6', + 186312, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sahitya', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sahitya font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sahitya + static TextTheme sahityaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sahitya(textStyle: textTheme.headline1), + headline2: GoogleFonts.sahitya(textStyle: textTheme.headline2), + headline3: GoogleFonts.sahitya(textStyle: textTheme.headline3), + headline4: GoogleFonts.sahitya(textStyle: textTheme.headline4), + headline5: GoogleFonts.sahitya(textStyle: textTheme.headline5), + headline6: GoogleFonts.sahitya(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sahitya(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sahitya(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sahitya(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sahitya(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sahitya(textStyle: textTheme.caption), + button: GoogleFonts.sahitya(textStyle: textTheme.button), + overline: GoogleFonts.sahitya(textStyle: textTheme.overline), + ); + } + + /// Applies the Sail font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sail + static TextStyle sail({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '448cb365963b156da5ce3bb2b69bd8c6837dfd0a2beb5f00d831143b1910ec6e', + 32436, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sail', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sail font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sail + static TextTheme sailTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sail(textStyle: textTheme.headline1), + headline2: GoogleFonts.sail(textStyle: textTheme.headline2), + headline3: GoogleFonts.sail(textStyle: textTheme.headline3), + headline4: GoogleFonts.sail(textStyle: textTheme.headline4), + headline5: GoogleFonts.sail(textStyle: textTheme.headline5), + headline6: GoogleFonts.sail(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sail(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sail(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sail(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sail(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sail(textStyle: textTheme.caption), + button: GoogleFonts.sail(textStyle: textTheme.button), + overline: GoogleFonts.sail(textStyle: textTheme.overline), + ); + } + + /// Applies the Saira font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira + static TextStyle saira({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b6d764b20e47ac3d6764acfa56dcca309c570f72779558c6c85b227d3d52c1a9', + 74292, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2b401181dcedd7b5ce954c3110d4a358e96333124e6afb4335cf4ce5a9612a21', + 80648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9bc2a7efb47daf648f831278c1e7d476dc527592af052be0f1b56d14e3b4e333', + 74772, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '52c681d7513af192559d2240ada8f9fa22b3643bdb673ee7e21e6eb5684435f9', + 74492, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2ca26aa1deaa72e2d0a3578ee8e0308aeeabd47a10628833efad904d84f252ba', + 74924, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd9b40c01b3303786bc3fffeff6a6d3a756acf2bd892721e8d28e640b1269900f', + 75408, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6f648ffbf75c94be4a3f3bdce9ed055f5ca4c76cea8df354c32deecf172d4bc3', + 75764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e7ef6f260e896a02dd09b2e149372bffaf3c2fc81e6a3eaba79751a2f84bc498', + 81492, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '784cb5c4c9a4355b55b1f819414b962800d401a312f0874e035e90ba2d1ebeb8', + 74768, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Saira', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Saira font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira + static TextTheme sairaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.saira(textStyle: textTheme.headline1), + headline2: GoogleFonts.saira(textStyle: textTheme.headline2), + headline3: GoogleFonts.saira(textStyle: textTheme.headline3), + headline4: GoogleFonts.saira(textStyle: textTheme.headline4), + headline5: GoogleFonts.saira(textStyle: textTheme.headline5), + headline6: GoogleFonts.saira(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.saira(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.saira(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.saira(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.saira(textStyle: textTheme.bodyText2), + caption: GoogleFonts.saira(textStyle: textTheme.caption), + button: GoogleFonts.saira(textStyle: textTheme.button), + overline: GoogleFonts.saira(textStyle: textTheme.overline), + ); + } + + /// Applies the Saira Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira+Condensed + static TextStyle sairaCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8220c0c8f2f9288ded38da89babb11b6da4163ebaf504f877d22fb4ee43a5418', + 74008, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '589e794e8c485b04766db461cee8244dec0abc305e90f5cffd6dc37917ace3e4', + 74504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6aeb3495feb7c7ed8e87afce584590944e61b1a581d26f494de054b8a430dca7', + 74344, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b0c1ee3c73539fe0da52806bb378267b315d3ebd7ffd40f7c435dd3dfef91baa', + 74884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c78b83e91201287296ae34c6159727fed972526b1dd8aefae5b922dd4196e687', + 74876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f1b084d4812e81b0cdfa9eed1b7256d043f5d4d8a00a81ab67440f9354549fc9', + 75652, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ca3926b06ade51157b1ce932574cac89a6f16dfbdd601a345701da25b7aa8dc', + 75188, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '17caf4ad92a39b0d9333a8f668c1582d993748126b1a8ebbd4b26bca25c66a00', + 75336, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3235689af1f16e3535c26922c2fb739dd02adef166d3e761175b3af89f72240b', + 75076, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SairaCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Saira Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira+Condensed + static TextTheme sairaCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sairaCondensed(textStyle: textTheme.headline1), + headline2: GoogleFonts.sairaCondensed(textStyle: textTheme.headline2), + headline3: GoogleFonts.sairaCondensed(textStyle: textTheme.headline3), + headline4: GoogleFonts.sairaCondensed(textStyle: textTheme.headline4), + headline5: GoogleFonts.sairaCondensed(textStyle: textTheme.headline5), + headline6: GoogleFonts.sairaCondensed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sairaCondensed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sairaCondensed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sairaCondensed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sairaCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sairaCondensed(textStyle: textTheme.caption), + button: GoogleFonts.sairaCondensed(textStyle: textTheme.button), + overline: GoogleFonts.sairaCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Saira Extra Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira+Extra+Condensed + static TextStyle sairaExtraCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '322d3973d59827b2504723abf3285c2d1e85181532fd146fdbabae00398ccbb1', + 73676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd52785c9322fca08c09dbab7952bdc038ce7ef5f58298a5252ccc2a9bacfc316', + 74496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aa5dedf23086451deef347c47898e8c5153ee408af19c44b9e780c1d559c7ce3', + 74168, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7c5c7b4ab19710c4557e47580d437ed2eb1add2fc90a641088ef31539197d16f', + 75172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '36d4ceb6924f219a43b1ef0abcf228bb570891d5c6360bcfd359afccb20b87fa', + 75268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a69037b3e5411f785d7b05bb682b957613e8105cae22044518c630107b4504b2', + 75560, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3b08c582f603d1d8ae1944b4362aa3f7db533be5b7ba1c0f4971b93188a903d4', + 75436, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3d5b2328322a4ecff567415a1417dff7b0659414c992b7e2b88ca399d456df3c', + 75340, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2f9e1ef084cecc66c6306c5618a464b6f6557c0fab6b20f4061378300d83e090', + 74940, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SairaExtraCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Saira Extra Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira+Extra+Condensed + static TextTheme sairaExtraCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.headline1), + headline2: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.headline2), + headline3: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.headline3), + headline4: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.headline4), + headline5: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.headline5), + headline6: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.sairaExtraCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sairaExtraCondensed(textStyle: textTheme.caption), + button: GoogleFonts.sairaExtraCondensed(textStyle: textTheme.button), + overline: GoogleFonts.sairaExtraCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Saira Semi Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira+Semi+Condensed + static TextStyle sairaSemiCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6b2e6d1dd40d36454cc2926dcb4a1a5561eefd558ed4335da50334fe382ae95e', + 74456, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ce22147c0af87efa1aecbc39ff8b87923aee3cf2f49375403f5f34979223e610', + 75020, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ef45b03e2a6a021a7b398dc695d9fe949857b4defe4cd062b0d2be306f51ef4e', + 74892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '80d72d164a187ce7476240396003c4b453c0f3b4565db50583a99ec1485cb6dc', + 74776, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '77903b1b3697f92cb3c1338d2bbd5de692eb31244fc785e5224c5e32faae51e4', + 74988, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '10bc52c72bdddd14cf11a9a428d2dd3348861b4c6106cd154406562cf41b7e66', + 75212, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'daba4551f3f2e9c9a6720e74d136524da54d3946352c47f4df6e3acb9a315ca9', + 75536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a742dc6740800e28cf269ffb74084610ab7590779de6185e12259b99ca780d21', + 75728, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '127a359a67e8fa386310e298528a130878d4284d08e3c7c34872f38bedbe6be5', + 75328, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SairaSemiCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Saira Semi Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira+Semi+Condensed + static TextTheme sairaSemiCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.headline1), + headline2: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.headline2), + headline3: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.headline3), + headline4: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.headline4), + headline5: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.headline5), + headline6: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.caption), + button: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.button), + overline: GoogleFonts.sairaSemiCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Saira Stencil One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira+Stencil+One + static TextStyle sairaStencilOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8932ea7e84bb7b374ef9df790d899402addcdd8028ad4d444096d4ae658c1030', + 66688, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SairaStencilOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Saira Stencil One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Saira+Stencil+One + static TextTheme sairaStencilOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sairaStencilOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.sairaStencilOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.sairaStencilOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.sairaStencilOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.sairaStencilOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.sairaStencilOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sairaStencilOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sairaStencilOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sairaStencilOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sairaStencilOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sairaStencilOne(textStyle: textTheme.caption), + button: GoogleFonts.sairaStencilOne(textStyle: textTheme.button), + overline: GoogleFonts.sairaStencilOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Salsa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Salsa + static TextStyle salsa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f7150b0f04dbec851c854504d5f97adf34024d4260449086de5fbdc791ab89ac', + 56632, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Salsa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Salsa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Salsa + static TextTheme salsaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.salsa(textStyle: textTheme.headline1), + headline2: GoogleFonts.salsa(textStyle: textTheme.headline2), + headline3: GoogleFonts.salsa(textStyle: textTheme.headline3), + headline4: GoogleFonts.salsa(textStyle: textTheme.headline4), + headline5: GoogleFonts.salsa(textStyle: textTheme.headline5), + headline6: GoogleFonts.salsa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.salsa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.salsa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.salsa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.salsa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.salsa(textStyle: textTheme.caption), + button: GoogleFonts.salsa(textStyle: textTheme.button), + overline: GoogleFonts.salsa(textStyle: textTheme.overline), + ); + } + + /// Applies the Sanchez font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sanchez + static TextStyle sanchez({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd4353709b92c21bf0606f2e6c956fddf56ee0fdea20110524ed03052efcc2bbe', + 72504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '62da09506355ddb13a8f3a0b9829d9420e5a0dc10a04fe9d6bd314501b513c93', + 75164, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sanchez', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sanchez font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sanchez + static TextTheme sanchezTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sanchez(textStyle: textTheme.headline1), + headline2: GoogleFonts.sanchez(textStyle: textTheme.headline2), + headline3: GoogleFonts.sanchez(textStyle: textTheme.headline3), + headline4: GoogleFonts.sanchez(textStyle: textTheme.headline4), + headline5: GoogleFonts.sanchez(textStyle: textTheme.headline5), + headline6: GoogleFonts.sanchez(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sanchez(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sanchez(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sanchez(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sanchez(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sanchez(textStyle: textTheme.caption), + button: GoogleFonts.sanchez(textStyle: textTheme.button), + overline: GoogleFonts.sanchez(textStyle: textTheme.overline), + ); + } + + /// Applies the Sancreek font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sancreek + static TextStyle sancreek({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ed5c3c851564b594f1e46baf486678ec23c42381e0439cdb2c79c04ca159563e', + 49604, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sancreek', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sancreek font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sancreek + static TextTheme sancreekTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sancreek(textStyle: textTheme.headline1), + headline2: GoogleFonts.sancreek(textStyle: textTheme.headline2), + headline3: GoogleFonts.sancreek(textStyle: textTheme.headline3), + headline4: GoogleFonts.sancreek(textStyle: textTheme.headline4), + headline5: GoogleFonts.sancreek(textStyle: textTheme.headline5), + headline6: GoogleFonts.sancreek(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sancreek(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sancreek(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sancreek(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sancreek(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sancreek(textStyle: textTheme.caption), + button: GoogleFonts.sancreek(textStyle: textTheme.button), + overline: GoogleFonts.sancreek(textStyle: textTheme.overline), + ); + } + + /// Applies the Sansita font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sansita + static TextStyle sansita({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7e365aa3bbe93b56d5d0182d955c0e71da391d8d6a95479cab79fa24ced4e21e', + 47676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5aadd2db25ea4fcdeb76680b8b44761b6914ed6b874b5861a9e8c52412b66918', + 52676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b4828652c6bf26cd36ad5741e616104c91b8c4023c6a891b4460029e6642a4cb', + 47984, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '50757fb78ba6b455ca114555fcedffe03432f6fd4eb385544018c427a43c0430', + 52732, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '45499f61b5c2d545e14c3d78cc4a76d906ae3a15bacbf4b5479233e04c979cad', + 48108, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6639d72f7bea1c80dcce732810166ac07da8ae78f5bb5cc798d11f97ce256a0b', + 52764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '21bb47cdb40ec87c2ddbbfcb8b02a2af52cab2e20147315381b65d54d1ae0e5f', + 48696, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2d3308301f6e427d108e0dab0cd6ed936a27d83cfd3dbfbc8693b260574b7cd3', + 53640, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sansita', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sansita font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sansita + static TextTheme sansitaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sansita(textStyle: textTheme.headline1), + headline2: GoogleFonts.sansita(textStyle: textTheme.headline2), + headline3: GoogleFonts.sansita(textStyle: textTheme.headline3), + headline4: GoogleFonts.sansita(textStyle: textTheme.headline4), + headline5: GoogleFonts.sansita(textStyle: textTheme.headline5), + headline6: GoogleFonts.sansita(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sansita(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sansita(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sansita(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sansita(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sansita(textStyle: textTheme.caption), + button: GoogleFonts.sansita(textStyle: textTheme.button), + overline: GoogleFonts.sansita(textStyle: textTheme.overline), + ); + } + + /// Applies the Sansita Swashed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sansita+Swashed + static TextStyle sansitaSwashed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '46bd39b8f615d07fdc7cecf44b42cb5d14cdf66da70aa05b66e7520ac9b50832', + 104096, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '05e62a87f1460b7970799bf3f368a0fdc1b25a39739d9d88fe011a153e1ea5d2', + 104144, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '76a665e8f726f9b8b14700a64df0e8ee7f5c57f3e6488bcbf8ef00bfc4284194', + 104164, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '55f85d0cf13c0c8c44eceae9cfa14bf3543cbc03163a9568c10d7d24e89bca19', + 104180, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b5e225292e98feef5f130f0689f2af441cb497b0e814b5acec0ad1420094b311', + 104072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e98f4b3fb17f6f7561d75c958248295b6d21af13e994ecc1308331685880db9a', + 104080, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '98eb0092fabbca4305d33cdef9e6db2457c35963ce94c74940eabed7525c43d2', + 104104, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SansitaSwashed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sansita Swashed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sansita+Swashed + static TextTheme sansitaSwashedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sansitaSwashed(textStyle: textTheme.headline1), + headline2: GoogleFonts.sansitaSwashed(textStyle: textTheme.headline2), + headline3: GoogleFonts.sansitaSwashed(textStyle: textTheme.headline3), + headline4: GoogleFonts.sansitaSwashed(textStyle: textTheme.headline4), + headline5: GoogleFonts.sansitaSwashed(textStyle: textTheme.headline5), + headline6: GoogleFonts.sansitaSwashed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sansitaSwashed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sansitaSwashed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sansitaSwashed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sansitaSwashed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sansitaSwashed(textStyle: textTheme.caption), + button: GoogleFonts.sansitaSwashed(textStyle: textTheme.button), + overline: GoogleFonts.sansitaSwashed(textStyle: textTheme.overline), + ); + } + + /// Applies the Sarabun font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sarabun + static TextStyle sarabun({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '50cf24ee678c36e02b98c19ccc01d8e59c50d00c66e75054e4cca503779d8f37', + 81728, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8ddc6bd48ee92ae9672930531c771ff526c5d8f06d26f1abdd8966cb2d563262', + 84640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3d79bab342addcc5613aed52e171c972f57a291ab53a7058d0412e3ade2c009a', + 81572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '58630737fd991b60fc7250ed8c5dac4599dd5b338ee6cfe1e9cb05dc7d0ac3db', + 84640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ea334f3326fdb7fe48915bb07db5004530cce0576194cc0c0865bdcf11cafdfd', + 81540, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1cc37aaa51644e80ff1fb97a07f05f066504d4b3e66358fc7c482ff7f79b4811', + 84372, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5eb10ecb7f0b1864511e05724501467da68496508c15fbf0ed3958e162575ddc', + 81452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4412c26720c9c31795b0d2912215dbdd0dfaf18b42b7953f9fb26b54427094b0', + 84388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '105263cd2ca92f9e66491c20400dfa6cdea9a47658d6074e7d04a6ceb3e2a96f', + 81404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e4253ff00e203d8cc8e0b7ebf54e2a55a3f2874c5ac9d191861983700c85103c', + 84440, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a93849f8fcd0c0df8318aa91b45b14a0b9d84123c8ec5f5d144347b2c03e00e0', + 81284, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c62534f6034acd31705d941b3ef92b86a40a6ce68879fe627c71e66f6d171add', + 84332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '330d03c990cec0cc7f6fc0c08f2fd09d616447a8b492c3decfd907d665be7e19', + 80984, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ce3ba67e7cb6d8993594f6a7cac0091efe50173174ed9044ebde2afa86922db9', + 84024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ad638b132e53ca7e95e1c81621980df4f1bc00248b98b088d5dbb67372dd5173', + 80968, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4bcc3502d7dc5c7b0f96076c30ed78f3854455f65e5146c76a13893aa033341a', + 83760, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sarabun', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sarabun font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sarabun + static TextTheme sarabunTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sarabun(textStyle: textTheme.headline1), + headline2: GoogleFonts.sarabun(textStyle: textTheme.headline2), + headline3: GoogleFonts.sarabun(textStyle: textTheme.headline3), + headline4: GoogleFonts.sarabun(textStyle: textTheme.headline4), + headline5: GoogleFonts.sarabun(textStyle: textTheme.headline5), + headline6: GoogleFonts.sarabun(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sarabun(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sarabun(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sarabun(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sarabun(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sarabun(textStyle: textTheme.caption), + button: GoogleFonts.sarabun(textStyle: textTheme.button), + overline: GoogleFonts.sarabun(textStyle: textTheme.overline), + ); + } + + /// Applies the Sarala font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sarala + static TextStyle sarala({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a9d80ed2e5dae04bd639f269f2f43d7fa0b65ef816a0abb64bbcae03db7a59bb', + 207268, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2b0699ce4a9bd9eb0f091d571c8992f4ff81d558ef3b60edd81a71a081a6420f', + 207396, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sarala', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sarala font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sarala + static TextTheme saralaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sarala(textStyle: textTheme.headline1), + headline2: GoogleFonts.sarala(textStyle: textTheme.headline2), + headline3: GoogleFonts.sarala(textStyle: textTheme.headline3), + headline4: GoogleFonts.sarala(textStyle: textTheme.headline4), + headline5: GoogleFonts.sarala(textStyle: textTheme.headline5), + headline6: GoogleFonts.sarala(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sarala(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sarala(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sarala(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sarala(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sarala(textStyle: textTheme.caption), + button: GoogleFonts.sarala(textStyle: textTheme.button), + overline: GoogleFonts.sarala(textStyle: textTheme.overline), + ); + } + + /// Applies the Sarina font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sarina + static TextStyle sarina({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e8cf41d2055d00dcd843e227fa52df85c9770e93179c0cec39909e4fccfc2dbf', + 96080, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sarina', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sarina font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sarina + static TextTheme sarinaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sarina(textStyle: textTheme.headline1), + headline2: GoogleFonts.sarina(textStyle: textTheme.headline2), + headline3: GoogleFonts.sarina(textStyle: textTheme.headline3), + headline4: GoogleFonts.sarina(textStyle: textTheme.headline4), + headline5: GoogleFonts.sarina(textStyle: textTheme.headline5), + headline6: GoogleFonts.sarina(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sarina(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sarina(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sarina(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sarina(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sarina(textStyle: textTheme.caption), + button: GoogleFonts.sarina(textStyle: textTheme.button), + overline: GoogleFonts.sarina(textStyle: textTheme.overline), + ); + } + + /// Applies the Sarpanch font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sarpanch + static TextStyle sarpanch({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a694e1d94a3cd59dead878c6ef1da8eb55274eb3b10e6f667a4506f4d2bf6a36', + 178940, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c7dedb13d24392e5c3e796641d50cce4643a03762ea0df2936f01cbdf94976bd', + 178348, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6bf8e038e00a3b7997da00d55f7715433a7c61351b1434e3659fb806f0c25a0e', + 176504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5e1a7afd37c3b896e4eeb5de1bd8a3414b6966b45f7a9652b041ae80cb3b1855', + 178680, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a9575bc7bbbe80afa882bd838018d60f95a70408b16be48f2ce3f32eefebc620', + 185716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '353bbda31bbbf4d1b499d676bded12b04e4aabafae78f929c4e5e875ecd09a19', + 187296, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sarpanch', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sarpanch font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sarpanch + static TextTheme sarpanchTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sarpanch(textStyle: textTheme.headline1), + headline2: GoogleFonts.sarpanch(textStyle: textTheme.headline2), + headline3: GoogleFonts.sarpanch(textStyle: textTheme.headline3), + headline4: GoogleFonts.sarpanch(textStyle: textTheme.headline4), + headline5: GoogleFonts.sarpanch(textStyle: textTheme.headline5), + headline6: GoogleFonts.sarpanch(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sarpanch(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sarpanch(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sarpanch(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sarpanch(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sarpanch(textStyle: textTheme.caption), + button: GoogleFonts.sarpanch(textStyle: textTheme.button), + overline: GoogleFonts.sarpanch(textStyle: textTheme.overline), + ); + } + + /// Applies the Satisfy font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Satisfy + static TextStyle satisfy({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4d3c18800d0d83b916c8d564ef9d72f9c23fd58cb7650edd14153251d25ffffc', + 47512, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Satisfy', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Satisfy font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Satisfy + static TextTheme satisfyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.satisfy(textStyle: textTheme.headline1), + headline2: GoogleFonts.satisfy(textStyle: textTheme.headline2), + headline3: GoogleFonts.satisfy(textStyle: textTheme.headline3), + headline4: GoogleFonts.satisfy(textStyle: textTheme.headline4), + headline5: GoogleFonts.satisfy(textStyle: textTheme.headline5), + headline6: GoogleFonts.satisfy(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.satisfy(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.satisfy(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.satisfy(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.satisfy(textStyle: textTheme.bodyText2), + caption: GoogleFonts.satisfy(textStyle: textTheme.caption), + button: GoogleFonts.satisfy(textStyle: textTheme.button), + overline: GoogleFonts.satisfy(textStyle: textTheme.overline), + ); + } + + /// Applies the Sawarabi Gothic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sawarabi+Gothic + static TextStyle sawarabiGothic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'da6058a80d658ffc7eaa1acdae31b56f86f9f59fcae94417efa5205b8c2a9c3e', + 1895880, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SawarabiGothic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sawarabi Gothic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sawarabi+Gothic + static TextTheme sawarabiGothicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sawarabiGothic(textStyle: textTheme.headline1), + headline2: GoogleFonts.sawarabiGothic(textStyle: textTheme.headline2), + headline3: GoogleFonts.sawarabiGothic(textStyle: textTheme.headline3), + headline4: GoogleFonts.sawarabiGothic(textStyle: textTheme.headline4), + headline5: GoogleFonts.sawarabiGothic(textStyle: textTheme.headline5), + headline6: GoogleFonts.sawarabiGothic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sawarabiGothic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sawarabiGothic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sawarabiGothic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sawarabiGothic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sawarabiGothic(textStyle: textTheme.caption), + button: GoogleFonts.sawarabiGothic(textStyle: textTheme.button), + overline: GoogleFonts.sawarabiGothic(textStyle: textTheme.overline), + ); + } + + /// Applies the Sawarabi Mincho font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sawarabi+Mincho + static TextStyle sawarabiMincho({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f3beec4e12191867fb2f0f6f9b79f2367eab607cb6a1f28f445a8ae4b13f6c15', + 1081468, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SawarabiMincho', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sawarabi Mincho font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sawarabi+Mincho + static TextTheme sawarabiMinchoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sawarabiMincho(textStyle: textTheme.headline1), + headline2: GoogleFonts.sawarabiMincho(textStyle: textTheme.headline2), + headline3: GoogleFonts.sawarabiMincho(textStyle: textTheme.headline3), + headline4: GoogleFonts.sawarabiMincho(textStyle: textTheme.headline4), + headline5: GoogleFonts.sawarabiMincho(textStyle: textTheme.headline5), + headline6: GoogleFonts.sawarabiMincho(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sawarabiMincho(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sawarabiMincho(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sawarabiMincho(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sawarabiMincho(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sawarabiMincho(textStyle: textTheme.caption), + button: GoogleFonts.sawarabiMincho(textStyle: textTheme.button), + overline: GoogleFonts.sawarabiMincho(textStyle: textTheme.overline), + ); + } + + /// Applies the Scada font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Scada + static TextStyle scada({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b50d4e47b78665f29007e923c626d8127c7c9793f60cc8b94e55fe65a9e1b156', + 62708, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '19e3630deea1d0d7694e73dfb85c5a97e8fc332031fc27897d4b5b14fb6f62b3', + 66088, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9a106a75900b9cafa514e2c814b45cabcd61c5f50ceac1772ce6a12386cfa505', + 62808, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c61947a93ece6ef8f4f35e6f1f51f2d2eae7d27d8c1e103b8a0792818925421e', + 66148, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Scada', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Scada font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Scada + static TextTheme scadaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.scada(textStyle: textTheme.headline1), + headline2: GoogleFonts.scada(textStyle: textTheme.headline2), + headline3: GoogleFonts.scada(textStyle: textTheme.headline3), + headline4: GoogleFonts.scada(textStyle: textTheme.headline4), + headline5: GoogleFonts.scada(textStyle: textTheme.headline5), + headline6: GoogleFonts.scada(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.scada(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.scada(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.scada(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.scada(textStyle: textTheme.bodyText2), + caption: GoogleFonts.scada(textStyle: textTheme.caption), + button: GoogleFonts.scada(textStyle: textTheme.button), + overline: GoogleFonts.scada(textStyle: textTheme.overline), + ); + } + + /// Applies the Scheherazade font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Scheherazade + static TextStyle scheherazade({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '19195e141f9f7a6781f93d0ee49ef46a8784c28c28047b0b821b639546c9d562', + 406552, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a5d40a2e35f3920327fbc1d576a3a1f7aadda38089f736dad6eda793e74a225', + 421884, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Scheherazade', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Scheherazade font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Scheherazade + static TextTheme scheherazadeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.scheherazade(textStyle: textTheme.headline1), + headline2: GoogleFonts.scheherazade(textStyle: textTheme.headline2), + headline3: GoogleFonts.scheherazade(textStyle: textTheme.headline3), + headline4: GoogleFonts.scheherazade(textStyle: textTheme.headline4), + headline5: GoogleFonts.scheherazade(textStyle: textTheme.headline5), + headline6: GoogleFonts.scheherazade(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.scheherazade(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.scheherazade(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.scheherazade(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.scheherazade(textStyle: textTheme.bodyText2), + caption: GoogleFonts.scheherazade(textStyle: textTheme.caption), + button: GoogleFonts.scheherazade(textStyle: textTheme.button), + overline: GoogleFonts.scheherazade(textStyle: textTheme.overline), + ); + } + + /// Applies the Schoolbell font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Schoolbell + static TextStyle schoolbell({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6746cbf7f7065953ffdd505057d2aafca2c4c38989ab1a2bb37f953e3692c7c9', + 48472, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Schoolbell', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Schoolbell font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Schoolbell + static TextTheme schoolbellTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.schoolbell(textStyle: textTheme.headline1), + headline2: GoogleFonts.schoolbell(textStyle: textTheme.headline2), + headline3: GoogleFonts.schoolbell(textStyle: textTheme.headline3), + headline4: GoogleFonts.schoolbell(textStyle: textTheme.headline4), + headline5: GoogleFonts.schoolbell(textStyle: textTheme.headline5), + headline6: GoogleFonts.schoolbell(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.schoolbell(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.schoolbell(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.schoolbell(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.schoolbell(textStyle: textTheme.bodyText2), + caption: GoogleFonts.schoolbell(textStyle: textTheme.caption), + button: GoogleFonts.schoolbell(textStyle: textTheme.button), + overline: GoogleFonts.schoolbell(textStyle: textTheme.overline), + ); + } + + /// Applies the Scope One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Scope+One + static TextStyle scopeOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4731e0b7f73e41e5dbd3b6282d39a0c36cdb8455e36b71e9b60319540c088c3d', + 69828, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ScopeOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Scope One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Scope+One + static TextTheme scopeOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.scopeOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.scopeOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.scopeOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.scopeOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.scopeOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.scopeOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.scopeOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.scopeOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.scopeOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.scopeOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.scopeOne(textStyle: textTheme.caption), + button: GoogleFonts.scopeOne(textStyle: textTheme.button), + overline: GoogleFonts.scopeOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Seaweed Script font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Seaweed+Script + static TextStyle seaweedScript({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6a7c62dc8a68c25b3dda440a08e1f3087e28832110098b91b4c412a906ebafa2', + 116656, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SeaweedScript', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Seaweed Script font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Seaweed+Script + static TextTheme seaweedScriptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.seaweedScript(textStyle: textTheme.headline1), + headline2: GoogleFonts.seaweedScript(textStyle: textTheme.headline2), + headline3: GoogleFonts.seaweedScript(textStyle: textTheme.headline3), + headline4: GoogleFonts.seaweedScript(textStyle: textTheme.headline4), + headline5: GoogleFonts.seaweedScript(textStyle: textTheme.headline5), + headline6: GoogleFonts.seaweedScript(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.seaweedScript(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.seaweedScript(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.seaweedScript(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.seaweedScript(textStyle: textTheme.bodyText2), + caption: GoogleFonts.seaweedScript(textStyle: textTheme.caption), + button: GoogleFonts.seaweedScript(textStyle: textTheme.button), + overline: GoogleFonts.seaweedScript(textStyle: textTheme.overline), + ); + } + + /// Applies the Secular One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Secular+One + static TextStyle secularOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dd6c129ece769b38daf0095b6545ec239fb57e4a2747ec848b6a49958ff0ffff', + 58488, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SecularOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Secular One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Secular+One + static TextTheme secularOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.secularOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.secularOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.secularOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.secularOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.secularOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.secularOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.secularOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.secularOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.secularOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.secularOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.secularOne(textStyle: textTheme.caption), + button: GoogleFonts.secularOne(textStyle: textTheme.button), + overline: GoogleFonts.secularOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Sedgwick Ave font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sedgwick+Ave + static TextStyle sedgwickAve({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '75c5db2b35fc38825c6bb8e5b7950fcedcfd03dec14b735dc12648a9b601d9f8', + 92948, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SedgwickAve', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sedgwick Ave font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sedgwick+Ave + static TextTheme sedgwickAveTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sedgwickAve(textStyle: textTheme.headline1), + headline2: GoogleFonts.sedgwickAve(textStyle: textTheme.headline2), + headline3: GoogleFonts.sedgwickAve(textStyle: textTheme.headline3), + headline4: GoogleFonts.sedgwickAve(textStyle: textTheme.headline4), + headline5: GoogleFonts.sedgwickAve(textStyle: textTheme.headline5), + headline6: GoogleFonts.sedgwickAve(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sedgwickAve(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sedgwickAve(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sedgwickAve(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sedgwickAve(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sedgwickAve(textStyle: textTheme.caption), + button: GoogleFonts.sedgwickAve(textStyle: textTheme.button), + overline: GoogleFonts.sedgwickAve(textStyle: textTheme.overline), + ); + } + + /// Applies the Sedgwick Ave Display font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sedgwick+Ave+Display + static TextStyle sedgwickAveDisplay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c1aa82570f810f79198c969d9475cd420e45b9de6957e8dcdedd71ecbaf755c4', + 88964, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SedgwickAveDisplay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sedgwick Ave Display font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sedgwick+Ave+Display + static TextTheme sedgwickAveDisplayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.headline1), + headline2: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.headline2), + headline3: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.headline3), + headline4: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.headline4), + headline5: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.headline5), + headline6: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.caption), + button: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.button), + overline: GoogleFonts.sedgwickAveDisplay(textStyle: textTheme.overline), + ); + } + + /// Applies the Sen font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sen + static TextStyle sen({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '74c43e6590cf290828c5cfbeac6dfeecfe47f48d77d71385189eedc28c93bd7d', + 28176, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '384267b011f455064f728397ef7bf6303e94e62dd85613372ca7dcc2add6eb0a', + 28104, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '709f63ed575896ba15fe606abd291ee16ebdba1d773b8df284f0c0ec5e6985e5', + 28012, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sen', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sen font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sen + static TextTheme senTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sen(textStyle: textTheme.headline1), + headline2: GoogleFonts.sen(textStyle: textTheme.headline2), + headline3: GoogleFonts.sen(textStyle: textTheme.headline3), + headline4: GoogleFonts.sen(textStyle: textTheme.headline4), + headline5: GoogleFonts.sen(textStyle: textTheme.headline5), + headline6: GoogleFonts.sen(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sen(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sen(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sen(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sen(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sen(textStyle: textTheme.caption), + button: GoogleFonts.sen(textStyle: textTheme.button), + overline: GoogleFonts.sen(textStyle: textTheme.overline), + ); + } + + /// Applies the Sevillana font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sevillana + static TextStyle sevillana({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1932da733380cee1525fb66845203d6b91ab799d20f9836d43b021d247101c76', + 65004, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sevillana', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sevillana font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sevillana + static TextTheme sevillanaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sevillana(textStyle: textTheme.headline1), + headline2: GoogleFonts.sevillana(textStyle: textTheme.headline2), + headline3: GoogleFonts.sevillana(textStyle: textTheme.headline3), + headline4: GoogleFonts.sevillana(textStyle: textTheme.headline4), + headline5: GoogleFonts.sevillana(textStyle: textTheme.headline5), + headline6: GoogleFonts.sevillana(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sevillana(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sevillana(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sevillana(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sevillana(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sevillana(textStyle: textTheme.caption), + button: GoogleFonts.sevillana(textStyle: textTheme.button), + overline: GoogleFonts.sevillana(textStyle: textTheme.overline), + ); + } + + /// Applies the Seymour One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Seymour+One + static TextStyle seymourOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e7cbd22ce54883fd2ac35ed6713f3fe1d70045e47934b033a6d51357e4d097f2', + 42796, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SeymourOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Seymour One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Seymour+One + static TextTheme seymourOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.seymourOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.seymourOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.seymourOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.seymourOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.seymourOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.seymourOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.seymourOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.seymourOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.seymourOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.seymourOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.seymourOne(textStyle: textTheme.caption), + button: GoogleFonts.seymourOne(textStyle: textTheme.button), + overline: GoogleFonts.seymourOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Shadows Into Light font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shadows+Into+Light + static TextStyle shadowsIntoLight({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd737d913f418f2f8e85744c94be63b75e1af421856c3a203104a211dc7f337fa', + 53856, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ShadowsIntoLight', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Shadows Into Light font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shadows+Into+Light + static TextTheme shadowsIntoLightTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.shadowsIntoLight(textStyle: textTheme.headline1), + headline2: GoogleFonts.shadowsIntoLight(textStyle: textTheme.headline2), + headline3: GoogleFonts.shadowsIntoLight(textStyle: textTheme.headline3), + headline4: GoogleFonts.shadowsIntoLight(textStyle: textTheme.headline4), + headline5: GoogleFonts.shadowsIntoLight(textStyle: textTheme.headline5), + headline6: GoogleFonts.shadowsIntoLight(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.shadowsIntoLight(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.shadowsIntoLight(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.shadowsIntoLight(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.shadowsIntoLight(textStyle: textTheme.bodyText2), + caption: GoogleFonts.shadowsIntoLight(textStyle: textTheme.caption), + button: GoogleFonts.shadowsIntoLight(textStyle: textTheme.button), + overline: GoogleFonts.shadowsIntoLight(textStyle: textTheme.overline), + ); + } + + /// Applies the Shadows Into Light Two font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shadows+Into+Light+Two + static TextStyle shadowsIntoLightTwo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '893c145feef9217e5c35f97bb6d74c1068a802587acc2f5f3c35f2c2ebf8730f', + 39372, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ShadowsIntoLightTwo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Shadows Into Light Two font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shadows+Into+Light+Two + static TextTheme shadowsIntoLightTwoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.headline1), + headline2: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.headline2), + headline3: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.headline3), + headline4: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.headline4), + headline5: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.headline5), + headline6: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.caption), + button: GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.button), + overline: GoogleFonts.shadowsIntoLightTwo(textStyle: textTheme.overline), + ); + } + + /// Applies the Shanti font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shanti + static TextStyle shanti({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a3182c815ff6755fb8f9b08ac951b5735b102c05b851eac2b1f6fd50a623cd82', + 65976, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Shanti', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Shanti font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shanti + static TextTheme shantiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.shanti(textStyle: textTheme.headline1), + headline2: GoogleFonts.shanti(textStyle: textTheme.headline2), + headline3: GoogleFonts.shanti(textStyle: textTheme.headline3), + headline4: GoogleFonts.shanti(textStyle: textTheme.headline4), + headline5: GoogleFonts.shanti(textStyle: textTheme.headline5), + headline6: GoogleFonts.shanti(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.shanti(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.shanti(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.shanti(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.shanti(textStyle: textTheme.bodyText2), + caption: GoogleFonts.shanti(textStyle: textTheme.caption), + button: GoogleFonts.shanti(textStyle: textTheme.button), + overline: GoogleFonts.shanti(textStyle: textTheme.overline), + ); + } + + /// Applies the Share font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Share + static TextStyle share({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c1621fb56fac35ccedec411f3ee0e726ca8c3b6c1e5616fcaec194d0e26c1207', + 52788, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e7c900b0cd2cdfb860519a4df3b0242ad6ae849a1fcb892760fbf78e93214626', + 54944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '283b89ac6d01b1444d546b1992f9ce7ab0f1ecda06b9d33769bbbf3ee979a76c', + 52808, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a8f8a01adf843c6551142bd88a1f437fa3b739e7dbaaef798f80a5500afae4d3', + 54996, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Share', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Share font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Share + static TextTheme shareTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.share(textStyle: textTheme.headline1), + headline2: GoogleFonts.share(textStyle: textTheme.headline2), + headline3: GoogleFonts.share(textStyle: textTheme.headline3), + headline4: GoogleFonts.share(textStyle: textTheme.headline4), + headline5: GoogleFonts.share(textStyle: textTheme.headline5), + headline6: GoogleFonts.share(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.share(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.share(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.share(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.share(textStyle: textTheme.bodyText2), + caption: GoogleFonts.share(textStyle: textTheme.caption), + button: GoogleFonts.share(textStyle: textTheme.button), + overline: GoogleFonts.share(textStyle: textTheme.overline), + ); + } + + /// Applies the Share Tech font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Share+Tech + static TextStyle shareTech({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e1804d3fb7ab822590fa14a41b103a7d679b4d284079cee4c7c5ebef0c940510', + 34888, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ShareTech', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Share Tech font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Share+Tech + static TextTheme shareTechTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.shareTech(textStyle: textTheme.headline1), + headline2: GoogleFonts.shareTech(textStyle: textTheme.headline2), + headline3: GoogleFonts.shareTech(textStyle: textTheme.headline3), + headline4: GoogleFonts.shareTech(textStyle: textTheme.headline4), + headline5: GoogleFonts.shareTech(textStyle: textTheme.headline5), + headline6: GoogleFonts.shareTech(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.shareTech(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.shareTech(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.shareTech(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.shareTech(textStyle: textTheme.bodyText2), + caption: GoogleFonts.shareTech(textStyle: textTheme.caption), + button: GoogleFonts.shareTech(textStyle: textTheme.button), + overline: GoogleFonts.shareTech(textStyle: textTheme.overline), + ); + } + + /// Applies the Share Tech Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Share+Tech+Mono + static TextStyle shareTechMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d8191f3a7dbbc940a83fb98e35db9faed0904879a2d5fd1d1c4443b1c3e9057', + 25776, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ShareTechMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Share Tech Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Share+Tech+Mono + static TextTheme shareTechMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.shareTechMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.shareTechMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.shareTechMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.shareTechMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.shareTechMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.shareTechMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.shareTechMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.shareTechMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.shareTechMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.shareTechMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.shareTechMono(textStyle: textTheme.caption), + button: GoogleFonts.shareTechMono(textStyle: textTheme.button), + overline: GoogleFonts.shareTechMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Shojumaru font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shojumaru + static TextStyle shojumaru({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fb8c1c2c57d08ed6f7529a7edaa63995da1703823a076877d46c77f0b984d3f5', + 71256, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Shojumaru', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Shojumaru font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shojumaru + static TextTheme shojumaruTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.shojumaru(textStyle: textTheme.headline1), + headline2: GoogleFonts.shojumaru(textStyle: textTheme.headline2), + headline3: GoogleFonts.shojumaru(textStyle: textTheme.headline3), + headline4: GoogleFonts.shojumaru(textStyle: textTheme.headline4), + headline5: GoogleFonts.shojumaru(textStyle: textTheme.headline5), + headline6: GoogleFonts.shojumaru(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.shojumaru(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.shojumaru(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.shojumaru(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.shojumaru(textStyle: textTheme.bodyText2), + caption: GoogleFonts.shojumaru(textStyle: textTheme.caption), + button: GoogleFonts.shojumaru(textStyle: textTheme.button), + overline: GoogleFonts.shojumaru(textStyle: textTheme.overline), + ); + } + + /// Applies the Short Stack font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Short+Stack + static TextStyle shortStack({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '558333b2d2edb0db150ab52358a8d983ea83d194559c81b99d0defac9ef6ea5c', + 68128, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ShortStack', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Short Stack font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Short+Stack + static TextTheme shortStackTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.shortStack(textStyle: textTheme.headline1), + headline2: GoogleFonts.shortStack(textStyle: textTheme.headline2), + headline3: GoogleFonts.shortStack(textStyle: textTheme.headline3), + headline4: GoogleFonts.shortStack(textStyle: textTheme.headline4), + headline5: GoogleFonts.shortStack(textStyle: textTheme.headline5), + headline6: GoogleFonts.shortStack(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.shortStack(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.shortStack(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.shortStack(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.shortStack(textStyle: textTheme.bodyText2), + caption: GoogleFonts.shortStack(textStyle: textTheme.caption), + button: GoogleFonts.shortStack(textStyle: textTheme.button), + overline: GoogleFonts.shortStack(textStyle: textTheme.overline), + ); + } + + /// Applies the Shrikhand font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shrikhand + static TextStyle shrikhand({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aacb9e67a15ab34c2c3cc3a314bd696f3ef409963bd74b25e61727a3b1414ffc', + 219252, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Shrikhand', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Shrikhand font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Shrikhand + static TextTheme shrikhandTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.shrikhand(textStyle: textTheme.headline1), + headline2: GoogleFonts.shrikhand(textStyle: textTheme.headline2), + headline3: GoogleFonts.shrikhand(textStyle: textTheme.headline3), + headline4: GoogleFonts.shrikhand(textStyle: textTheme.headline4), + headline5: GoogleFonts.shrikhand(textStyle: textTheme.headline5), + headline6: GoogleFonts.shrikhand(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.shrikhand(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.shrikhand(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.shrikhand(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.shrikhand(textStyle: textTheme.bodyText2), + caption: GoogleFonts.shrikhand(textStyle: textTheme.caption), + button: GoogleFonts.shrikhand(textStyle: textTheme.button), + overline: GoogleFonts.shrikhand(textStyle: textTheme.overline), + ); + } + + /// Applies the Sigmar One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sigmar+One + static TextStyle sigmarOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a26bc79f6d548004cb3a749091e43721c48faa5e364f6729ca4ba11bc29f7672', + 110044, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SigmarOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sigmar One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sigmar+One + static TextTheme sigmarOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sigmarOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.sigmarOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.sigmarOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.sigmarOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.sigmarOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.sigmarOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sigmarOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sigmarOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sigmarOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sigmarOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sigmarOne(textStyle: textTheme.caption), + button: GoogleFonts.sigmarOne(textStyle: textTheme.button), + overline: GoogleFonts.sigmarOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Signika font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Signika + static TextStyle signika({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '57a28a3623e1ad46bb9a9d87d09811b72a87364aeb2d326a4df99bf0e23c0874', + 74672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '028c027c049948e0a67c1a20b73992c9449bec50376131d3a57d3f98ad790c63', + 75492, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2d6ed6b2f09f8f763304a07135b4a8dca9de0b7e1aea586a5f033133ae2e83cd', + 75484, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ffc0cf7832a52fdacc4833c2d951e529281b9eb803b1eeac14f4e69a0b5d1f7', + 74932, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Signika', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Signika font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Signika + static TextTheme signikaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.signika(textStyle: textTheme.headline1), + headline2: GoogleFonts.signika(textStyle: textTheme.headline2), + headline3: GoogleFonts.signika(textStyle: textTheme.headline3), + headline4: GoogleFonts.signika(textStyle: textTheme.headline4), + headline5: GoogleFonts.signika(textStyle: textTheme.headline5), + headline6: GoogleFonts.signika(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.signika(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.signika(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.signika(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.signika(textStyle: textTheme.bodyText2), + caption: GoogleFonts.signika(textStyle: textTheme.caption), + button: GoogleFonts.signika(textStyle: textTheme.button), + overline: GoogleFonts.signika(textStyle: textTheme.overline), + ); + } + + /// Applies the Signika Negative font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Signika+Negative + static TextStyle signikaNegative({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8a98587d6b5889382e0756db0404bae7fab53cd05d1ed3acfe5d2e92ce054710', + 54576, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4dafecef4dffed68c6467a6368c16342c151a400ebf2e1d10c208843e0f7f4f2', + 53324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '00703f7e2d564d97ed7ae01055939e32779956267e52d2c91697d4c58571d0a3', + 52908, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '49c7f19df1afc9e1068c8860087405401cf9a4d406cfc46b15013bbb95ecb2e4', + 53108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SignikaNegative', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Signika Negative font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Signika+Negative + static TextTheme signikaNegativeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.signikaNegative(textStyle: textTheme.headline1), + headline2: GoogleFonts.signikaNegative(textStyle: textTheme.headline2), + headline3: GoogleFonts.signikaNegative(textStyle: textTheme.headline3), + headline4: GoogleFonts.signikaNegative(textStyle: textTheme.headline4), + headline5: GoogleFonts.signikaNegative(textStyle: textTheme.headline5), + headline6: GoogleFonts.signikaNegative(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.signikaNegative(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.signikaNegative(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.signikaNegative(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.signikaNegative(textStyle: textTheme.bodyText2), + caption: GoogleFonts.signikaNegative(textStyle: textTheme.caption), + button: GoogleFonts.signikaNegative(textStyle: textTheme.button), + overline: GoogleFonts.signikaNegative(textStyle: textTheme.overline), + ); + } + + /// Applies the Simonetta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Simonetta + static TextStyle simonetta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd055b6397968d2e7b9a9c70b4e5d12a390ae937fbb2c140c5a2ca2bcb019501f', + 46244, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dbbbd6a2dedbac1c09bf69696a69adec943f3ac81e9a4b6cedf0fab0beee274e', + 42592, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2f9dab867c54e03c7203dae54a40e8233843e6ed0c74e9f1c939a0c3ff6e48ef', + 56952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b59c51c3445243e941c14dbc3663f87d2ffaa11e037d4eca6d8cc9103048d478', + 61084, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Simonetta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Simonetta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Simonetta + static TextTheme simonettaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.simonetta(textStyle: textTheme.headline1), + headline2: GoogleFonts.simonetta(textStyle: textTheme.headline2), + headline3: GoogleFonts.simonetta(textStyle: textTheme.headline3), + headline4: GoogleFonts.simonetta(textStyle: textTheme.headline4), + headline5: GoogleFonts.simonetta(textStyle: textTheme.headline5), + headline6: GoogleFonts.simonetta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.simonetta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.simonetta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.simonetta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.simonetta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.simonetta(textStyle: textTheme.caption), + button: GoogleFonts.simonetta(textStyle: textTheme.button), + overline: GoogleFonts.simonetta(textStyle: textTheme.overline), + ); + } + + /// Applies the Single Day font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Single+Day + static TextStyle singleDay({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b02bca0a89e3562bbfc779b333184a73ca6652a644aec2ca6113185f3fd7c413', + 638184, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SingleDay', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Single Day font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Single+Day + static TextTheme singleDayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.singleDay(textStyle: textTheme.headline1), + headline2: GoogleFonts.singleDay(textStyle: textTheme.headline2), + headline3: GoogleFonts.singleDay(textStyle: textTheme.headline3), + headline4: GoogleFonts.singleDay(textStyle: textTheme.headline4), + headline5: GoogleFonts.singleDay(textStyle: textTheme.headline5), + headline6: GoogleFonts.singleDay(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.singleDay(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.singleDay(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.singleDay(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.singleDay(textStyle: textTheme.bodyText2), + caption: GoogleFonts.singleDay(textStyle: textTheme.caption), + button: GoogleFonts.singleDay(textStyle: textTheme.button), + overline: GoogleFonts.singleDay(textStyle: textTheme.overline), + ); + } + + /// Applies the Sintony font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sintony + static TextStyle sintony({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '69767c8fec4cb9cf66b8022ffc9f15e99f1b4f6a15c1412ba8974fd55969ffa1', + 25664, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9c0d2538023d9d221278dc34698930aa90cd23ba0e8b8516986c6c7d88e03a3b', + 25968, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sintony', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sintony font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sintony + static TextTheme sintonyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sintony(textStyle: textTheme.headline1), + headline2: GoogleFonts.sintony(textStyle: textTheme.headline2), + headline3: GoogleFonts.sintony(textStyle: textTheme.headline3), + headline4: GoogleFonts.sintony(textStyle: textTheme.headline4), + headline5: GoogleFonts.sintony(textStyle: textTheme.headline5), + headline6: GoogleFonts.sintony(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sintony(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sintony(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sintony(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sintony(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sintony(textStyle: textTheme.caption), + button: GoogleFonts.sintony(textStyle: textTheme.button), + overline: GoogleFonts.sintony(textStyle: textTheme.overline), + ); + } + + /// Applies the Sirin Stencil font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sirin+Stencil + static TextStyle sirinStencil({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '49b8495ba38ff41cb2fe6ffa19be0105173e6318d239a91687520ba2ed2b5cbc', + 45740, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SirinStencil', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sirin Stencil font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sirin+Stencil + static TextTheme sirinStencilTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sirinStencil(textStyle: textTheme.headline1), + headline2: GoogleFonts.sirinStencil(textStyle: textTheme.headline2), + headline3: GoogleFonts.sirinStencil(textStyle: textTheme.headline3), + headline4: GoogleFonts.sirinStencil(textStyle: textTheme.headline4), + headline5: GoogleFonts.sirinStencil(textStyle: textTheme.headline5), + headline6: GoogleFonts.sirinStencil(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sirinStencil(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sirinStencil(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sirinStencil(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sirinStencil(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sirinStencil(textStyle: textTheme.caption), + button: GoogleFonts.sirinStencil(textStyle: textTheme.button), + overline: GoogleFonts.sirinStencil(textStyle: textTheme.overline), + ); + } + + /// Applies the Six Caps font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Six+Caps + static TextStyle sixCaps({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ecba544210f8553e76664f6e55b95afb42c005696628af22f50b59b88678debd', + 28656, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SixCaps', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Six Caps font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Six+Caps + static TextTheme sixCapsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sixCaps(textStyle: textTheme.headline1), + headline2: GoogleFonts.sixCaps(textStyle: textTheme.headline2), + headline3: GoogleFonts.sixCaps(textStyle: textTheme.headline3), + headline4: GoogleFonts.sixCaps(textStyle: textTheme.headline4), + headline5: GoogleFonts.sixCaps(textStyle: textTheme.headline5), + headline6: GoogleFonts.sixCaps(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sixCaps(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sixCaps(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sixCaps(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sixCaps(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sixCaps(textStyle: textTheme.caption), + button: GoogleFonts.sixCaps(textStyle: textTheme.button), + overline: GoogleFonts.sixCaps(textStyle: textTheme.overline), + ); + } + + /// Applies the Skranji font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Skranji + static TextStyle skranji({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9ee2c9312ee6ae5db2fdf49b0a797da03bd5ae1df447d051b081612b3db1d2fd', + 207480, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7dd8ded95fc8d9be6c80296a989eb3057929d548770081d17653c90dc11d8248', + 206848, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Skranji', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Skranji font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Skranji + static TextTheme skranjiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.skranji(textStyle: textTheme.headline1), + headline2: GoogleFonts.skranji(textStyle: textTheme.headline2), + headline3: GoogleFonts.skranji(textStyle: textTheme.headline3), + headline4: GoogleFonts.skranji(textStyle: textTheme.headline4), + headline5: GoogleFonts.skranji(textStyle: textTheme.headline5), + headline6: GoogleFonts.skranji(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.skranji(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.skranji(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.skranji(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.skranji(textStyle: textTheme.bodyText2), + caption: GoogleFonts.skranji(textStyle: textTheme.caption), + button: GoogleFonts.skranji(textStyle: textTheme.button), + overline: GoogleFonts.skranji(textStyle: textTheme.overline), + ); + } + + /// Applies the Slabo 13px font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Slabo+13px + static TextStyle slabo13px({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '55c7ef45e832252817233d906300e1087c565a52b4cedecffcf03d7edb86f694', + 32100, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Slabo13px', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Slabo 13px font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Slabo+13px + static TextTheme slabo13pxTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.slabo13px(textStyle: textTheme.headline1), + headline2: GoogleFonts.slabo13px(textStyle: textTheme.headline2), + headline3: GoogleFonts.slabo13px(textStyle: textTheme.headline3), + headline4: GoogleFonts.slabo13px(textStyle: textTheme.headline4), + headline5: GoogleFonts.slabo13px(textStyle: textTheme.headline5), + headline6: GoogleFonts.slabo13px(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.slabo13px(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.slabo13px(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.slabo13px(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.slabo13px(textStyle: textTheme.bodyText2), + caption: GoogleFonts.slabo13px(textStyle: textTheme.caption), + button: GoogleFonts.slabo13px(textStyle: textTheme.button), + overline: GoogleFonts.slabo13px(textStyle: textTheme.overline), + ); + } + + /// Applies the Slabo 27px font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Slabo+27px + static TextStyle slabo27px({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e451771d704b04c776176b6033f4c66aaab3edf2422d0811687a7f9b53c03486', + 33960, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Slabo27px', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Slabo 27px font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Slabo+27px + static TextTheme slabo27pxTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.slabo27px(textStyle: textTheme.headline1), + headline2: GoogleFonts.slabo27px(textStyle: textTheme.headline2), + headline3: GoogleFonts.slabo27px(textStyle: textTheme.headline3), + headline4: GoogleFonts.slabo27px(textStyle: textTheme.headline4), + headline5: GoogleFonts.slabo27px(textStyle: textTheme.headline5), + headline6: GoogleFonts.slabo27px(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.slabo27px(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.slabo27px(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.slabo27px(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.slabo27px(textStyle: textTheme.bodyText2), + caption: GoogleFonts.slabo27px(textStyle: textTheme.caption), + button: GoogleFonts.slabo27px(textStyle: textTheme.button), + overline: GoogleFonts.slabo27px(textStyle: textTheme.overline), + ); + } + + /// Applies the Slackey font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Slackey + static TextStyle slackey({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bceb941e47abbef80f27aebbdcb657e241b5ea1f17923b61537b6f64ff87af62', + 37516, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Slackey', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Slackey font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Slackey + static TextTheme slackeyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.slackey(textStyle: textTheme.headline1), + headline2: GoogleFonts.slackey(textStyle: textTheme.headline2), + headline3: GoogleFonts.slackey(textStyle: textTheme.headline3), + headline4: GoogleFonts.slackey(textStyle: textTheme.headline4), + headline5: GoogleFonts.slackey(textStyle: textTheme.headline5), + headline6: GoogleFonts.slackey(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.slackey(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.slackey(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.slackey(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.slackey(textStyle: textTheme.bodyText2), + caption: GoogleFonts.slackey(textStyle: textTheme.caption), + button: GoogleFonts.slackey(textStyle: textTheme.button), + overline: GoogleFonts.slackey(textStyle: textTheme.overline), + ); + } + + /// Applies the Smokum font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Smokum + static TextStyle smokum({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2c700a4722b34ec677fb0c4c7ae242886cead014ec06aef3e02dc311def9ccbb', + 63924, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Smokum', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Smokum font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Smokum + static TextTheme smokumTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.smokum(textStyle: textTheme.headline1), + headline2: GoogleFonts.smokum(textStyle: textTheme.headline2), + headline3: GoogleFonts.smokum(textStyle: textTheme.headline3), + headline4: GoogleFonts.smokum(textStyle: textTheme.headline4), + headline5: GoogleFonts.smokum(textStyle: textTheme.headline5), + headline6: GoogleFonts.smokum(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.smokum(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.smokum(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.smokum(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.smokum(textStyle: textTheme.bodyText2), + caption: GoogleFonts.smokum(textStyle: textTheme.caption), + button: GoogleFonts.smokum(textStyle: textTheme.button), + overline: GoogleFonts.smokum(textStyle: textTheme.overline), + ); + } + + /// Applies the Smythe font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Smythe + static TextStyle smythe({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1f1e3d2a79f5bdab563797693fd14a8c6e868b0778cf746e4a4d22aedc216dbc', + 64160, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Smythe', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Smythe font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Smythe + static TextTheme smytheTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.smythe(textStyle: textTheme.headline1), + headline2: GoogleFonts.smythe(textStyle: textTheme.headline2), + headline3: GoogleFonts.smythe(textStyle: textTheme.headline3), + headline4: GoogleFonts.smythe(textStyle: textTheme.headline4), + headline5: GoogleFonts.smythe(textStyle: textTheme.headline5), + headline6: GoogleFonts.smythe(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.smythe(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.smythe(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.smythe(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.smythe(textStyle: textTheme.bodyText2), + caption: GoogleFonts.smythe(textStyle: textTheme.caption), + button: GoogleFonts.smythe(textStyle: textTheme.button), + overline: GoogleFonts.smythe(textStyle: textTheme.overline), + ); + } + + /// Applies the Sniglet font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sniglet + static TextStyle sniglet({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '106613b6566b3b9a696c095879b31e220c39d60c508dae033b5f3680aaa48732', + 51356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '439b0ab4a7a1d2a1328cc8eb52d10167325643f9c15a187d3d7650cdd15cf896', + 54768, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sniglet', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sniglet font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sniglet + static TextTheme snigletTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sniglet(textStyle: textTheme.headline1), + headline2: GoogleFonts.sniglet(textStyle: textTheme.headline2), + headline3: GoogleFonts.sniglet(textStyle: textTheme.headline3), + headline4: GoogleFonts.sniglet(textStyle: textTheme.headline4), + headline5: GoogleFonts.sniglet(textStyle: textTheme.headline5), + headline6: GoogleFonts.sniglet(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sniglet(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sniglet(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sniglet(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sniglet(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sniglet(textStyle: textTheme.caption), + button: GoogleFonts.sniglet(textStyle: textTheme.button), + overline: GoogleFonts.sniglet(textStyle: textTheme.overline), + ); + } + + /// Applies the Snippet font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Snippet + static TextStyle snippet({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8cc4ae1951b9917cd740fe17346eee27c893d200ad251063c1aa3c48b6e02682', + 39260, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Snippet', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Snippet font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Snippet + static TextTheme snippetTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.snippet(textStyle: textTheme.headline1), + headline2: GoogleFonts.snippet(textStyle: textTheme.headline2), + headline3: GoogleFonts.snippet(textStyle: textTheme.headline3), + headline4: GoogleFonts.snippet(textStyle: textTheme.headline4), + headline5: GoogleFonts.snippet(textStyle: textTheme.headline5), + headline6: GoogleFonts.snippet(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.snippet(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.snippet(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.snippet(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.snippet(textStyle: textTheme.bodyText2), + caption: GoogleFonts.snippet(textStyle: textTheme.caption), + button: GoogleFonts.snippet(textStyle: textTheme.button), + overline: GoogleFonts.snippet(textStyle: textTheme.overline), + ); + } + + /// Applies the Snowburst One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Snowburst+One + static TextStyle snowburstOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f0b3d75c3024cdb3e14b5006a726dacaa747fd5b1436d7123f63ed83d1d60e28', + 54060, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SnowburstOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Snowburst One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Snowburst+One + static TextTheme snowburstOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.snowburstOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.snowburstOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.snowburstOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.snowburstOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.snowburstOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.snowburstOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.snowburstOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.snowburstOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.snowburstOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.snowburstOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.snowburstOne(textStyle: textTheme.caption), + button: GoogleFonts.snowburstOne(textStyle: textTheme.button), + overline: GoogleFonts.snowburstOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Sofadi One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sofadi+One + static TextStyle sofadiOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bd2ee7258a722de3e36e84a9aadf3edfe4b91221f382e3e5bbe75b786119526f', + 34584, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SofadiOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sofadi One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sofadi+One + static TextTheme sofadiOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sofadiOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.sofadiOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.sofadiOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.sofadiOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.sofadiOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.sofadiOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sofadiOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sofadiOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sofadiOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sofadiOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sofadiOne(textStyle: textTheme.caption), + button: GoogleFonts.sofadiOne(textStyle: textTheme.button), + overline: GoogleFonts.sofadiOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Sofia font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sofia + static TextStyle sofia({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ca5d81d1b4b38fae521b80e8ab25a7632893d98285e79fa51e53975b807afcb1', + 29748, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sofia', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sofia font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sofia + static TextTheme sofiaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sofia(textStyle: textTheme.headline1), + headline2: GoogleFonts.sofia(textStyle: textTheme.headline2), + headline3: GoogleFonts.sofia(textStyle: textTheme.headline3), + headline4: GoogleFonts.sofia(textStyle: textTheme.headline4), + headline5: GoogleFonts.sofia(textStyle: textTheme.headline5), + headline6: GoogleFonts.sofia(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sofia(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sofia(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sofia(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sofia(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sofia(textStyle: textTheme.caption), + button: GoogleFonts.sofia(textStyle: textTheme.button), + overline: GoogleFonts.sofia(textStyle: textTheme.overline), + ); + } + + /// Applies the Solway font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Solway + static TextStyle solway({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '30f12e709261a80d1a2f35d02c568e8080aa52e556cea38ec163ee09a6482606', + 34188, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bc55ce65a041c9b5001bb030477677f6a44eeb3946a418259202a162382044d2', + 36536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c03b2ecebe399988e043ffcd0707d72b1327076b7c0f255c24c88e453a8163eb', + 36536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd3b46e3ef557420e377ce5924289b7f1987a6a99f5625aa5e6ef6f74002198fd', + 37076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6be411cbc685fc6716528e253c309c7af939f60f2bf83919a384384ee527a079', + 37408, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Solway', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Solway font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Solway + static TextTheme solwayTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.solway(textStyle: textTheme.headline1), + headline2: GoogleFonts.solway(textStyle: textTheme.headline2), + headline3: GoogleFonts.solway(textStyle: textTheme.headline3), + headline4: GoogleFonts.solway(textStyle: textTheme.headline4), + headline5: GoogleFonts.solway(textStyle: textTheme.headline5), + headline6: GoogleFonts.solway(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.solway(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.solway(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.solway(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.solway(textStyle: textTheme.bodyText2), + caption: GoogleFonts.solway(textStyle: textTheme.caption), + button: GoogleFonts.solway(textStyle: textTheme.button), + overline: GoogleFonts.solway(textStyle: textTheme.overline), + ); + } + + /// Applies the Song Myung font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Song+Myung + static TextStyle songMyung({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '45407348eb54e83212eddfa7ad22cd18d0f75783316406f08beb532a835bc3f4', + 1202620, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SongMyung', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Song Myung font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Song+Myung + static TextTheme songMyungTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.songMyung(textStyle: textTheme.headline1), + headline2: GoogleFonts.songMyung(textStyle: textTheme.headline2), + headline3: GoogleFonts.songMyung(textStyle: textTheme.headline3), + headline4: GoogleFonts.songMyung(textStyle: textTheme.headline4), + headline5: GoogleFonts.songMyung(textStyle: textTheme.headline5), + headline6: GoogleFonts.songMyung(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.songMyung(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.songMyung(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.songMyung(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.songMyung(textStyle: textTheme.bodyText2), + caption: GoogleFonts.songMyung(textStyle: textTheme.caption), + button: GoogleFonts.songMyung(textStyle: textTheme.button), + overline: GoogleFonts.songMyung(textStyle: textTheme.overline), + ); + } + + /// Applies the Sonsie One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sonsie+One + static TextStyle sonsieOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a621714ea4d59e0ead90246169593f8487db34752634db76b12ab329e9cf4e1', + 75992, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SonsieOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sonsie One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sonsie+One + static TextTheme sonsieOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sonsieOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.sonsieOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.sonsieOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.sonsieOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.sonsieOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.sonsieOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sonsieOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sonsieOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sonsieOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sonsieOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sonsieOne(textStyle: textTheme.caption), + button: GoogleFonts.sonsieOne(textStyle: textTheme.button), + overline: GoogleFonts.sonsieOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Sora font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sora + static TextStyle sora({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '64d4cbd26de694ec801ad917d3c5a43436ee7982fad956e6d6d748adef743ecd', + 43136, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '10e1f33d3a9eb7b9084257e3150626d0e5ae65963784367ae211693196fb350c', + 43196, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b745f6732aacc43ddac8ec3bab7443f3af6da26663557ea6838d0e7462031ff4', + 43140, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8fdab44c4a4386999298b584aa1f206f953a2fb931a2ee6ec38899f5db10a39d', + 43104, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fc19fd9674df1fd4ca7db321338aab809eaa602467812b10823dd95039445192', + 43108, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f60d0ed209fbf16025ff3c8f81fa826e24fd3b7a0c106d7f5035523dc91df799', + 43124, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c05902680317d01f35b1b110da938465cb8fc85c4606c7d1dca71e17f49a4872', + 43052, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5f3b77615262ef6157c6dbbfaef740184837e7c012009d8d3251fba62561d938', + 43100, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sora', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sora font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sora + static TextTheme soraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sora(textStyle: textTheme.headline1), + headline2: GoogleFonts.sora(textStyle: textTheme.headline2), + headline3: GoogleFonts.sora(textStyle: textTheme.headline3), + headline4: GoogleFonts.sora(textStyle: textTheme.headline4), + headline5: GoogleFonts.sora(textStyle: textTheme.headline5), + headline6: GoogleFonts.sora(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sora(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sora(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sora(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sora(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sora(textStyle: textTheme.caption), + button: GoogleFonts.sora(textStyle: textTheme.button), + overline: GoogleFonts.sora(textStyle: textTheme.overline), + ); + } + + /// Applies the Sorts Mill Goudy font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sorts+Mill+Goudy + static TextStyle sortsMillGoudy({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '70d3ad626ef92c3b9eeaff7e3694af6d64f477a31ab242d11f98704e9903a065', + 121324, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd8d1d17c5bffaec08a5c129dfdbd62c0a538de036da120d20edef29019f0b5bf', + 105636, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SortsMillGoudy', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sorts Mill Goudy font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sorts+Mill+Goudy + static TextTheme sortsMillGoudyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sortsMillGoudy(textStyle: textTheme.headline1), + headline2: GoogleFonts.sortsMillGoudy(textStyle: textTheme.headline2), + headline3: GoogleFonts.sortsMillGoudy(textStyle: textTheme.headline3), + headline4: GoogleFonts.sortsMillGoudy(textStyle: textTheme.headline4), + headline5: GoogleFonts.sortsMillGoudy(textStyle: textTheme.headline5), + headline6: GoogleFonts.sortsMillGoudy(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sortsMillGoudy(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sortsMillGoudy(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sortsMillGoudy(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sortsMillGoudy(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sortsMillGoudy(textStyle: textTheme.caption), + button: GoogleFonts.sortsMillGoudy(textStyle: textTheme.button), + overline: GoogleFonts.sortsMillGoudy(textStyle: textTheme.overline), + ); + } + + /// Applies the Source Code Pro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Source+Code+Pro + static TextStyle sourceCodePro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5a618360951a8134d26923216c53da2cee51d55e6e2ca0003ecfe111b701bae5', + 87468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e0184502d4eb4b41dcd3d65fecad4fcf8b6b46f13967b60ac98eedcc43aacb30', + 87064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2d1bcd5038af1287746b7b1d1a4db65f091b3e9811428076d43a73121893922d', + 86408, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '18daf5f11e4f1462c2a5b5f8e439dfce5a846e27eff21a622f9031f58d257aa2', + 85948, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '807061463bc4cdacd2299a10cc0b7862e4a925cb984fec0016307fea9df6aa78', + 85956, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '51b4ad25947aa6ab4e72faea203ad4b74e4de08b9bbc4d254cdd9dc26dfc2d19', + 86076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '677bde76eea8889e4ec713ec738f7fadd150aee2ffca36efb65946a45e6b93cc', + 86280, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SourceCodePro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Source Code Pro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Source+Code+Pro + static TextTheme sourceCodeProTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sourceCodePro(textStyle: textTheme.headline1), + headline2: GoogleFonts.sourceCodePro(textStyle: textTheme.headline2), + headline3: GoogleFonts.sourceCodePro(textStyle: textTheme.headline3), + headline4: GoogleFonts.sourceCodePro(textStyle: textTheme.headline4), + headline5: GoogleFonts.sourceCodePro(textStyle: textTheme.headline5), + headline6: GoogleFonts.sourceCodePro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sourceCodePro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sourceCodePro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sourceCodePro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sourceCodePro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sourceCodePro(textStyle: textTheme.caption), + button: GoogleFonts.sourceCodePro(textStyle: textTheme.button), + overline: GoogleFonts.sourceCodePro(textStyle: textTheme.overline), + ); + } + + /// Applies the Source Sans Pro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Source+Sans+Pro + static TextStyle sourceSansPro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '069aaad5d271d9417c8b97f8312f686cf5a9a41a8e3644b572c60c8e176ed7e0', + 233472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1538944579d3bc333bfe34ed45c1db572897fcf695af75f4e45ef5ac42c3aa12', + 84024, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bb276921895494650544883e21f7d2bc91ec918522ac3d355582b0cd472592cc', + 234308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c068f601e24f3e8ced3014cb3dc4a32022c06af8e27ca870d6c76432d280e75a', + 83820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6ed615e8d0355256e2d6d907b3addb929879c90c8383dd566b2208c79ffd16f7', + 234740, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e35d7fde727174172e9689f4584ff9e4559a37ca0b39b096fa72f0f657b31bc9', + 83244, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5629ccf5ed16fa41c51a964b882a8e1e1e395a714906a90567278bd0c439ecc1', + 233912, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e8bcda13818deef42d6e19f3009f6e18a595746c5dcc1d35c56280c5dea32b21', + 83064, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6b9e7872867a9a0fca2083e62b2c39727a93c81b736fb1e21cc1c29ba89008ff', + 233516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f417993b734490d591dd2a3f10022f8ff1a376876eeca00098baf25759b2522b', + 82856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1d969d176ba4ea2075fe69e5b9799e9dbc146889092823d49453241c80e93a2a', + 231580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '954080abe4fffebb675bea9c34eb0d873cf25f8674e9d55cde4c9c962f44a421', + 83000, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SourceSansPro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Source Sans Pro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Source+Sans+Pro + static TextTheme sourceSansProTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sourceSansPro(textStyle: textTheme.headline1), + headline2: GoogleFonts.sourceSansPro(textStyle: textTheme.headline2), + headline3: GoogleFonts.sourceSansPro(textStyle: textTheme.headline3), + headline4: GoogleFonts.sourceSansPro(textStyle: textTheme.headline4), + headline5: GoogleFonts.sourceSansPro(textStyle: textTheme.headline5), + headline6: GoogleFonts.sourceSansPro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sourceSansPro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sourceSansPro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sourceSansPro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sourceSansPro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sourceSansPro(textStyle: textTheme.caption), + button: GoogleFonts.sourceSansPro(textStyle: textTheme.button), + overline: GoogleFonts.sourceSansPro(textStyle: textTheme.overline), + ); + } + + /// Applies the Source Serif Pro font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Source+Serif+Pro + static TextStyle sourceSerifPro({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f87f7b82ba7f18f5fc9e92b9a88f9da0c847cee069182948fc67c6440c888949', + 87572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '21ba3c9624cb12920db48bb25f0e1db9398acab0031d2ae8f13b8628f4d02740', + 88436, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eb04de6aca072d01a88545fa409c6264d93f9b38f86a0ecd3a00708917085bd8', + 87152, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SourceSerifPro', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Source Serif Pro font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Source+Serif+Pro + static TextTheme sourceSerifProTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sourceSerifPro(textStyle: textTheme.headline1), + headline2: GoogleFonts.sourceSerifPro(textStyle: textTheme.headline2), + headline3: GoogleFonts.sourceSerifPro(textStyle: textTheme.headline3), + headline4: GoogleFonts.sourceSerifPro(textStyle: textTheme.headline4), + headline5: GoogleFonts.sourceSerifPro(textStyle: textTheme.headline5), + headline6: GoogleFonts.sourceSerifPro(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sourceSerifPro(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sourceSerifPro(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sourceSerifPro(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sourceSerifPro(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sourceSerifPro(textStyle: textTheme.caption), + button: GoogleFonts.sourceSerifPro(textStyle: textTheme.button), + overline: GoogleFonts.sourceSerifPro(textStyle: textTheme.overline), + ); + } + + /// Applies the Space Grotesk font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Space+Grotesk + static TextStyle spaceGrotesk({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '78538bc64b6fc5ae6669761b5cdd3506b0158c3146a0dbf75ce7894cfc32f43f', + 62548, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ac7df787842e477e1f25aea92d7a62eebddab6df822e91fc12d846d93de3ed98', + 62500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '25f055989d0add3601ef96ee9e16a6b16d56789d7e1d9152b85c304361144659', + 62532, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'be5fd5b8b5cce95f3932d341f4ab214a0fdb5a5b572a6b7736cd23e6a6b51ac9', + 62488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cc1c7851cb7fdc9a545caf729159ed3a5647debd7ae514283a8e831b9b0b29ab', + 62432, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SpaceGrotesk', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Space Grotesk font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Space+Grotesk + static TextTheme spaceGroteskTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.spaceGrotesk(textStyle: textTheme.headline1), + headline2: GoogleFonts.spaceGrotesk(textStyle: textTheme.headline2), + headline3: GoogleFonts.spaceGrotesk(textStyle: textTheme.headline3), + headline4: GoogleFonts.spaceGrotesk(textStyle: textTheme.headline4), + headline5: GoogleFonts.spaceGrotesk(textStyle: textTheme.headline5), + headline6: GoogleFonts.spaceGrotesk(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.spaceGrotesk(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.spaceGrotesk(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.spaceGrotesk(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.spaceGrotesk(textStyle: textTheme.bodyText2), + caption: GoogleFonts.spaceGrotesk(textStyle: textTheme.caption), + button: GoogleFonts.spaceGrotesk(textStyle: textTheme.button), + overline: GoogleFonts.spaceGrotesk(textStyle: textTheme.overline), + ); + } + + /// Applies the Space Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Space+Mono + static TextStyle spaceMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1308fd8bd0f79e0517319bf0429226dfce5ae67beb495577737524f29b537527', + 62960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '461bb1d5b84d057c522eedf582e3704890be96aed239020438b09168f8ef296b', + 69728, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d1e9fe7ab3138b3f1465d1b1afc457934abae86c1803611dbbcfd28f5f97e2b', + 61696, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ec50d2d9cc5bbed72fae03e2bc8a720e2cca1324f8bc99b30089d51896917f0e', + 66880, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SpaceMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Space Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Space+Mono + static TextTheme spaceMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.spaceMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.spaceMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.spaceMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.spaceMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.spaceMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.spaceMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.spaceMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.spaceMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.spaceMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.spaceMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.spaceMono(textStyle: textTheme.caption), + button: GoogleFonts.spaceMono(textStyle: textTheme.button), + overline: GoogleFonts.spaceMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Spartan font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spartan + static TextStyle spartan({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4869cf7b66d0abcfafa64d169a39a8d60f681ae939db8334f68920cadb32601d', + 34308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '46bd04dc18fcff69cd6119022da0ed080ab1f747a043ae642cd1f09687377059', + 34392, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8b99bb8f62db78d7bce20b083bd51aa4f624f859741f6d6cb1377c1b4e8849d3', + 34356, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'de5f4b08f5a84e557927cdef6b4a25c339dd1d76a2011f735151de162d44a19f', + 34276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd105bc50e2051f3f0a3e4ffd1bc4e0dc3d766607e557c3b6f1f26795a57176b5', + 34252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '039cfc4f464367e72a155853e5a73a28674cb54d69def7e8a9e0079070d7f515', + 34276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '322f9c7edf2eb6257b5f37642d91307f821dff6cc6d4ee33d4629189b43b164f', + 34332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '60bd60c81e7531c33b4e0734ea135bd549841147edb59355003ac9b01c5dcfdb', + 34472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4fa2cc56e1f8204b4487730ab9ea24620b0649fe9ccd37048feebd3230c02cad', + 34500, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Spartan', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Spartan font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spartan + static TextTheme spartanTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.spartan(textStyle: textTheme.headline1), + headline2: GoogleFonts.spartan(textStyle: textTheme.headline2), + headline3: GoogleFonts.spartan(textStyle: textTheme.headline3), + headline4: GoogleFonts.spartan(textStyle: textTheme.headline4), + headline5: GoogleFonts.spartan(textStyle: textTheme.headline5), + headline6: GoogleFonts.spartan(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.spartan(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.spartan(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.spartan(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.spartan(textStyle: textTheme.bodyText2), + caption: GoogleFonts.spartan(textStyle: textTheme.caption), + button: GoogleFonts.spartan(textStyle: textTheme.button), + overline: GoogleFonts.spartan(textStyle: textTheme.overline), + ); + } + + /// Applies the Special Elite font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Special+Elite + static TextStyle specialElite({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a1b32a7d4f38d2ebfa68de6ead2295ba312231237e0088e5d4fc3e1c66a516d', + 165808, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SpecialElite', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Special Elite font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Special+Elite + static TextTheme specialEliteTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.specialElite(textStyle: textTheme.headline1), + headline2: GoogleFonts.specialElite(textStyle: textTheme.headline2), + headline3: GoogleFonts.specialElite(textStyle: textTheme.headline3), + headline4: GoogleFonts.specialElite(textStyle: textTheme.headline4), + headline5: GoogleFonts.specialElite(textStyle: textTheme.headline5), + headline6: GoogleFonts.specialElite(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.specialElite(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.specialElite(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.specialElite(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.specialElite(textStyle: textTheme.bodyText2), + caption: GoogleFonts.specialElite(textStyle: textTheme.caption), + button: GoogleFonts.specialElite(textStyle: textTheme.button), + overline: GoogleFonts.specialElite(textStyle: textTheme.overline), + ); + } + + /// Applies the Spectral font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spectral + static TextStyle spectral({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '38faebd2b01ddd2e497f09028eb10210de56ffadde5c5842c2f70a195865e869', + 199076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3ee03dc791594673ce8b752c95ef9d29d66d2afb3777a862edd4e9886ceff42a', + 220088, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '877b7e52c3c9951be21132edc23e99f7b227c3cf6a6189a349ea4195a5ca645d', + 227408, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3fceb0d465d8e2d6c3b28408281c75b8a55b5228875d262f65cafbf9f89aa1b5', + 240880, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cf0966737e7520da7784b9dfadc8744a34d7d90ab9d90ee290f28a8b29b868ea', + 221072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9ba9b61cb4417f86b861d19cadc70e612a8e32596f88e9eaf7f65a33ac37e363', + 230908, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91b2985ae69deaca521a82b390a544247f735dfd48b0338fa92a1ab42a0a6414', + 233368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '47041fa850a2c3190804212d1ffe2e590aef6306201b9cff1c6bc798da3ea255', + 241960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '04a313e8c2f5ac831e7298c25c6075b9660a810569519797c226baede971cda1', + 233468, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '85a9ddd0720f69c9da803991658683f387f75a2d200989f17e4c84f03353a73f', + 241720, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '49302f1176eef815c75aec07833e13b9758532914b49c1993e9b619638ebcfd8', + 233260, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '8f82f95515722a631616d0b69effe11da9717cf7eea641359596c20dbe87a7ca', + 242076, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8a965c3cce6911f473a1523ad68029f95071a6aaabe726bf72ff4f9ed5455f0e', + 221968, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '528018df6d31607eec08ae87cd710edd29678dd7b9a2946b21fe5c2f725d95e5', + 230424, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Spectral', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Spectral font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spectral + static TextTheme spectralTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.spectral(textStyle: textTheme.headline1), + headline2: GoogleFonts.spectral(textStyle: textTheme.headline2), + headline3: GoogleFonts.spectral(textStyle: textTheme.headline3), + headline4: GoogleFonts.spectral(textStyle: textTheme.headline4), + headline5: GoogleFonts.spectral(textStyle: textTheme.headline5), + headline6: GoogleFonts.spectral(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.spectral(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.spectral(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.spectral(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.spectral(textStyle: textTheme.bodyText2), + caption: GoogleFonts.spectral(textStyle: textTheme.caption), + button: GoogleFonts.spectral(textStyle: textTheme.button), + overline: GoogleFonts.spectral(textStyle: textTheme.overline), + ); + } + + /// Applies the Spectral SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spectral+SC + static TextStyle spectralSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '63d4dd9a1b6ca94347d9be458d3d3f27437804fcdcf96de19115ce63eab80e09', + 199108, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1940514dc53b85d4d87e4f9ea64470eb98c107c053377538d63a88cd7f3c90e5', + 220128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '891b1d15d1fd0adffff4ab8a71237e846a7facbe29b6fa94e95a2e2125a162b0', + 227440, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4a35ca51d42122c0e214b00754e3aabd760891dd4fe8f23e3211970b66fccde5', + 240920, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '992f8c6dff2fd1f14725272931fc3336a540546fa7846b3e278bd85836fb7545', + 221108, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0517c9389a7f90b8ee1d792ac8572855f7ec302e33658d957763f50fa551141f', + 230944, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ffddde35929f7228c85cec1b5c3e93f839d845a8f751a7aef1b27a53f7ed7d87', + 233400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'da37956c506e2a8bb47a1cefda935cc60a00a1735c34ec2727db59fd9f5c8f72', + 242000, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f7bfc53ad029c821a35bea359076f8a826719e43c0491aee00359e7acdf6d2fc', + 233500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1fb487f3103ff60bc6f5f01b422f906549ece9883a49e5b87c3be0dd78428e36', + 241760, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cb2b064297cc41a5df572410b58a26772056bf765768fc1a1510374bf5dea8e9', + 233296, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '380b7badc0bd105618648f3c7b9681a5e2c6a3b65569037a3c589e4a028aa6b3', + 242108, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cb4ff7e22c08a17af3b239331337982b0c9f8cad6207546a955a1ea2dadddf16', + 222000, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '379b67f997439e4df148b4cd426dd5ebe6ec642bcf4d4a74f192d664f97306f4', + 230464, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SpectralSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Spectral SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spectral+SC + static TextTheme spectralScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.spectralSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.spectralSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.spectralSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.spectralSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.spectralSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.spectralSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.spectralSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.spectralSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.spectralSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.spectralSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.spectralSc(textStyle: textTheme.caption), + button: GoogleFonts.spectralSc(textStyle: textTheme.button), + overline: GoogleFonts.spectralSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Spicy Rice font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spicy+Rice + static TextStyle spicyRice({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e097f53ad6ba5f9e022be6b68002e3d8ccd021b1b340e077113c6d537de3ab75', + 66828, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SpicyRice', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Spicy Rice font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spicy+Rice + static TextTheme spicyRiceTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.spicyRice(textStyle: textTheme.headline1), + headline2: GoogleFonts.spicyRice(textStyle: textTheme.headline2), + headline3: GoogleFonts.spicyRice(textStyle: textTheme.headline3), + headline4: GoogleFonts.spicyRice(textStyle: textTheme.headline4), + headline5: GoogleFonts.spicyRice(textStyle: textTheme.headline5), + headline6: GoogleFonts.spicyRice(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.spicyRice(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.spicyRice(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.spicyRice(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.spicyRice(textStyle: textTheme.bodyText2), + caption: GoogleFonts.spicyRice(textStyle: textTheme.caption), + button: GoogleFonts.spicyRice(textStyle: textTheme.button), + overline: GoogleFonts.spicyRice(textStyle: textTheme.overline), + ); + } + + /// Applies the Spinnaker font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spinnaker + static TextStyle spinnaker({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '086026fa129fbdfec07fc9736f5f1a5577d7c1a6f4cf1daa40f5a524db14db1d', + 22408, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Spinnaker', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Spinnaker font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spinnaker + static TextTheme spinnakerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.spinnaker(textStyle: textTheme.headline1), + headline2: GoogleFonts.spinnaker(textStyle: textTheme.headline2), + headline3: GoogleFonts.spinnaker(textStyle: textTheme.headline3), + headline4: GoogleFonts.spinnaker(textStyle: textTheme.headline4), + headline5: GoogleFonts.spinnaker(textStyle: textTheme.headline5), + headline6: GoogleFonts.spinnaker(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.spinnaker(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.spinnaker(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.spinnaker(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.spinnaker(textStyle: textTheme.bodyText2), + caption: GoogleFonts.spinnaker(textStyle: textTheme.caption), + button: GoogleFonts.spinnaker(textStyle: textTheme.button), + overline: GoogleFonts.spinnaker(textStyle: textTheme.overline), + ); + } + + /// Applies the Spirax font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spirax + static TextStyle spirax({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '165b0a7ca4871b5440455c3c991428f478c37eee5f78637905aceaa58275feda', + 49016, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Spirax', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Spirax font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Spirax + static TextTheme spiraxTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.spirax(textStyle: textTheme.headline1), + headline2: GoogleFonts.spirax(textStyle: textTheme.headline2), + headline3: GoogleFonts.spirax(textStyle: textTheme.headline3), + headline4: GoogleFonts.spirax(textStyle: textTheme.headline4), + headline5: GoogleFonts.spirax(textStyle: textTheme.headline5), + headline6: GoogleFonts.spirax(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.spirax(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.spirax(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.spirax(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.spirax(textStyle: textTheme.bodyText2), + caption: GoogleFonts.spirax(textStyle: textTheme.caption), + button: GoogleFonts.spirax(textStyle: textTheme.button), + overline: GoogleFonts.spirax(textStyle: textTheme.overline), + ); + } + + /// Applies the Squada One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Squada+One + static TextStyle squadaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd162c6edeab12c48ff421bd0de5d144ae2c1f762b16d00e4efb07d42b4847cbe', + 19024, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SquadaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Squada One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Squada+One + static TextTheme squadaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.squadaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.squadaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.squadaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.squadaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.squadaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.squadaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.squadaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.squadaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.squadaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.squadaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.squadaOne(textStyle: textTheme.caption), + button: GoogleFonts.squadaOne(textStyle: textTheme.button), + overline: GoogleFonts.squadaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Sree Krushnadevaraya font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sree+Krushnadevaraya + static TextStyle sreeKrushnadevaraya({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '380fee09dc7039f216c5208086c2919b9b332d06de401d60f4b57d8cba7e080e', + 410260, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SreeKrushnadevaraya', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sree Krushnadevaraya font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sree+Krushnadevaraya + static TextTheme sreeKrushnadevarayaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.headline1), + headline2: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.headline2), + headline3: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.headline3), + headline4: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.headline4), + headline5: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.headline5), + headline6: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.caption), + button: GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.button), + overline: GoogleFonts.sreeKrushnadevaraya(textStyle: textTheme.overline), + ); + } + + /// Applies the Sriracha font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sriracha + static TextStyle sriracha({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9b5c54ea181b3d73d0d289e4182c26d2a6cca9e06c00edd861a65a36f6b559e7', + 207108, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sriracha', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sriracha font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sriracha + static TextTheme srirachaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sriracha(textStyle: textTheme.headline1), + headline2: GoogleFonts.sriracha(textStyle: textTheme.headline2), + headline3: GoogleFonts.sriracha(textStyle: textTheme.headline3), + headline4: GoogleFonts.sriracha(textStyle: textTheme.headline4), + headline5: GoogleFonts.sriracha(textStyle: textTheme.headline5), + headline6: GoogleFonts.sriracha(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sriracha(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sriracha(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sriracha(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sriracha(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sriracha(textStyle: textTheme.caption), + button: GoogleFonts.sriracha(textStyle: textTheme.button), + overline: GoogleFonts.sriracha(textStyle: textTheme.overline), + ); + } + + /// Applies the Srisakdi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Srisakdi + static TextStyle srisakdi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5b078682ce7a5aa20cc137b975bd70e97752800f9ba9fc1761c050ef3bffc84a', + 96252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a3084b442fdea4ccce8907fe71e60006e0bcd2b686cd8c5d2c572d0483a1e27a', + 96120, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Srisakdi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Srisakdi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Srisakdi + static TextTheme srisakdiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.srisakdi(textStyle: textTheme.headline1), + headline2: GoogleFonts.srisakdi(textStyle: textTheme.headline2), + headline3: GoogleFonts.srisakdi(textStyle: textTheme.headline3), + headline4: GoogleFonts.srisakdi(textStyle: textTheme.headline4), + headline5: GoogleFonts.srisakdi(textStyle: textTheme.headline5), + headline6: GoogleFonts.srisakdi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.srisakdi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.srisakdi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.srisakdi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.srisakdi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.srisakdi(textStyle: textTheme.caption), + button: GoogleFonts.srisakdi(textStyle: textTheme.button), + overline: GoogleFonts.srisakdi(textStyle: textTheme.overline), + ); + } + + /// Applies the Staatliches font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Staatliches + static TextStyle staatliches({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2ae636039aa5e081cbad2b79ad512682296ab9af1a36078372db12f68f540ab8', + 42160, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Staatliches', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Staatliches font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Staatliches + static TextTheme staatlichesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.staatliches(textStyle: textTheme.headline1), + headline2: GoogleFonts.staatliches(textStyle: textTheme.headline2), + headline3: GoogleFonts.staatliches(textStyle: textTheme.headline3), + headline4: GoogleFonts.staatliches(textStyle: textTheme.headline4), + headline5: GoogleFonts.staatliches(textStyle: textTheme.headline5), + headline6: GoogleFonts.staatliches(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.staatliches(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.staatliches(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.staatliches(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.staatliches(textStyle: textTheme.bodyText2), + caption: GoogleFonts.staatliches(textStyle: textTheme.caption), + button: GoogleFonts.staatliches(textStyle: textTheme.button), + overline: GoogleFonts.staatliches(textStyle: textTheme.overline), + ); + } + + /// Applies the Stalemate font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stalemate + static TextStyle stalemate({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c98986a49a80ea3130e9eb7c16b9470c6295a26b0207da72e59c4c01ab9c369b', + 74940, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Stalemate', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Stalemate font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stalemate + static TextTheme stalemateTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.stalemate(textStyle: textTheme.headline1), + headline2: GoogleFonts.stalemate(textStyle: textTheme.headline2), + headline3: GoogleFonts.stalemate(textStyle: textTheme.headline3), + headline4: GoogleFonts.stalemate(textStyle: textTheme.headline4), + headline5: GoogleFonts.stalemate(textStyle: textTheme.headline5), + headline6: GoogleFonts.stalemate(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.stalemate(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.stalemate(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.stalemate(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.stalemate(textStyle: textTheme.bodyText2), + caption: GoogleFonts.stalemate(textStyle: textTheme.caption), + button: GoogleFonts.stalemate(textStyle: textTheme.button), + overline: GoogleFonts.stalemate(textStyle: textTheme.overline), + ); + } + + /// Applies the Stalinist One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stalinist+One + static TextStyle stalinistOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '87936ca01db4621bdb144a35bb1e89bc7e9b769a899d90ea618736467886c01d', + 30808, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'StalinistOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Stalinist One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stalinist+One + static TextTheme stalinistOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.stalinistOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.stalinistOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.stalinistOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.stalinistOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.stalinistOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.stalinistOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.stalinistOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.stalinistOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.stalinistOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.stalinistOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.stalinistOne(textStyle: textTheme.caption), + button: GoogleFonts.stalinistOne(textStyle: textTheme.button), + overline: GoogleFonts.stalinistOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Stardos Stencil font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stardos+Stencil + static TextStyle stardosStencil({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b677e9855e2ae2d05e70f39ac58d82bfe1f9ea6ecb62fcf63cc3c0f10c456ba9', + 44164, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b5b4ccf1291484af094cadfcd7fa357b84b8c25db613f74330c32b39a270fda1', + 34796, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'StardosStencil', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Stardos Stencil font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stardos+Stencil + static TextTheme stardosStencilTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.stardosStencil(textStyle: textTheme.headline1), + headline2: GoogleFonts.stardosStencil(textStyle: textTheme.headline2), + headline3: GoogleFonts.stardosStencil(textStyle: textTheme.headline3), + headline4: GoogleFonts.stardosStencil(textStyle: textTheme.headline4), + headline5: GoogleFonts.stardosStencil(textStyle: textTheme.headline5), + headline6: GoogleFonts.stardosStencil(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.stardosStencil(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.stardosStencil(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.stardosStencil(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.stardosStencil(textStyle: textTheme.bodyText2), + caption: GoogleFonts.stardosStencil(textStyle: textTheme.caption), + button: GoogleFonts.stardosStencil(textStyle: textTheme.button), + overline: GoogleFonts.stardosStencil(textStyle: textTheme.overline), + ); + } + + /// Applies the Stint Ultra Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stint+Ultra+Condensed + static TextStyle stintUltraCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'feefd36d93b983bb86af74847749eae8e80b528fd8e91dd95e3ec89419bacb1b', + 39832, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'StintUltraCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Stint Ultra Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stint+Ultra+Condensed + static TextTheme stintUltraCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.headline1), + headline2: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.headline2), + headline3: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.headline3), + headline4: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.headline4), + headline5: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.headline5), + headline6: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.stintUltraCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.stintUltraCondensed(textStyle: textTheme.caption), + button: GoogleFonts.stintUltraCondensed(textStyle: textTheme.button), + overline: GoogleFonts.stintUltraCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Stint Ultra Expanded font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stint+Ultra+Expanded + static TextStyle stintUltraExpanded({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e2e52b99f99f593fd768d038a499b7217a4852adceb02fa177857827ecd46921', + 42348, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'StintUltraExpanded', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Stint Ultra Expanded font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stint+Ultra+Expanded + static TextTheme stintUltraExpandedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.stintUltraExpanded(textStyle: textTheme.headline1), + headline2: GoogleFonts.stintUltraExpanded(textStyle: textTheme.headline2), + headline3: GoogleFonts.stintUltraExpanded(textStyle: textTheme.headline3), + headline4: GoogleFonts.stintUltraExpanded(textStyle: textTheme.headline4), + headline5: GoogleFonts.stintUltraExpanded(textStyle: textTheme.headline5), + headline6: GoogleFonts.stintUltraExpanded(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.stintUltraExpanded(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.stintUltraExpanded(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.stintUltraExpanded(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.stintUltraExpanded(textStyle: textTheme.bodyText2), + caption: GoogleFonts.stintUltraExpanded(textStyle: textTheme.caption), + button: GoogleFonts.stintUltraExpanded(textStyle: textTheme.button), + overline: GoogleFonts.stintUltraExpanded(textStyle: textTheme.overline), + ); + } + + /// Applies the Stoke font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stoke + static TextStyle stoke({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd452122746813947edb624edec6a876538c722d14e0fe96ba0524f09e515f3b6', + 50796, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fcfdfb02835f6966c5279db21b784abc2cfe9e1ec03d8c4452852483fb8f17c1', + 52516, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Stoke', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Stoke font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stoke + static TextTheme stokeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.stoke(textStyle: textTheme.headline1), + headline2: GoogleFonts.stoke(textStyle: textTheme.headline2), + headline3: GoogleFonts.stoke(textStyle: textTheme.headline3), + headline4: GoogleFonts.stoke(textStyle: textTheme.headline4), + headline5: GoogleFonts.stoke(textStyle: textTheme.headline5), + headline6: GoogleFonts.stoke(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.stoke(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.stoke(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.stoke(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.stoke(textStyle: textTheme.bodyText2), + caption: GoogleFonts.stoke(textStyle: textTheme.caption), + button: GoogleFonts.stoke(textStyle: textTheme.button), + overline: GoogleFonts.stoke(textStyle: textTheme.overline), + ); + } + + /// Applies the Strait font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Strait + static TextStyle strait({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '878aae72e6ee31acbf6951998be893d7fb71a57b07974d83623e60b6ccc8d671', + 33040, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Strait', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Strait font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Strait + static TextTheme straitTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.strait(textStyle: textTheme.headline1), + headline2: GoogleFonts.strait(textStyle: textTheme.headline2), + headline3: GoogleFonts.strait(textStyle: textTheme.headline3), + headline4: GoogleFonts.strait(textStyle: textTheme.headline4), + headline5: GoogleFonts.strait(textStyle: textTheme.headline5), + headline6: GoogleFonts.strait(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.strait(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.strait(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.strait(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.strait(textStyle: textTheme.bodyText2), + caption: GoogleFonts.strait(textStyle: textTheme.caption), + button: GoogleFonts.strait(textStyle: textTheme.button), + overline: GoogleFonts.strait(textStyle: textTheme.overline), + ); + } + + /// Applies the Stylish font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stylish + static TextStyle stylish({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '489ff10987ec4798768e532c108dbfb20bf68e1e122df1f77b9f35568d34a103', + 6162676, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Stylish', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Stylish font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Stylish + static TextTheme stylishTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.stylish(textStyle: textTheme.headline1), + headline2: GoogleFonts.stylish(textStyle: textTheme.headline2), + headline3: GoogleFonts.stylish(textStyle: textTheme.headline3), + headline4: GoogleFonts.stylish(textStyle: textTheme.headline4), + headline5: GoogleFonts.stylish(textStyle: textTheme.headline5), + headline6: GoogleFonts.stylish(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.stylish(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.stylish(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.stylish(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.stylish(textStyle: textTheme.bodyText2), + caption: GoogleFonts.stylish(textStyle: textTheme.caption), + button: GoogleFonts.stylish(textStyle: textTheme.button), + overline: GoogleFonts.stylish(textStyle: textTheme.overline), + ); + } + + /// Applies the Sue Ellen Francisco font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sue+Ellen+Francisco + static TextStyle sueEllenFrancisco({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd72aa0c7340b64bd3fc70457dd03d38b35b8cb3fd30f3f1af4a5f9b4bfd870aa', + 55840, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SueEllenFrancisco', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sue Ellen Francisco font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sue+Ellen+Francisco + static TextTheme sueEllenFranciscoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.headline1), + headline2: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.headline2), + headline3: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.headline3), + headline4: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.headline4), + headline5: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.headline5), + headline6: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.caption), + button: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.button), + overline: GoogleFonts.sueEllenFrancisco(textStyle: textTheme.overline), + ); + } + + /// Applies the Suez One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Suez+One + static TextStyle suezOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7e2e07a8ef35ea21aa3b0630f261b07ce1e992cf94e2161128376c440c9ed2df', + 69424, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SuezOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Suez One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Suez+One + static TextTheme suezOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.suezOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.suezOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.suezOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.suezOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.suezOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.suezOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.suezOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.suezOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.suezOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.suezOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.suezOne(textStyle: textTheme.caption), + button: GoogleFonts.suezOne(textStyle: textTheme.button), + overline: GoogleFonts.suezOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Sulphur Point font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sulphur+Point + static TextStyle sulphurPoint({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a21388d3a52630430a38cfb9e7aefbfa4653889b768e5fdc07c3eaa76c4bc5f0', + 36516, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fd7664cb5a15da70be5d1769533c9cfa5abe937f64ce7bc3cf0fd9e155151280', + 34400, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '27c023fb553e5fa85d985bf1965ac74cdc7ca09e715c656f8dfe82a44c53f18d', + 36180, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SulphurPoint', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sulphur Point font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sulphur+Point + static TextTheme sulphurPointTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sulphurPoint(textStyle: textTheme.headline1), + headline2: GoogleFonts.sulphurPoint(textStyle: textTheme.headline2), + headline3: GoogleFonts.sulphurPoint(textStyle: textTheme.headline3), + headline4: GoogleFonts.sulphurPoint(textStyle: textTheme.headline4), + headline5: GoogleFonts.sulphurPoint(textStyle: textTheme.headline5), + headline6: GoogleFonts.sulphurPoint(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sulphurPoint(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sulphurPoint(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sulphurPoint(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sulphurPoint(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sulphurPoint(textStyle: textTheme.caption), + button: GoogleFonts.sulphurPoint(textStyle: textTheme.button), + overline: GoogleFonts.sulphurPoint(textStyle: textTheme.overline), + ); + } + + /// Applies the Sumana font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sumana + static TextStyle sumana({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9fc4eb110fb834ab65fd4f7af149d8ca3402dde810677f1f6dc84f2b08194c7c', + 144712, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b035af08a910c59c4baf4941cca6a95cdea0a5c22c5d2615f77267f808f82c28', + 143064, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sumana', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sumana font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sumana + static TextTheme sumanaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sumana(textStyle: textTheme.headline1), + headline2: GoogleFonts.sumana(textStyle: textTheme.headline2), + headline3: GoogleFonts.sumana(textStyle: textTheme.headline3), + headline4: GoogleFonts.sumana(textStyle: textTheme.headline4), + headline5: GoogleFonts.sumana(textStyle: textTheme.headline5), + headline6: GoogleFonts.sumana(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sumana(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sumana(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sumana(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sumana(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sumana(textStyle: textTheme.caption), + button: GoogleFonts.sumana(textStyle: textTheme.button), + overline: GoogleFonts.sumana(textStyle: textTheme.overline), + ); + } + + /// Applies the Sunflower font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sunflower + static TextStyle sunflower({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e60ce84d8ac799e771211c4fa34de99812b730e86342f32f94fbccfa79461bd0', + 352904, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cf53d978b098c900279393bfdf56611a8003d688b2b16b7bd767182e1b0c58e8', + 341128, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f3b680ac8a8f4a8a9ede88bf72084ae45ddd8dd7a8a87e826b9ce8946a7b0536', + 347780, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sunflower', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sunflower font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sunflower + static TextTheme sunflowerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sunflower(textStyle: textTheme.headline1), + headline2: GoogleFonts.sunflower(textStyle: textTheme.headline2), + headline3: GoogleFonts.sunflower(textStyle: textTheme.headline3), + headline4: GoogleFonts.sunflower(textStyle: textTheme.headline4), + headline5: GoogleFonts.sunflower(textStyle: textTheme.headline5), + headline6: GoogleFonts.sunflower(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sunflower(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sunflower(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sunflower(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sunflower(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sunflower(textStyle: textTheme.caption), + button: GoogleFonts.sunflower(textStyle: textTheme.button), + overline: GoogleFonts.sunflower(textStyle: textTheme.overline), + ); + } + + /// Applies the Sunshiney font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sunshiney + static TextStyle sunshiney({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7ec73237e0e7d1a4339d0381c584067becd402e92eb382bcff00860e277d2ca', + 159812, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sunshiney', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sunshiney font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sunshiney + static TextTheme sunshineyTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sunshiney(textStyle: textTheme.headline1), + headline2: GoogleFonts.sunshiney(textStyle: textTheme.headline2), + headline3: GoogleFonts.sunshiney(textStyle: textTheme.headline3), + headline4: GoogleFonts.sunshiney(textStyle: textTheme.headline4), + headline5: GoogleFonts.sunshiney(textStyle: textTheme.headline5), + headline6: GoogleFonts.sunshiney(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sunshiney(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sunshiney(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sunshiney(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sunshiney(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sunshiney(textStyle: textTheme.caption), + button: GoogleFonts.sunshiney(textStyle: textTheme.button), + overline: GoogleFonts.sunshiney(textStyle: textTheme.overline), + ); + } + + /// Applies the Supermercado One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Supermercado+One + static TextStyle supermercadoOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ea1b33f9fdd9d3df950419909fa184a44918ab451c8e9e3fc175b440d0938a9f', + 79764, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SupermercadoOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Supermercado One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Supermercado+One + static TextTheme supermercadoOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.supermercadoOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.supermercadoOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.supermercadoOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.supermercadoOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.supermercadoOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.supermercadoOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.supermercadoOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.supermercadoOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.supermercadoOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.supermercadoOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.supermercadoOne(textStyle: textTheme.caption), + button: GoogleFonts.supermercadoOne(textStyle: textTheme.button), + overline: GoogleFonts.supermercadoOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Sura font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sura + static TextStyle sura({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '701cc1c8fa22221123e6045f90d0db8d42edadf3b831862ce801b57bb14ac1b1', + 121816, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a88482ddb9067b01125775fc0f780c4b615bc72ad86cbec920ee03b2756d8d90', + 122316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Sura', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Sura font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Sura + static TextTheme suraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.sura(textStyle: textTheme.headline1), + headline2: GoogleFonts.sura(textStyle: textTheme.headline2), + headline3: GoogleFonts.sura(textStyle: textTheme.headline3), + headline4: GoogleFonts.sura(textStyle: textTheme.headline4), + headline5: GoogleFonts.sura(textStyle: textTheme.headline5), + headline6: GoogleFonts.sura(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.sura(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.sura(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.sura(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.sura(textStyle: textTheme.bodyText2), + caption: GoogleFonts.sura(textStyle: textTheme.caption), + button: GoogleFonts.sura(textStyle: textTheme.button), + overline: GoogleFonts.sura(textStyle: textTheme.overline), + ); + } + + /// Applies the Suranna font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Suranna + static TextStyle suranna({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5737d88c714925c169afd72de230a6a9feb3a2d7a026b33b5ccfa42e60cef970', + 387684, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Suranna', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Suranna font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Suranna + static TextTheme surannaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.suranna(textStyle: textTheme.headline1), + headline2: GoogleFonts.suranna(textStyle: textTheme.headline2), + headline3: GoogleFonts.suranna(textStyle: textTheme.headline3), + headline4: GoogleFonts.suranna(textStyle: textTheme.headline4), + headline5: GoogleFonts.suranna(textStyle: textTheme.headline5), + headline6: GoogleFonts.suranna(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.suranna(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.suranna(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.suranna(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.suranna(textStyle: textTheme.bodyText2), + caption: GoogleFonts.suranna(textStyle: textTheme.caption), + button: GoogleFonts.suranna(textStyle: textTheme.button), + overline: GoogleFonts.suranna(textStyle: textTheme.overline), + ); + } + + /// Applies the Suravaram font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Suravaram + static TextStyle suravaram({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f9de796b7b600961688891106b7bc5efe1090a6ab181d91cc08b19a88e999360', + 189524, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Suravaram', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Suravaram font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Suravaram + static TextTheme suravaramTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.suravaram(textStyle: textTheme.headline1), + headline2: GoogleFonts.suravaram(textStyle: textTheme.headline2), + headline3: GoogleFonts.suravaram(textStyle: textTheme.headline3), + headline4: GoogleFonts.suravaram(textStyle: textTheme.headline4), + headline5: GoogleFonts.suravaram(textStyle: textTheme.headline5), + headline6: GoogleFonts.suravaram(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.suravaram(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.suravaram(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.suravaram(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.suravaram(textStyle: textTheme.bodyText2), + caption: GoogleFonts.suravaram(textStyle: textTheme.caption), + button: GoogleFonts.suravaram(textStyle: textTheme.button), + overline: GoogleFonts.suravaram(textStyle: textTheme.overline), + ); + } + + /// Applies the Swanky and Moo Moo font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Swanky+and+Moo+Moo + static TextStyle swankyAndMooMoo({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5d97fafd655154f9469db4b981793373b837c26023dd266164ebd62c6320aa39', + 58868, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SwankyandMooMoo', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Swanky and Moo Moo font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Swanky+and+Moo+Moo + static TextTheme swankyAndMooMooTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.headline1), + headline2: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.headline2), + headline3: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.headline3), + headline4: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.headline4), + headline5: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.headline5), + headline6: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.bodyText2), + caption: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.caption), + button: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.button), + overline: GoogleFonts.swankyAndMooMoo(textStyle: textTheme.overline), + ); + } + + /// Applies the Syncopate font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Syncopate + static TextStyle syncopate({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8f40fe696b566662712524f9cf3f5c4aff3afa640f0bd4ec0e527c22369561a9', + 67800, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0c6b8fb391ff34b292bb2091302fb45fcc3b16eefc6bf4e67b9f1fe38f4ab3fe', + 36484, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Syncopate', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Syncopate font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Syncopate + static TextTheme syncopateTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.syncopate(textStyle: textTheme.headline1), + headline2: GoogleFonts.syncopate(textStyle: textTheme.headline2), + headline3: GoogleFonts.syncopate(textStyle: textTheme.headline3), + headline4: GoogleFonts.syncopate(textStyle: textTheme.headline4), + headline5: GoogleFonts.syncopate(textStyle: textTheme.headline5), + headline6: GoogleFonts.syncopate(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.syncopate(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.syncopate(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.syncopate(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.syncopate(textStyle: textTheme.bodyText2), + caption: GoogleFonts.syncopate(textStyle: textTheme.caption), + button: GoogleFonts.syncopate(textStyle: textTheme.button), + overline: GoogleFonts.syncopate(textStyle: textTheme.overline), + ); + } + + /// Applies the Syne font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Syne + static TextStyle syne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '10a95c1d5441e25f26b113321ba395252616458e6bc6cb4ab2b30a6e1dff5f95', + 41596, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e9ec25bf50bdda60cae5ba089430a671b69e0eb0df474f513df3dc4af6a37eb4', + 41688, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b910b382d4f52c23227a1a5c42534c6e7a34c0ad59bb199c233e78ff07b715d7', + 41780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cf8fa7ceef12ecbce519bb32e8812c4115c3907472effb279de7f994f4edba2f', + 41748, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e3fd3e1944f3aef431c55c83b8d1664b81f5a0eefcf5cf1f4f6a7cc95b9d5da3', + 41956, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Syne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Syne font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Syne + static TextTheme syneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.syne(textStyle: textTheme.headline1), + headline2: GoogleFonts.syne(textStyle: textTheme.headline2), + headline3: GoogleFonts.syne(textStyle: textTheme.headline3), + headline4: GoogleFonts.syne(textStyle: textTheme.headline4), + headline5: GoogleFonts.syne(textStyle: textTheme.headline5), + headline6: GoogleFonts.syne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.syne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.syne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.syne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.syne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.syne(textStyle: textTheme.caption), + button: GoogleFonts.syne(textStyle: textTheme.button), + overline: GoogleFonts.syne(textStyle: textTheme.overline), + ); + } + + /// Applies the Syne Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Syne+Mono + static TextStyle syneMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f193ba0e19a956372bbf64662ae7062fe4c130d8339ce679217867f1922e3049', + 35128, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SyneMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Syne Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Syne+Mono + static TextTheme syneMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.syneMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.syneMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.syneMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.syneMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.syneMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.syneMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.syneMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.syneMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.syneMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.syneMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.syneMono(textStyle: textTheme.caption), + button: GoogleFonts.syneMono(textStyle: textTheme.button), + overline: GoogleFonts.syneMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Syne Tactile font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Syne+Tactile + static TextStyle syneTactile({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a9b880a161ac123e7e3413839ffeb154b4de7e8cc6ae2caa02b8b3b2877c9f9', + 86160, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'SyneTactile', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Syne Tactile font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Syne+Tactile + static TextTheme syneTactileTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.syneTactile(textStyle: textTheme.headline1), + headline2: GoogleFonts.syneTactile(textStyle: textTheme.headline2), + headline3: GoogleFonts.syneTactile(textStyle: textTheme.headline3), + headline4: GoogleFonts.syneTactile(textStyle: textTheme.headline4), + headline5: GoogleFonts.syneTactile(textStyle: textTheme.headline5), + headline6: GoogleFonts.syneTactile(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.syneTactile(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.syneTactile(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.syneTactile(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.syneTactile(textStyle: textTheme.bodyText2), + caption: GoogleFonts.syneTactile(textStyle: textTheme.caption), + button: GoogleFonts.syneTactile(textStyle: textTheme.button), + overline: GoogleFonts.syneTactile(textStyle: textTheme.overline), + ); + } + + /// Applies the Tajawal font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tajawal + static TextStyle tajawal({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1591b1d4b425865ad56f27769d7904f608af3a947ce4a365c5e6f1a66ed36c5c', + 51368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '96516512d599f345601934621e5ddc2b61c7967d59e4ee3bea24cb11c9f720d8', + 56216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6008a589c04e1cca5b78ecd73eb5f54a525670df2d3627fcddac202dac0b8db5', + 55044, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'efce394f1ebd252328bf21261a39ead5a083741b090a73e22bec34acbd910611', + 56256, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '647958c651db7515a77fab543f70f06386720821399060f8b1791b1dc23a845b', + 55492, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '354e92ab2c7c9b84b1e80ee6431ea8e8bc0fe58113d4afa3fbf186b193168ca5', + 55216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9953e51150483dc38b632c494f68d39e59b6c474716bc0ac3e9d997c4ec0df52', + 54644, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Tajawal', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tajawal font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tajawal + static TextTheme tajawalTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tajawal(textStyle: textTheme.headline1), + headline2: GoogleFonts.tajawal(textStyle: textTheme.headline2), + headline3: GoogleFonts.tajawal(textStyle: textTheme.headline3), + headline4: GoogleFonts.tajawal(textStyle: textTheme.headline4), + headline5: GoogleFonts.tajawal(textStyle: textTheme.headline5), + headline6: GoogleFonts.tajawal(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tajawal(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tajawal(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tajawal(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tajawal(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tajawal(textStyle: textTheme.caption), + button: GoogleFonts.tajawal(textStyle: textTheme.button), + overline: GoogleFonts.tajawal(textStyle: textTheme.overline), + ); + } + + /// Applies the Tangerine font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tangerine + static TextStyle tangerine({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd57c4cf7ce5cace0ff51506a942305cb2a8342c0d13badf47b74d8b7ccd6a976', + 39584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '99be610fa0d0acc2de30af936f07ac82bda5378a98b867c55dc1d8ae1a763c72', + 39460, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Tangerine', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tangerine font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tangerine + static TextTheme tangerineTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tangerine(textStyle: textTheme.headline1), + headline2: GoogleFonts.tangerine(textStyle: textTheme.headline2), + headline3: GoogleFonts.tangerine(textStyle: textTheme.headline3), + headline4: GoogleFonts.tangerine(textStyle: textTheme.headline4), + headline5: GoogleFonts.tangerine(textStyle: textTheme.headline5), + headline6: GoogleFonts.tangerine(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tangerine(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tangerine(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tangerine(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tangerine(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tangerine(textStyle: textTheme.caption), + button: GoogleFonts.tangerine(textStyle: textTheme.button), + overline: GoogleFonts.tangerine(textStyle: textTheme.overline), + ); + } + + /// Applies the Tauri font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tauri + static TextStyle tauri({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '364639e2343951f5f67f35cd32dddd5050f5a7d4b5170fd1f4b9bcdcfd3b70a5', + 25452, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Tauri', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tauri font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tauri + static TextTheme tauriTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tauri(textStyle: textTheme.headline1), + headline2: GoogleFonts.tauri(textStyle: textTheme.headline2), + headline3: GoogleFonts.tauri(textStyle: textTheme.headline3), + headline4: GoogleFonts.tauri(textStyle: textTheme.headline4), + headline5: GoogleFonts.tauri(textStyle: textTheme.headline5), + headline6: GoogleFonts.tauri(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tauri(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tauri(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tauri(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tauri(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tauri(textStyle: textTheme.caption), + button: GoogleFonts.tauri(textStyle: textTheme.button), + overline: GoogleFonts.tauri(textStyle: textTheme.overline), + ); + } + + /// Applies the Taviraj font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Taviraj + static TextStyle taviraj({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '52fbea14874ede87677741ccb667e42f7f7032e15c8b1a97be9fb092777027f3', + 137276, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd637ee5b1965213b2d0a0e00861b1be03c91e65b536d89344ca8311230055a55', + 151012, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0f7c36cf8282e0201e715b76951dfdbbb3cbfd0205738f51c9ecf4317214ac1d', + 137232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '595da34fe677c807a56dbef57b36441f4cd9de4747ca13a95bc88dd802565032', + 151740, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b164693b28772a83e0ba3ea3b0795121a18396d1d22e4896f1f49fc90acc48b0', + 136700, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4835b3444e501b13a94cc6e04b4b19278bf42fae51e45998c0b41de8111b0727', + 138660, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cc53748aefd7d7a100dafa7ee826dbe17e7e14c04500e79b83a7960d0e379305', + 137464, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '9dd995b1166e87570dc10d6a2afb2e5bdc5a0a8897063971ff30f8be824cbdb0', + 151440, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8088b428c6a34c587047b747ef8b7e12084beb84bd154855e5c2d5038047e712', + 136676, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f38fc8738bdc33986e0ef3c36e4c1af93939c40aee8d6db38f93edcefac57482', + 152500, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '60262effd08d123f96e4ab6a7b67e4bdf366592724ab6211ea76e298b32de956', + 123836, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c32503bb0fe3a7c346743b68f48dba5c7de00074f0b33e16f2e1e34686a75575', + 138496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'df6e4ecf9639e7dc02de4f99c5c63ebf641345e361470a40c48179c0dc47de55', + 135496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e3ea04696627c46a58fa5ef27becd6ba6de21760fbeda60718e5ea072290165b', + 150784, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aff20cbaad70c21cda602d83dcf1df3e91122111271040a17451c90f91c0bc44', + 135488, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ce78de38f72b4be9e1af07713b59f4497cc2677898bd647e19679c6b10bd16d7', + 149960, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '75383093cb1afbe41275d2188c2d57c958f8fb94eff2dc57382eb5c77ca82138', + 134912, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '181f5aa6c3cfc77afd3dbcbc58dd4a621984f78739969774a7f939caee61b936', + 145500, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Taviraj', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Taviraj font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Taviraj + static TextTheme tavirajTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.taviraj(textStyle: textTheme.headline1), + headline2: GoogleFonts.taviraj(textStyle: textTheme.headline2), + headline3: GoogleFonts.taviraj(textStyle: textTheme.headline3), + headline4: GoogleFonts.taviraj(textStyle: textTheme.headline4), + headline5: GoogleFonts.taviraj(textStyle: textTheme.headline5), + headline6: GoogleFonts.taviraj(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.taviraj(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.taviraj(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.taviraj(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.taviraj(textStyle: textTheme.bodyText2), + caption: GoogleFonts.taviraj(textStyle: textTheme.caption), + button: GoogleFonts.taviraj(textStyle: textTheme.button), + overline: GoogleFonts.taviraj(textStyle: textTheme.overline), + ); + } + + /// Applies the Teko font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Teko + static TextStyle teko({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b31400af25afcb1ea24b0a3b59e18957132c4df53084ec09f2978ddfd1e67fc5', + 183236, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd796b7d93c33a941a6521bb31d3ce37f381b87f97447077405c1cf841c4cb586', + 188060, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '88b2962aecc7ff0d4a09258f8eff7210ff6c72abd16a8229f30da45d3c428b44', + 189536, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '93c13926efeae26ea7017e3777dd33149524c7eb3907c791e4b8c8edc57848f6', + 188860, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8c33b42189d0afc837f06ec5fd8b20cc431d75823356156ab00af8dcb949fa69', + 178052, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Teko', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Teko font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Teko + static TextTheme tekoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.teko(textStyle: textTheme.headline1), + headline2: GoogleFonts.teko(textStyle: textTheme.headline2), + headline3: GoogleFonts.teko(textStyle: textTheme.headline3), + headline4: GoogleFonts.teko(textStyle: textTheme.headline4), + headline5: GoogleFonts.teko(textStyle: textTheme.headline5), + headline6: GoogleFonts.teko(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.teko(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.teko(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.teko(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.teko(textStyle: textTheme.bodyText2), + caption: GoogleFonts.teko(textStyle: textTheme.caption), + button: GoogleFonts.teko(textStyle: textTheme.button), + overline: GoogleFonts.teko(textStyle: textTheme.overline), + ); + } + + /// Applies the Telex font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Telex + static TextStyle telex({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '75d35766aa0cce57bcd40915972194111fc782787321d3eed8813c7c8d1e9e39', + 25416, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Telex', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Telex font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Telex + static TextTheme telexTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.telex(textStyle: textTheme.headline1), + headline2: GoogleFonts.telex(textStyle: textTheme.headline2), + headline3: GoogleFonts.telex(textStyle: textTheme.headline3), + headline4: GoogleFonts.telex(textStyle: textTheme.headline4), + headline5: GoogleFonts.telex(textStyle: textTheme.headline5), + headline6: GoogleFonts.telex(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.telex(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.telex(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.telex(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.telex(textStyle: textTheme.bodyText2), + caption: GoogleFonts.telex(textStyle: textTheme.caption), + button: GoogleFonts.telex(textStyle: textTheme.button), + overline: GoogleFonts.telex(textStyle: textTheme.overline), + ); + } + + /// Applies the Tenali Ramakrishna font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tenali+Ramakrishna + static TextStyle tenaliRamakrishna({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b6f6e7bc4fab4b63722a7970012462fc4dd196307fcab934cabb392e9b45b437', + 484616, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TenaliRamakrishna', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tenali Ramakrishna font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tenali+Ramakrishna + static TextTheme tenaliRamakrishnaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.headline1), + headline2: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.headline2), + headline3: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.headline3), + headline4: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.headline4), + headline5: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.headline5), + headline6: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.caption), + button: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.button), + overline: GoogleFonts.tenaliRamakrishna(textStyle: textTheme.overline), + ); + } + + /// Applies the Tenor Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tenor+Sans + static TextStyle tenorSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8282a828e14c73c12ba9034180b4a4840baca4c02a86359f63143806dcc81f23', + 76800, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TenorSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tenor Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tenor+Sans + static TextTheme tenorSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tenorSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.tenorSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.tenorSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.tenorSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.tenorSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.tenorSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tenorSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tenorSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tenorSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tenorSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tenorSans(textStyle: textTheme.caption), + button: GoogleFonts.tenorSans(textStyle: textTheme.button), + overline: GoogleFonts.tenorSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Text Me One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Text+Me+One + static TextStyle textMeOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '804cbe1e9c5d9e08155e548789f8b5f53ff150c0785dbeae1c9361e8749b4e52', + 37304, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TextMeOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Text Me One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Text+Me+One + static TextTheme textMeOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.textMeOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.textMeOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.textMeOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.textMeOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.textMeOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.textMeOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.textMeOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.textMeOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.textMeOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.textMeOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.textMeOne(textStyle: textTheme.caption), + button: GoogleFonts.textMeOne(textStyle: textTheme.button), + overline: GoogleFonts.textMeOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Thasadith font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Thasadith + static TextStyle thasadith({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b9b28f00da26a27f2be523c47e0404d6bad035dead548d2418197cd755cc3ac5', + 86212, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6c61662859aba973376a911040a9d141a67b1fa741ad54150e2bca1ec179e824', + 89192, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '45b2059a66559645a04c064051f3e3d8f18c0e883aab89bae7fff6d05ad0043b', + 86580, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '758c9bca5f80c1e919aa4821259cd1a773692ab770622c36f688ea4c8524b0ae', + 89588, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Thasadith', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Thasadith font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Thasadith + static TextTheme thasadithTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.thasadith(textStyle: textTheme.headline1), + headline2: GoogleFonts.thasadith(textStyle: textTheme.headline2), + headline3: GoogleFonts.thasadith(textStyle: textTheme.headline3), + headline4: GoogleFonts.thasadith(textStyle: textTheme.headline4), + headline5: GoogleFonts.thasadith(textStyle: textTheme.headline5), + headline6: GoogleFonts.thasadith(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.thasadith(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.thasadith(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.thasadith(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.thasadith(textStyle: textTheme.bodyText2), + caption: GoogleFonts.thasadith(textStyle: textTheme.caption), + button: GoogleFonts.thasadith(textStyle: textTheme.button), + overline: GoogleFonts.thasadith(textStyle: textTheme.overline), + ); + } + + /// Applies the The Girl Next Door font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/The+Girl+Next+Door + static TextStyle theGirlNextDoor({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '51c93d3ab1885507b024f2ed61854dbb865696dcb5dbdfd1b135cefd74150fef', + 45248, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TheGirlNextDoor', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the The Girl Next Door font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/The+Girl+Next+Door + static TextTheme theGirlNextDoorTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.theGirlNextDoor(textStyle: textTheme.headline1), + headline2: GoogleFonts.theGirlNextDoor(textStyle: textTheme.headline2), + headline3: GoogleFonts.theGirlNextDoor(textStyle: textTheme.headline3), + headline4: GoogleFonts.theGirlNextDoor(textStyle: textTheme.headline4), + headline5: GoogleFonts.theGirlNextDoor(textStyle: textTheme.headline5), + headline6: GoogleFonts.theGirlNextDoor(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.theGirlNextDoor(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.theGirlNextDoor(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.theGirlNextDoor(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.theGirlNextDoor(textStyle: textTheme.bodyText2), + caption: GoogleFonts.theGirlNextDoor(textStyle: textTheme.caption), + button: GoogleFonts.theGirlNextDoor(textStyle: textTheme.button), + overline: GoogleFonts.theGirlNextDoor(textStyle: textTheme.overline), + ); + } + + /// Applies the Tienne font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tienne + static TextStyle tienne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e11280c2a4284740a646bbace5bf0a018fa38ead3ba5b33b7d6a55a646342b17', + 40772, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '62ae315531bcb85150dfefb27cbccbb30f331e0c091470a03aca49e6b1842e5f', + 38824, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7882a99c925a597867e27f064c12db77d2185f452bd9b0bc83862549c886331c', + 36220, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Tienne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tienne font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tienne + static TextTheme tienneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tienne(textStyle: textTheme.headline1), + headline2: GoogleFonts.tienne(textStyle: textTheme.headline2), + headline3: GoogleFonts.tienne(textStyle: textTheme.headline3), + headline4: GoogleFonts.tienne(textStyle: textTheme.headline4), + headline5: GoogleFonts.tienne(textStyle: textTheme.headline5), + headline6: GoogleFonts.tienne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tienne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tienne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tienne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tienne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tienne(textStyle: textTheme.caption), + button: GoogleFonts.tienne(textStyle: textTheme.button), + overline: GoogleFonts.tienne(textStyle: textTheme.overline), + ); + } + + /// Applies the Tillana font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tillana + static TextStyle tillana({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f767b3a50e7fbd85244228fd72776e996704c5b833256c5fa56b782821e015af', + 217680, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5aecdf23e36ca11770901c226daf192765931a12afd290bbf684884f9bbf1c7c', + 222092, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a5f11d010b5bd339931701e1853b2788fccf7cb07bbf503ff03f027a3086f3f3', + 222844, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aed658fc70549eb112a013dc7ce6145b1f2719ee7d6179a5c4fd7be399a68511', + 222308, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'df261f8eeab47304d5e83ee3d77bba8193f51bd098bab3370180417296143318', + 222568, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Tillana', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tillana font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tillana + static TextTheme tillanaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tillana(textStyle: textTheme.headline1), + headline2: GoogleFonts.tillana(textStyle: textTheme.headline2), + headline3: GoogleFonts.tillana(textStyle: textTheme.headline3), + headline4: GoogleFonts.tillana(textStyle: textTheme.headline4), + headline5: GoogleFonts.tillana(textStyle: textTheme.headline5), + headline6: GoogleFonts.tillana(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tillana(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tillana(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tillana(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tillana(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tillana(textStyle: textTheme.caption), + button: GoogleFonts.tillana(textStyle: textTheme.button), + overline: GoogleFonts.tillana(textStyle: textTheme.overline), + ); + } + + /// Applies the Timmana font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Timmana + static TextStyle timmana({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6cf943319390cff3797ae7f9cf411dc8a14a739df02bdb952ae54284aaf15b01', + 469544, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Timmana', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Timmana font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Timmana + static TextTheme timmanaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.timmana(textStyle: textTheme.headline1), + headline2: GoogleFonts.timmana(textStyle: textTheme.headline2), + headline3: GoogleFonts.timmana(textStyle: textTheme.headline3), + headline4: GoogleFonts.timmana(textStyle: textTheme.headline4), + headline5: GoogleFonts.timmana(textStyle: textTheme.headline5), + headline6: GoogleFonts.timmana(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.timmana(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.timmana(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.timmana(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.timmana(textStyle: textTheme.bodyText2), + caption: GoogleFonts.timmana(textStyle: textTheme.caption), + button: GoogleFonts.timmana(textStyle: textTheme.button), + overline: GoogleFonts.timmana(textStyle: textTheme.overline), + ); + } + + /// Applies the Tinos font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tinos + static TextStyle tinos({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e3fb073d6d034814d7825107e1eae4eee8c1f169d87607f2df536bb4e4093ddf', + 262544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '27dde2d7c4a3b5edc81ddca48874ffcb63a893df81e508e07a3565f70323fdaf', + 263828, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dc658c10271c22ff1ad12fc220c05dadf678b1fa42443b874fd100f68afa117c', + 256496, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '839f50ca06adbf9bc25feef137791fcd9983139a76881789a290e71d685feab5', + 261992, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Tinos', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tinos font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tinos + static TextTheme tinosTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tinos(textStyle: textTheme.headline1), + headline2: GoogleFonts.tinos(textStyle: textTheme.headline2), + headline3: GoogleFonts.tinos(textStyle: textTheme.headline3), + headline4: GoogleFonts.tinos(textStyle: textTheme.headline4), + headline5: GoogleFonts.tinos(textStyle: textTheme.headline5), + headline6: GoogleFonts.tinos(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tinos(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tinos(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tinos(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tinos(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tinos(textStyle: textTheme.caption), + button: GoogleFonts.tinos(textStyle: textTheme.button), + overline: GoogleFonts.tinos(textStyle: textTheme.overline), + ); + } + + /// Applies the Titan One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Titan+One + static TextStyle titanOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '065d13ba1ab0e715e15feed24b86ff9a58a8df624d74923e1a1c710b36e08e99', + 55664, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TitanOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Titan One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Titan+One + static TextTheme titanOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.titanOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.titanOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.titanOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.titanOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.titanOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.titanOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.titanOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.titanOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.titanOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.titanOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.titanOne(textStyle: textTheme.caption), + button: GoogleFonts.titanOne(textStyle: textTheme.button), + overline: GoogleFonts.titanOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Titillium Web font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Titillium+Web + static TextStyle titilliumWeb({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '19772d85bad94abc7a76fc4a64849db9638e9c00e7e0dadd3872a583b74adbe3', + 62712, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'a39917b8e97b8433f10dae6821885f087662f1062a48a366f2f2f287c74ecb6c', + 67404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7da8c41b9e519ca322471fc0bdcc15a795423fb09cbf094a6787142218ec1c9e', + 63520, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f0ff528b94c980870d32757c89817e790c119bea9de817d49334ba1a3f04ef9a', + 71232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ba6d03922294b498b3e57ace654a9ee6715c33081cd24c1df56004ca64ba6e66', + 63188, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd785f9b4efc2d7f91a854d36930d269122091296e25a46cc7931e2cd717567d5', + 71912, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8c9b215a8e543b09a087afec74223fb41a74378deb5b83c8457630d03f0b5fc3', + 62524, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e43b57298b99f0da6d3bfa3de072e88a539bf01332c5232e8e29dfee09cb859c', + 71340, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '10e8c4207611b16691202b4204f5fbd4e27aa240a45dbb2ca91f63f341056539', + 59388, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'dd23a74d333a9694f51ccb193efddc8d38e892053eca374882e2fe4043181559', + 69256, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '742f14f17526638a90f24974f5222008c89acabe2c636deb378ba287cf381bc6', + 48836, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TitilliumWeb', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Titillium Web font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Titillium+Web + static TextTheme titilliumWebTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.titilliumWeb(textStyle: textTheme.headline1), + headline2: GoogleFonts.titilliumWeb(textStyle: textTheme.headline2), + headline3: GoogleFonts.titilliumWeb(textStyle: textTheme.headline3), + headline4: GoogleFonts.titilliumWeb(textStyle: textTheme.headline4), + headline5: GoogleFonts.titilliumWeb(textStyle: textTheme.headline5), + headline6: GoogleFonts.titilliumWeb(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.titilliumWeb(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.titilliumWeb(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.titilliumWeb(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.titilliumWeb(textStyle: textTheme.bodyText2), + caption: GoogleFonts.titilliumWeb(textStyle: textTheme.caption), + button: GoogleFonts.titilliumWeb(textStyle: textTheme.button), + overline: GoogleFonts.titilliumWeb(textStyle: textTheme.overline), + ); + } + + /// Applies the Tomorrow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tomorrow + static TextStyle tomorrow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2bf064837570b16e64b6e16bb607ccd32e353ea52ff1860fd61a0de72f6a5ea0', + 54872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5dd9ba1be08d4e07fc0457665070caeecdad448ec1322aaac51e215904362e1e', + 58008, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '79fcf41f1188438fdf8ed0f55418e4ca98f03b8443301282f5802555a96f74af', + 56872, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '425bd4136783e2ffeb2842db5e8492f0dc216f55affb59a6318a92710baa27eb', + 58892, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7b2dfcddbd51d970a89a1da730c28728ef35143b92571a0784e276e6717c88ef', + 56908, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd222b2be7527fd1ff40802e62efd580a26a2af8429cf2dbddbce712e5a794dba', + 58928, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5256d55c0d21f605ff31cd07ca4024c586239869f4fe1ce2e54ef2b9b6dd1611', + 56716, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'b3eda563419f8c13997aed418ed32fcc44e137a85792169be016f3242f1dbd26', + 58568, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '60bf8a426801434668a4d142fe97fa27c6e2dc3fa243ddeebf54f7c9d0284cbf', + 56172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '74048134b96771acecb5de5c4af84c177e24ca1b8a7c3b6c9852c5f68517cbb0', + 58112, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3de6c087f280da15fd40635ba1cc66fe7c78a10350dd0f94ae6ada95384f31a4', + 56784, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2e985e11cd4dd1e0fd28d54e7a8c28dd1d7bf7fb880476ad1ff3ea0920bae21a', + 59016, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2434798866b49db9f385b1aff9ce12097fd03456a8dd4c6aa8dfa8478446c036', + 55956, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '523759fa7f5b6d8e1fd036f0fe530eb086c95d6be872aa152730f72cc697b264', + 58964, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a88013dd353dca273c7a4129ba7433767521753e669d6b73174ac30b3004aca', + 56584, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'c11ab2b695c695bcd579be5ede3d5e8f268d1754defa82cb82da445a0f6fcc68', + 59704, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '976124bee1d9ac2c0b64250e695eb111c22947028b468261ac2ba747e935ce41', + 52332, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '84a0fcf0b30441638a28059e5e836a2441bbd5f51553c29ae163f37af0e07b6e', + 55780, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Tomorrow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tomorrow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tomorrow + static TextTheme tomorrowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tomorrow(textStyle: textTheme.headline1), + headline2: GoogleFonts.tomorrow(textStyle: textTheme.headline2), + headline3: GoogleFonts.tomorrow(textStyle: textTheme.headline3), + headline4: GoogleFonts.tomorrow(textStyle: textTheme.headline4), + headline5: GoogleFonts.tomorrow(textStyle: textTheme.headline5), + headline6: GoogleFonts.tomorrow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tomorrow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tomorrow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tomorrow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tomorrow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tomorrow(textStyle: textTheme.caption), + button: GoogleFonts.tomorrow(textStyle: textTheme.button), + overline: GoogleFonts.tomorrow(textStyle: textTheme.overline), + ); + } + + /// Applies the Trade Winds font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trade+Winds + static TextStyle tradeWinds({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3700d4f7d8215f29936d00b52a4b5bf1b2c28b9df395be53d179282b32834cdb', + 85328, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TradeWinds', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Trade Winds font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trade+Winds + static TextTheme tradeWindsTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tradeWinds(textStyle: textTheme.headline1), + headline2: GoogleFonts.tradeWinds(textStyle: textTheme.headline2), + headline3: GoogleFonts.tradeWinds(textStyle: textTheme.headline3), + headline4: GoogleFonts.tradeWinds(textStyle: textTheme.headline4), + headline5: GoogleFonts.tradeWinds(textStyle: textTheme.headline5), + headline6: GoogleFonts.tradeWinds(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tradeWinds(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tradeWinds(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tradeWinds(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tradeWinds(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tradeWinds(textStyle: textTheme.caption), + button: GoogleFonts.tradeWinds(textStyle: textTheme.button), + overline: GoogleFonts.tradeWinds(textStyle: textTheme.overline), + ); + } + + /// Applies the Trirong font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trirong + static TextStyle trirong({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ebda10c096f251b0f84ce8b6fad4468a087d944c5c45081c09f9b355ed9c2757', + 130884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7a42cfb5ac38b434d94f2da531cd684023ef0223664c7a1dcc27c1abbb1da60a', + 145452, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c24e38979d00ca5cc7b8263089200c8047ff2589fdccff637c44dd6e0ab1f408', + 130952, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '273025dcd85321fcb1f102724944a7150fea25d03ff9ed2bb7386973e88b9e50', + 146848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5f63c33f4190aa7884d7b64f11279c4507d7317e5624d0bfc1b05eca2ff418e7', + 132208, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '1784836440ffdf31286b0df9584970579b1af1952ac75dfd022bf9d7e0984fe1', + 146876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '83969f4046620c10445d07b6cec90f9d567b3cb5ae9f8a0d216568cc2d15654c', + 132240, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '841e812a25eb28ca4e21cb658d8366c9bb981105dd1d7aa88ca994bb54894ea3', + 135792, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '43bcfe3403429145f5c7fb7b1c235b3f7c6ec53c0eb74c60aacf204b951b5401', + 132568, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5e3cacecc05b4c5ec441b805e2a762128058bec1d536af471ba5e41bdc4aeab6', + 145648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1bcf42948a6cb24de06e4672a41d7be5d5a78f8666cb01af47465ae500a71d3f', + 119756, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '33b42029fe9f85e3aca1571116b8931e01d2c0532a8686fa4d4c1a9a6002d4c7', + 133248, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f44ac39f4897c03dc6b971c1150fb6931ae23244de24ad8b7e7786cf80d05bdf', + 132408, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '253f1ffccc8aef2bd32268020b2c2043f73135a8ae452a59da8a0392eb550f15', + 149368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91503f7fd8f6427f0f52f59b2eb579609644a895bbc23cf120d005ca661664a3', + 132344, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '4bfb31e96b8c31946d7ad03ee00d18bbe83bb6f3259286bfcf595eb3a58f0d0c', + 148940, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '68b6c54a09143e5a61f93d87711cea8b55c71178340aa29d7900f345a39d6fec', + 132288, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3065ef76d27a4859bed714e0ff5f472bd1675a0fc4b103a5b365fb7e367acbdc', + 149148, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Trirong', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Trirong font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trirong + static TextTheme trirongTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.trirong(textStyle: textTheme.headline1), + headline2: GoogleFonts.trirong(textStyle: textTheme.headline2), + headline3: GoogleFonts.trirong(textStyle: textTheme.headline3), + headline4: GoogleFonts.trirong(textStyle: textTheme.headline4), + headline5: GoogleFonts.trirong(textStyle: textTheme.headline5), + headline6: GoogleFonts.trirong(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.trirong(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.trirong(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.trirong(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.trirong(textStyle: textTheme.bodyText2), + caption: GoogleFonts.trirong(textStyle: textTheme.caption), + button: GoogleFonts.trirong(textStyle: textTheme.button), + overline: GoogleFonts.trirong(textStyle: textTheme.overline), + ); + } + + /// Applies the Trispace font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trispace + static TextStyle trispace({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b3404c98e8b052927506deba2273cdeff5b08bf49bc3a775dbcb2d2695f56d5a', + 53512, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9412d5707c25a2fb98656127b7821c8578cf409832511eafff58b365122fcf12', + 53572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ac2a043612ddf6a6ab209a0b9220cac2ea1a50e352b37e2c8bebdeba9baffea9', + 53544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2775d9e85d7a86e22a08277823b8574695d6d856ceaeccee367699c7a9108a60', + 53544, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '420c166488b9b29145af63bbaabdf0ddacd5cb4eaa5084a568274514f91cdc76', + 53616, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1a01819504ed7c14b6a89fc429166810ba37507d741e1dbd9eb3c0567b4fc6d1', + 53808, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd98f23221487bb9a3761267c52a362c092e195ceb1ff754670532170f3b32e31', + 53876, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'ab1caf8338f45565ae7cbdd85a7bf8ee5fb58a44063836ee19ee2a89e3bc0af6', + 54184, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Trispace', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Trispace font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trispace + static TextTheme trispaceTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.trispace(textStyle: textTheme.headline1), + headline2: GoogleFonts.trispace(textStyle: textTheme.headline2), + headline3: GoogleFonts.trispace(textStyle: textTheme.headline3), + headline4: GoogleFonts.trispace(textStyle: textTheme.headline4), + headline5: GoogleFonts.trispace(textStyle: textTheme.headline5), + headline6: GoogleFonts.trispace(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.trispace(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.trispace(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.trispace(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.trispace(textStyle: textTheme.bodyText2), + caption: GoogleFonts.trispace(textStyle: textTheme.caption), + button: GoogleFonts.trispace(textStyle: textTheme.button), + overline: GoogleFonts.trispace(textStyle: textTheme.overline), + ); + } + + /// Applies the Trocchi font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trocchi + static TextStyle trocchi({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'eb00e832bf4003425484645b8e897ee2762c5ef155286eb4647745a9992d91e5', + 43796, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Trocchi', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Trocchi font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trocchi + static TextTheme trocchiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.trocchi(textStyle: textTheme.headline1), + headline2: GoogleFonts.trocchi(textStyle: textTheme.headline2), + headline3: GoogleFonts.trocchi(textStyle: textTheme.headline3), + headline4: GoogleFonts.trocchi(textStyle: textTheme.headline4), + headline5: GoogleFonts.trocchi(textStyle: textTheme.headline5), + headline6: GoogleFonts.trocchi(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.trocchi(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.trocchi(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.trocchi(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.trocchi(textStyle: textTheme.bodyText2), + caption: GoogleFonts.trocchi(textStyle: textTheme.caption), + button: GoogleFonts.trocchi(textStyle: textTheme.button), + overline: GoogleFonts.trocchi(textStyle: textTheme.overline), + ); + } + + /// Applies the Trochut font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trochut + static TextStyle trochut({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'fb7ad314480eec04c8ff53ad7a24690495145d924a92be149c75ccd5fe144215', + 25252, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '05e2d11e0d53984525926d1c86d71eab21194ae2664a3696175f68fb9e8969de', + 27860, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '82633b54306a8a1649b8590f40a509a2808ff33ef157f6cc3f98d52130752914', + 25364, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Trochut', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Trochut font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trochut + static TextTheme trochutTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.trochut(textStyle: textTheme.headline1), + headline2: GoogleFonts.trochut(textStyle: textTheme.headline2), + headline3: GoogleFonts.trochut(textStyle: textTheme.headline3), + headline4: GoogleFonts.trochut(textStyle: textTheme.headline4), + headline5: GoogleFonts.trochut(textStyle: textTheme.headline5), + headline6: GoogleFonts.trochut(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.trochut(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.trochut(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.trochut(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.trochut(textStyle: textTheme.bodyText2), + caption: GoogleFonts.trochut(textStyle: textTheme.caption), + button: GoogleFonts.trochut(textStyle: textTheme.button), + overline: GoogleFonts.trochut(textStyle: textTheme.overline), + ); + } + + /// Applies the Trykker font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trykker + static TextStyle trykker({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a90a15371d777f248a91bd42582cdab700d67f8d3ca9b191fa8f32923f781e02', + 38116, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Trykker', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Trykker font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Trykker + static TextTheme trykkerTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.trykker(textStyle: textTheme.headline1), + headline2: GoogleFonts.trykker(textStyle: textTheme.headline2), + headline3: GoogleFonts.trykker(textStyle: textTheme.headline3), + headline4: GoogleFonts.trykker(textStyle: textTheme.headline4), + headline5: GoogleFonts.trykker(textStyle: textTheme.headline5), + headline6: GoogleFonts.trykker(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.trykker(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.trykker(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.trykker(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.trykker(textStyle: textTheme.bodyText2), + caption: GoogleFonts.trykker(textStyle: textTheme.caption), + button: GoogleFonts.trykker(textStyle: textTheme.button), + overline: GoogleFonts.trykker(textStyle: textTheme.overline), + ); + } + + /// Applies the Tulpen One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tulpen+One + static TextStyle tulpenOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7952e8a169708673ce2f03a77306fa166fa25d0f8475c26ea3cf055d955577c', + 35220, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TulpenOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Tulpen One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Tulpen+One + static TextTheme tulpenOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.tulpenOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.tulpenOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.tulpenOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.tulpenOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.tulpenOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.tulpenOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.tulpenOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.tulpenOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.tulpenOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.tulpenOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.tulpenOne(textStyle: textTheme.caption), + button: GoogleFonts.tulpenOne(textStyle: textTheme.button), + overline: GoogleFonts.tulpenOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Turret Road font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Turret+Road + static TextStyle turretRoad({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1eb2f6296f0d09925f225ecec4142547ba09542fcc5069fe46fe0d8673c2b6a3', + 31752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e38827c14383deae6789dc0f07d95b6cbb5f0093dbd0d872fcd4e792c8903562', + 31504, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a9fe5d3ea03de544cf78476012b66bd6ec9240790f7e13b7365bab19f4d7dceb', + 31648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6d3a6fdd0ccdd0665ca8b9ff99c62c571a5779139c039da471fb8b0d313b4c09', + 31556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1ba5b04b2f9d8431b7bd41642ebdd197b5d904f1002cafc12fa7828579bc9970', + 30868, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b60bec40097c905a21009c6ad48cbe4c2c44f58ef95171a0a61efb0d6727a620', + 31516, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'TurretRoad', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Turret Road font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Turret+Road + static TextTheme turretRoadTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.turretRoad(textStyle: textTheme.headline1), + headline2: GoogleFonts.turretRoad(textStyle: textTheme.headline2), + headline3: GoogleFonts.turretRoad(textStyle: textTheme.headline3), + headline4: GoogleFonts.turretRoad(textStyle: textTheme.headline4), + headline5: GoogleFonts.turretRoad(textStyle: textTheme.headline5), + headline6: GoogleFonts.turretRoad(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.turretRoad(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.turretRoad(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.turretRoad(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.turretRoad(textStyle: textTheme.bodyText2), + caption: GoogleFonts.turretRoad(textStyle: textTheme.caption), + button: GoogleFonts.turretRoad(textStyle: textTheme.button), + overline: GoogleFonts.turretRoad(textStyle: textTheme.overline), + ); + } + + /// Applies the Ubuntu font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ubuntu + static TextStyle ubuntu({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'af68436b9e6b56275cecbabf026fbfa760095b5fc054f802c17ae15dcb4cbf18', + 209640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f1fc680395fdc7b33c4b64324bb4e34779fb8acfbb6d18b837932e0b8d1a69ee', + 235432, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '69538c1ee708ba76c975ea534b5ea8bd65054114da93581ed279bdedde98986c', + 222172, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '191ec3d947057bfaa61cf55e8133a8dfa252400009e628a2141f7aafd3047ca9', + 231260, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c1964f6ef40fc1fdf7599700b74b4446f181c52a6547cac09a325565ad55e639', + 224556, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '02b8cbdca4e9916efc303be2f40666b27aa1928896d3f783fec01f97e23f7f64', + 228072, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd897d5edfc8d1b9f611f1936d05ea7f52b66071ab5f3fa3dbc357cee0e02f204', + 231472, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '5c1ea5c0feab209d1204650845041e13ed77ef6451d9f081711e7d698ba20b52', + 245888, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ubuntu', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ubuntu font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ubuntu + static TextTheme ubuntuTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ubuntu(textStyle: textTheme.headline1), + headline2: GoogleFonts.ubuntu(textStyle: textTheme.headline2), + headline3: GoogleFonts.ubuntu(textStyle: textTheme.headline3), + headline4: GoogleFonts.ubuntu(textStyle: textTheme.headline4), + headline5: GoogleFonts.ubuntu(textStyle: textTheme.headline5), + headline6: GoogleFonts.ubuntu(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ubuntu(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ubuntu(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ubuntu(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ubuntu(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ubuntu(textStyle: textTheme.caption), + button: GoogleFonts.ubuntu(textStyle: textTheme.button), + overline: GoogleFonts.ubuntu(textStyle: textTheme.overline), + ); + } + + /// Applies the Ubuntu Condensed font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ubuntu+Condensed + static TextStyle ubuntuCondensed({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d1044be5c621b9779245f7324c08c3991b0a609d3de1eae6b7f914cd54de315', + 253684, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'UbuntuCondensed', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ubuntu Condensed font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ubuntu+Condensed + static TextTheme ubuntuCondensedTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ubuntuCondensed(textStyle: textTheme.headline1), + headline2: GoogleFonts.ubuntuCondensed(textStyle: textTheme.headline2), + headline3: GoogleFonts.ubuntuCondensed(textStyle: textTheme.headline3), + headline4: GoogleFonts.ubuntuCondensed(textStyle: textTheme.headline4), + headline5: GoogleFonts.ubuntuCondensed(textStyle: textTheme.headline5), + headline6: GoogleFonts.ubuntuCondensed(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ubuntuCondensed(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ubuntuCondensed(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ubuntuCondensed(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ubuntuCondensed(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ubuntuCondensed(textStyle: textTheme.caption), + button: GoogleFonts.ubuntuCondensed(textStyle: textTheme.button), + overline: GoogleFonts.ubuntuCondensed(textStyle: textTheme.overline), + ); + } + + /// Applies the Ubuntu Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ubuntu+Mono + static TextStyle ubuntuMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cd1f8cec4767686edcf755dcde43ac58d83cef21ee96f0e6d850aaf359edd22c', + 115764, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f9935197a4379e2812e72644ce77c4d8bd3f108ff3b23ed5fccb7032f08d6626', + 120736, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7f6a2a5a1eeef3fd539d7cb59119e2a720c33fb75347a47de6c1b4daef4ab63c', + 114936, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '91873d66153347506011f860ea9c87fc36c2ee4ef726bd95cc88c86e0b1ec5f2', + 118912, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'UbuntuMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ubuntu Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ubuntu+Mono + static TextTheme ubuntuMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ubuntuMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.ubuntuMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.ubuntuMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.ubuntuMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.ubuntuMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.ubuntuMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ubuntuMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ubuntuMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ubuntuMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ubuntuMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ubuntuMono(textStyle: textTheme.caption), + button: GoogleFonts.ubuntuMono(textStyle: textTheme.button), + overline: GoogleFonts.ubuntuMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Ultra font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ultra + static TextStyle ultra({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b8f140ef86bd070e1a1d30fffe3069a30b84663f4dbdb628765d5813caa50003', + 52776, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Ultra', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Ultra font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Ultra + static TextTheme ultraTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.ultra(textStyle: textTheme.headline1), + headline2: GoogleFonts.ultra(textStyle: textTheme.headline2), + headline3: GoogleFonts.ultra(textStyle: textTheme.headline3), + headline4: GoogleFonts.ultra(textStyle: textTheme.headline4), + headline5: GoogleFonts.ultra(textStyle: textTheme.headline5), + headline6: GoogleFonts.ultra(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.ultra(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.ultra(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.ultra(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.ultra(textStyle: textTheme.bodyText2), + caption: GoogleFonts.ultra(textStyle: textTheme.caption), + button: GoogleFonts.ultra(textStyle: textTheme.button), + overline: GoogleFonts.ultra(textStyle: textTheme.overline), + ); + } + + /// Applies the Uncial Antiqua font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Uncial+Antiqua + static TextStyle uncialAntiqua({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '88158802093284fa91900c03a6d4ad980decb35d9f668fb97ae46095f6669770', + 62988, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'UncialAntiqua', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Uncial Antiqua font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Uncial+Antiqua + static TextTheme uncialAntiquaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.uncialAntiqua(textStyle: textTheme.headline1), + headline2: GoogleFonts.uncialAntiqua(textStyle: textTheme.headline2), + headline3: GoogleFonts.uncialAntiqua(textStyle: textTheme.headline3), + headline4: GoogleFonts.uncialAntiqua(textStyle: textTheme.headline4), + headline5: GoogleFonts.uncialAntiqua(textStyle: textTheme.headline5), + headline6: GoogleFonts.uncialAntiqua(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.uncialAntiqua(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.uncialAntiqua(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.uncialAntiqua(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.uncialAntiqua(textStyle: textTheme.bodyText2), + caption: GoogleFonts.uncialAntiqua(textStyle: textTheme.caption), + button: GoogleFonts.uncialAntiqua(textStyle: textTheme.button), + overline: GoogleFonts.uncialAntiqua(textStyle: textTheme.overline), + ); + } + + /// Applies the Underdog font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Underdog + static TextStyle underdog({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '02f2cb9d97d94732f703fb34d2332cacf667304208fd69704a5e2ff904dcccff', + 70256, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Underdog', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Underdog font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Underdog + static TextTheme underdogTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.underdog(textStyle: textTheme.headline1), + headline2: GoogleFonts.underdog(textStyle: textTheme.headline2), + headline3: GoogleFonts.underdog(textStyle: textTheme.headline3), + headline4: GoogleFonts.underdog(textStyle: textTheme.headline4), + headline5: GoogleFonts.underdog(textStyle: textTheme.headline5), + headline6: GoogleFonts.underdog(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.underdog(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.underdog(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.underdog(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.underdog(textStyle: textTheme.bodyText2), + caption: GoogleFonts.underdog(textStyle: textTheme.caption), + button: GoogleFonts.underdog(textStyle: textTheme.button), + overline: GoogleFonts.underdog(textStyle: textTheme.overline), + ); + } + + /// Applies the Unica One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Unica+One + static TextStyle unicaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5616e05bc01af9a3a0c6ab46088658b8dfa74ac2b709df893baaefaa711889ed', + 39876, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'UnicaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Unica One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Unica+One + static TextTheme unicaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.unicaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.unicaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.unicaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.unicaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.unicaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.unicaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.unicaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.unicaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.unicaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.unicaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.unicaOne(textStyle: textTheme.caption), + button: GoogleFonts.unicaOne(textStyle: textTheme.button), + overline: GoogleFonts.unicaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the UnifrakturCook font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/UnifrakturCook + static TextStyle unifrakturCook({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '36511c1da21b02a70a6926e12d439ba9c9dba3d5ff0a282c31fa85c4ca96a121', + 41860, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'UnifrakturCook', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the UnifrakturCook font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/UnifrakturCook + static TextTheme unifrakturCookTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.unifrakturCook(textStyle: textTheme.headline1), + headline2: GoogleFonts.unifrakturCook(textStyle: textTheme.headline2), + headline3: GoogleFonts.unifrakturCook(textStyle: textTheme.headline3), + headline4: GoogleFonts.unifrakturCook(textStyle: textTheme.headline4), + headline5: GoogleFonts.unifrakturCook(textStyle: textTheme.headline5), + headline6: GoogleFonts.unifrakturCook(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.unifrakturCook(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.unifrakturCook(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.unifrakturCook(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.unifrakturCook(textStyle: textTheme.bodyText2), + caption: GoogleFonts.unifrakturCook(textStyle: textTheme.caption), + button: GoogleFonts.unifrakturCook(textStyle: textTheme.button), + overline: GoogleFonts.unifrakturCook(textStyle: textTheme.overline), + ); + } + + /// Applies the UnifrakturMaguntia font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/UnifrakturMaguntia + static TextStyle unifrakturMaguntia({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '760d5515a6a9a134ae422f5944056967d7e7d59e1e22b09f4c37caa548229534', + 71824, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'UnifrakturMaguntia', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the UnifrakturMaguntia font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/UnifrakturMaguntia + static TextTheme unifrakturMaguntiaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.headline1), + headline2: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.headline2), + headline3: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.headline3), + headline4: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.headline4), + headline5: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.headline5), + headline6: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.bodyText2), + caption: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.caption), + button: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.button), + overline: GoogleFonts.unifrakturMaguntia(textStyle: textTheme.overline), + ); + } + + /// Applies the Unkempt font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Unkempt + static TextStyle unkempt({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd4f6b7d5ae22a39c55f20fa7871901f21fd6c60c5a788fcf578cf326216a1052', + 191984, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7fd27119b105972e2538d19f5b9fc686ccaf1e10de3d8c7ab7c7d3e0111700dd', + 190680, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Unkempt', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Unkempt font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Unkempt + static TextTheme unkemptTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.unkempt(textStyle: textTheme.headline1), + headline2: GoogleFonts.unkempt(textStyle: textTheme.headline2), + headline3: GoogleFonts.unkempt(textStyle: textTheme.headline3), + headline4: GoogleFonts.unkempt(textStyle: textTheme.headline4), + headline5: GoogleFonts.unkempt(textStyle: textTheme.headline5), + headline6: GoogleFonts.unkempt(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.unkempt(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.unkempt(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.unkempt(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.unkempt(textStyle: textTheme.bodyText2), + caption: GoogleFonts.unkempt(textStyle: textTheme.caption), + button: GoogleFonts.unkempt(textStyle: textTheme.button), + overline: GoogleFonts.unkempt(textStyle: textTheme.overline), + ); + } + + /// Applies the Unlock font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Unlock + static TextStyle unlock({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e9ad989b6ef86cedca3ed0f4a06cc4bb6fbf6dce9c2d5ccd288512d49e861de4', + 27032, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Unlock', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Unlock font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Unlock + static TextTheme unlockTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.unlock(textStyle: textTheme.headline1), + headline2: GoogleFonts.unlock(textStyle: textTheme.headline2), + headline3: GoogleFonts.unlock(textStyle: textTheme.headline3), + headline4: GoogleFonts.unlock(textStyle: textTheme.headline4), + headline5: GoogleFonts.unlock(textStyle: textTheme.headline5), + headline6: GoogleFonts.unlock(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.unlock(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.unlock(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.unlock(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.unlock(textStyle: textTheme.bodyText2), + caption: GoogleFonts.unlock(textStyle: textTheme.caption), + button: GoogleFonts.unlock(textStyle: textTheme.button), + overline: GoogleFonts.unlock(textStyle: textTheme.overline), + ); + } + + /// Applies the Unna font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Unna + static TextStyle unna({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'aa20b27f175098965dc2897d6bb836199b5df9ae3a2e04ce93c359976f4ad15b', + 40900, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'adf583a9103ab9e6d88d247e15e1b9eee56b751099e349c84f7c344391ba5365', + 47428, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ea1c7e13a6450b0389fe43811640a115ceff510dce477813d552533bb8c2a1d', + 41572, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '2c998279cfb60a24fb17f126e193378afe16e6056a7b57ac4cd78b2047759fd8', + 48440, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Unna', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Unna font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Unna + static TextTheme unnaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.unna(textStyle: textTheme.headline1), + headline2: GoogleFonts.unna(textStyle: textTheme.headline2), + headline3: GoogleFonts.unna(textStyle: textTheme.headline3), + headline4: GoogleFonts.unna(textStyle: textTheme.headline4), + headline5: GoogleFonts.unna(textStyle: textTheme.headline5), + headline6: GoogleFonts.unna(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.unna(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.unna(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.unna(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.unna(textStyle: textTheme.bodyText2), + caption: GoogleFonts.unna(textStyle: textTheme.caption), + button: GoogleFonts.unna(textStyle: textTheme.button), + overline: GoogleFonts.unna(textStyle: textTheme.overline), + ); + } + + /// Applies the VT323 font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/VT323 + static TextStyle vt323({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bb4e9d2d01d2cd1a001d4822ed239ffd38df2ee07a6a1f581288f34dbd2f4060', + 107768, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'VT323', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the VT323 font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/VT323 + static TextTheme vt323TextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vt323(textStyle: textTheme.headline1), + headline2: GoogleFonts.vt323(textStyle: textTheme.headline2), + headline3: GoogleFonts.vt323(textStyle: textTheme.headline3), + headline4: GoogleFonts.vt323(textStyle: textTheme.headline4), + headline5: GoogleFonts.vt323(textStyle: textTheme.headline5), + headline6: GoogleFonts.vt323(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vt323(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vt323(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vt323(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vt323(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vt323(textStyle: textTheme.caption), + button: GoogleFonts.vt323(textStyle: textTheme.button), + overline: GoogleFonts.vt323(textStyle: textTheme.overline), + ); + } + + /// Applies the Vampiro One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vampiro+One + static TextStyle vampiroOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'da13d8511c4c84999202a24524c1d204e28aa4fc7d38266b472306622f383317', + 21848, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'VampiroOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Vampiro One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vampiro+One + static TextTheme vampiroOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vampiroOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.vampiroOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.vampiroOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.vampiroOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.vampiroOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.vampiroOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vampiroOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vampiroOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vampiroOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vampiroOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vampiroOne(textStyle: textTheme.caption), + button: GoogleFonts.vampiroOne(textStyle: textTheme.button), + overline: GoogleFonts.vampiroOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Varela font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Varela + static TextStyle varela({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '96887ebd8375ca5af98d18cb1de4dbf2999792851119cd372a33470d59245222', + 103004, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Varela', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Varela font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Varela + static TextTheme varelaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.varela(textStyle: textTheme.headline1), + headline2: GoogleFonts.varela(textStyle: textTheme.headline2), + headline3: GoogleFonts.varela(textStyle: textTheme.headline3), + headline4: GoogleFonts.varela(textStyle: textTheme.headline4), + headline5: GoogleFonts.varela(textStyle: textTheme.headline5), + headline6: GoogleFonts.varela(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.varela(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.varela(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.varela(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.varela(textStyle: textTheme.bodyText2), + caption: GoogleFonts.varela(textStyle: textTheme.caption), + button: GoogleFonts.varela(textStyle: textTheme.button), + overline: GoogleFonts.varela(textStyle: textTheme.overline), + ); + } + + /// Applies the Varela Round font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Varela+Round + static TextStyle varelaRound({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '23459f7eed93ae80137b9ac0c3c1ab000743c9c983fb7c14b6d5f3ceb8e4eb15', + 105652, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'VarelaRound', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Varela Round font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Varela+Round + static TextTheme varelaRoundTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.varelaRound(textStyle: textTheme.headline1), + headline2: GoogleFonts.varelaRound(textStyle: textTheme.headline2), + headline3: GoogleFonts.varelaRound(textStyle: textTheme.headline3), + headline4: GoogleFonts.varelaRound(textStyle: textTheme.headline4), + headline5: GoogleFonts.varelaRound(textStyle: textTheme.headline5), + headline6: GoogleFonts.varelaRound(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.varelaRound(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.varelaRound(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.varelaRound(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.varelaRound(textStyle: textTheme.bodyText2), + caption: GoogleFonts.varelaRound(textStyle: textTheme.caption), + button: GoogleFonts.varelaRound(textStyle: textTheme.button), + overline: GoogleFonts.varelaRound(textStyle: textTheme.overline), + ); + } + + /// Applies the Varta font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Varta + static TextStyle varta({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '2aea56851bc37f1bd42371e8851887d38d8da945897da94b4bda866332ef0358', + 59232, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9b04506911ea313ea9e8ddcd0acb91527b5726610ef716c8a52d301598b263d4', + 59200, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'afeb9cdc53886d1866c52d07df6bf4078bebaa70062b192491f8ba4181fafea6', + 59192, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cc2323f655465146d3347dddfb6fc3eb3b1017bbce627740e8c45e1b001d0df2', + 59216, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b1f85e3bc0f474c35e402ac2196cb76aad8fd65cb372d3bff84dcf25b4fc63ba', + 59104, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Varta', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Varta font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Varta + static TextTheme vartaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.varta(textStyle: textTheme.headline1), + headline2: GoogleFonts.varta(textStyle: textTheme.headline2), + headline3: GoogleFonts.varta(textStyle: textTheme.headline3), + headline4: GoogleFonts.varta(textStyle: textTheme.headline4), + headline5: GoogleFonts.varta(textStyle: textTheme.headline5), + headline6: GoogleFonts.varta(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.varta(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.varta(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.varta(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.varta(textStyle: textTheme.bodyText2), + caption: GoogleFonts.varta(textStyle: textTheme.caption), + button: GoogleFonts.varta(textStyle: textTheme.button), + overline: GoogleFonts.varta(textStyle: textTheme.overline), + ); + } + + /// Applies the Vast Shadow font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vast+Shadow + static TextStyle vastShadow({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c7455e059437040326c4daa3043261ce959c3f096f26dbe670dec65d1a611705', + 62316, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'VastShadow', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Vast Shadow font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vast+Shadow + static TextTheme vastShadowTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vastShadow(textStyle: textTheme.headline1), + headline2: GoogleFonts.vastShadow(textStyle: textTheme.headline2), + headline3: GoogleFonts.vastShadow(textStyle: textTheme.headline3), + headline4: GoogleFonts.vastShadow(textStyle: textTheme.headline4), + headline5: GoogleFonts.vastShadow(textStyle: textTheme.headline5), + headline6: GoogleFonts.vastShadow(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vastShadow(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vastShadow(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vastShadow(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vastShadow(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vastShadow(textStyle: textTheme.caption), + button: GoogleFonts.vastShadow(textStyle: textTheme.button), + overline: GoogleFonts.vastShadow(textStyle: textTheme.overline), + ); + } + + /// Applies the Vesper Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vesper+Libre + static TextStyle vesperLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '23ebf9650e07e0d9fc46ae2eba26ac2ec4ce96fb1c5dfe8d1e68697caa450075', + 165640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0d1943717826e25f00193643ca5cef6a8e84d9949f43eea2e7fcbbcf7eac6472', + 167888, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c45aa4f922411d07c89ae4f96d05177e84e280aecdda0fdee999b1a617b4c1ce', + 167692, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0f6179f3446d68f20aa486aed461cc68f86028fd02217a13559a2bf5c3e60702', + 165240, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'VesperLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Vesper Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vesper+Libre + static TextTheme vesperLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vesperLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.vesperLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.vesperLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.vesperLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.vesperLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.vesperLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vesperLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vesperLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vesperLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vesperLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vesperLibre(textStyle: textTheme.caption), + button: GoogleFonts.vesperLibre(textStyle: textTheme.button), + overline: GoogleFonts.vesperLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Viaoda Libre font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Viaoda+Libre + static TextStyle viaodaLibre({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4c7e54848245264f0ecb5994ce321b185812cc6e451cdd2fc341d8f505686dd4', + 95364, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ViaodaLibre', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Viaoda Libre font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Viaoda+Libre + static TextTheme viaodaLibreTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.viaodaLibre(textStyle: textTheme.headline1), + headline2: GoogleFonts.viaodaLibre(textStyle: textTheme.headline2), + headline3: GoogleFonts.viaodaLibre(textStyle: textTheme.headline3), + headline4: GoogleFonts.viaodaLibre(textStyle: textTheme.headline4), + headline5: GoogleFonts.viaodaLibre(textStyle: textTheme.headline5), + headline6: GoogleFonts.viaodaLibre(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.viaodaLibre(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.viaodaLibre(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.viaodaLibre(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.viaodaLibre(textStyle: textTheme.bodyText2), + caption: GoogleFonts.viaodaLibre(textStyle: textTheme.caption), + button: GoogleFonts.viaodaLibre(textStyle: textTheme.button), + overline: GoogleFonts.viaodaLibre(textStyle: textTheme.overline), + ); + } + + /// Applies the Vibes font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vibes + static TextStyle vibes({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '270c48b74a5e6a356c51d4c42ec0a6889691ba3d2ec03f0bbec16078d2ac9093', + 49952, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Vibes', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Vibes font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vibes + static TextTheme vibesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vibes(textStyle: textTheme.headline1), + headline2: GoogleFonts.vibes(textStyle: textTheme.headline2), + headline3: GoogleFonts.vibes(textStyle: textTheme.headline3), + headline4: GoogleFonts.vibes(textStyle: textTheme.headline4), + headline5: GoogleFonts.vibes(textStyle: textTheme.headline5), + headline6: GoogleFonts.vibes(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vibes(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vibes(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vibes(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vibes(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vibes(textStyle: textTheme.caption), + button: GoogleFonts.vibes(textStyle: textTheme.button), + overline: GoogleFonts.vibes(textStyle: textTheme.overline), + ); + } + + /// Applies the Vibur font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vibur + static TextStyle vibur({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4a341a2553f7bac9bf3d756c88bdb1a67934839f2a343ef00268f04d641803f8', + 143772, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Vibur', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Vibur font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vibur + static TextTheme viburTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vibur(textStyle: textTheme.headline1), + headline2: GoogleFonts.vibur(textStyle: textTheme.headline2), + headline3: GoogleFonts.vibur(textStyle: textTheme.headline3), + headline4: GoogleFonts.vibur(textStyle: textTheme.headline4), + headline5: GoogleFonts.vibur(textStyle: textTheme.headline5), + headline6: GoogleFonts.vibur(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vibur(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vibur(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vibur(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vibur(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vibur(textStyle: textTheme.caption), + button: GoogleFonts.vibur(textStyle: textTheme.button), + overline: GoogleFonts.vibur(textStyle: textTheme.overline), + ); + } + + /// Applies the Vidaloka font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vidaloka + static TextStyle vidaloka({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '222cf887f6f4ef0661c73aee6ad041d0d4e6630c7d2bff7e851025a024b44cfd', + 104304, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Vidaloka', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Vidaloka font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vidaloka + static TextTheme vidalokaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vidaloka(textStyle: textTheme.headline1), + headline2: GoogleFonts.vidaloka(textStyle: textTheme.headline2), + headline3: GoogleFonts.vidaloka(textStyle: textTheme.headline3), + headline4: GoogleFonts.vidaloka(textStyle: textTheme.headline4), + headline5: GoogleFonts.vidaloka(textStyle: textTheme.headline5), + headline6: GoogleFonts.vidaloka(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vidaloka(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vidaloka(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vidaloka(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vidaloka(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vidaloka(textStyle: textTheme.caption), + button: GoogleFonts.vidaloka(textStyle: textTheme.button), + overline: GoogleFonts.vidaloka(textStyle: textTheme.overline), + ); + } + + /// Applies the Viga font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Viga + static TextStyle viga({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd85fc50295193b5956d4737878484d6ec2b1681053e75a2c986238285e1ac681', + 28388, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Viga', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Viga font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Viga + static TextTheme vigaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.viga(textStyle: textTheme.headline1), + headline2: GoogleFonts.viga(textStyle: textTheme.headline2), + headline3: GoogleFonts.viga(textStyle: textTheme.headline3), + headline4: GoogleFonts.viga(textStyle: textTheme.headline4), + headline5: GoogleFonts.viga(textStyle: textTheme.headline5), + headline6: GoogleFonts.viga(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.viga(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.viga(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.viga(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.viga(textStyle: textTheme.bodyText2), + caption: GoogleFonts.viga(textStyle: textTheme.caption), + button: GoogleFonts.viga(textStyle: textTheme.button), + overline: GoogleFonts.viga(textStyle: textTheme.overline), + ); + } + + /// Applies the Voces font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Voces + static TextStyle voces({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0be995322d0fd8e055fc6d3cb9352a0c551e91531d41946d20c450fe3e4c20d8', + 65956, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Voces', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Voces font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Voces + static TextTheme vocesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.voces(textStyle: textTheme.headline1), + headline2: GoogleFonts.voces(textStyle: textTheme.headline2), + headline3: GoogleFonts.voces(textStyle: textTheme.headline3), + headline4: GoogleFonts.voces(textStyle: textTheme.headline4), + headline5: GoogleFonts.voces(textStyle: textTheme.headline5), + headline6: GoogleFonts.voces(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.voces(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.voces(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.voces(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.voces(textStyle: textTheme.bodyText2), + caption: GoogleFonts.voces(textStyle: textTheme.caption), + button: GoogleFonts.voces(textStyle: textTheme.button), + overline: GoogleFonts.voces(textStyle: textTheme.overline), + ); + } + + /// Applies the Volkhov font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Volkhov + static TextStyle volkhov({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a3fa059553ab62381a8974ef60376b4bad0e91f2d72092094e74fb1c2fcca886', + 84908, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '7d27f866b8f11b00603bcc07b2e7ae49e4405fde4b3db227065ad57f92b8953c', + 84532, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f24fe6c57bdf816d9c6e09602548002ca61aca7eec23b40635c4a46f84347d47', + 84288, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '0db6f541c0e1a1f792feaacd69708e50b99aabf1ada6028e80fca14cfafe030c', + 85744, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Volkhov', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Volkhov font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Volkhov + static TextTheme volkhovTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.volkhov(textStyle: textTheme.headline1), + headline2: GoogleFonts.volkhov(textStyle: textTheme.headline2), + headline3: GoogleFonts.volkhov(textStyle: textTheme.headline3), + headline4: GoogleFonts.volkhov(textStyle: textTheme.headline4), + headline5: GoogleFonts.volkhov(textStyle: textTheme.headline5), + headline6: GoogleFonts.volkhov(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.volkhov(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.volkhov(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.volkhov(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.volkhov(textStyle: textTheme.bodyText2), + caption: GoogleFonts.volkhov(textStyle: textTheme.caption), + button: GoogleFonts.volkhov(textStyle: textTheme.button), + overline: GoogleFonts.volkhov(textStyle: textTheme.overline), + ); + } + + /// Applies the Vollkorn font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vollkorn + static TextStyle vollkorn({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9fd84335b1beb10505c201815682f7b543aa429a5a909e8b2126f15d36a0705a', + 262424, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '784ba33f30493ef78ca0217d7f6c243c8bf7bec2cd1b9c4d813af99941bf730e', + 271752, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9d702c22f1d2ea4a1521efff825d5c362adca54b6fbe2343ab2ed6b7e2119610', + 276280, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '6cd6efd288ac8587690f7a7f5788bea147c0c5432224a04874dc4494a8691955', + 279348, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '14aa1fb5f42a8088a0d91ca54dbc7d6eea615db621929c7bdc35ae4a6c64fcb5', + 276384, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'ef717b899e1af61e2a62cfed23623b0d5c844e2745616be4a949bf84f6e7457e', + 279732, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '14e5d20d80ab9df765ef117415850050320fa766eb246296c67924737f88c2d1', + 272880, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '3953dfef7c1118f089612462105779d89da8f9df1aa11b74a8b2a58bb8359a44', + 272552, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Vollkorn', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Vollkorn font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vollkorn + static TextTheme vollkornTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vollkorn(textStyle: textTheme.headline1), + headline2: GoogleFonts.vollkorn(textStyle: textTheme.headline2), + headline3: GoogleFonts.vollkorn(textStyle: textTheme.headline3), + headline4: GoogleFonts.vollkorn(textStyle: textTheme.headline4), + headline5: GoogleFonts.vollkorn(textStyle: textTheme.headline5), + headline6: GoogleFonts.vollkorn(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vollkorn(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vollkorn(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vollkorn(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vollkorn(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vollkorn(textStyle: textTheme.caption), + button: GoogleFonts.vollkorn(textStyle: textTheme.button), + overline: GoogleFonts.vollkorn(textStyle: textTheme.overline), + ); + } + + /// Applies the Vollkorn SC font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vollkorn+SC + static TextStyle vollkornSc({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '3a204e8e6e256d182887114991a86b3853bd7b370eb298c5c5358a4924e94326', + 145820, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c3f8bc857ab58e19ba62ee008373ba5b707f586065cc0a59e68cf3781b1075f5', + 150112, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0281449b729b1b8cb680dbcd00fd7d2e9d40ff24c858a834e3670997a561aea3', + 150144, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b95dc90d6b58551cd5cadf844986de95a70432ebf303eaf23270184113144a67', + 149088, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'VollkornSC', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Vollkorn SC font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Vollkorn+SC + static TextTheme vollkornScTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.vollkornSc(textStyle: textTheme.headline1), + headline2: GoogleFonts.vollkornSc(textStyle: textTheme.headline2), + headline3: GoogleFonts.vollkornSc(textStyle: textTheme.headline3), + headline4: GoogleFonts.vollkornSc(textStyle: textTheme.headline4), + headline5: GoogleFonts.vollkornSc(textStyle: textTheme.headline5), + headline6: GoogleFonts.vollkornSc(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.vollkornSc(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.vollkornSc(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.vollkornSc(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.vollkornSc(textStyle: textTheme.bodyText2), + caption: GoogleFonts.vollkornSc(textStyle: textTheme.caption), + button: GoogleFonts.vollkornSc(textStyle: textTheme.button), + overline: GoogleFonts.vollkornSc(textStyle: textTheme.overline), + ); + } + + /// Applies the Voltaire font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Voltaire + static TextStyle voltaire({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '8e446b1dcde5e45745bd6e82bfacf76b313042b232e4fceaa22d745f13e176d3', + 28800, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Voltaire', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Voltaire font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Voltaire + static TextTheme voltaireTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.voltaire(textStyle: textTheme.headline1), + headline2: GoogleFonts.voltaire(textStyle: textTheme.headline2), + headline3: GoogleFonts.voltaire(textStyle: textTheme.headline3), + headline4: GoogleFonts.voltaire(textStyle: textTheme.headline4), + headline5: GoogleFonts.voltaire(textStyle: textTheme.headline5), + headline6: GoogleFonts.voltaire(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.voltaire(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.voltaire(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.voltaire(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.voltaire(textStyle: textTheme.bodyText2), + caption: GoogleFonts.voltaire(textStyle: textTheme.caption), + button: GoogleFonts.voltaire(textStyle: textTheme.button), + overline: GoogleFonts.voltaire(textStyle: textTheme.overline), + ); + } + + /// Applies the Waiting for the Sunrise font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Waiting+for+the+Sunrise + static TextStyle waitingForTheSunrise({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5d952514968d1ce922a541f2099d884967f1970682676c3f1cca1b4668f07ff1', + 57412, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'WaitingfortheSunrise', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Waiting for the Sunrise font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Waiting+for+the+Sunrise + static TextTheme waitingForTheSunriseTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.headline1), + headline2: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.headline2), + headline3: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.headline3), + headline4: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.headline4), + headline5: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.headline5), + headline6: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.waitingForTheSunrise(textStyle: textTheme.bodyText2), + caption: GoogleFonts.waitingForTheSunrise(textStyle: textTheme.caption), + button: GoogleFonts.waitingForTheSunrise(textStyle: textTheme.button), + overline: GoogleFonts.waitingForTheSunrise(textStyle: textTheme.overline), + ); + } + + /// Applies the Wallpoet font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Wallpoet + static TextStyle wallpoet({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9989a07c4d82441ed4366747a76f537b925a6d9f691e7b0cd97713bcac160b20', + 22488, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Wallpoet', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Wallpoet font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Wallpoet + static TextTheme wallpoetTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.wallpoet(textStyle: textTheme.headline1), + headline2: GoogleFonts.wallpoet(textStyle: textTheme.headline2), + headline3: GoogleFonts.wallpoet(textStyle: textTheme.headline3), + headline4: GoogleFonts.wallpoet(textStyle: textTheme.headline4), + headline5: GoogleFonts.wallpoet(textStyle: textTheme.headline5), + headline6: GoogleFonts.wallpoet(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.wallpoet(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.wallpoet(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.wallpoet(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.wallpoet(textStyle: textTheme.bodyText2), + caption: GoogleFonts.wallpoet(textStyle: textTheme.caption), + button: GoogleFonts.wallpoet(textStyle: textTheme.button), + overline: GoogleFonts.wallpoet(textStyle: textTheme.overline), + ); + } + + /// Applies the Walter Turncoat font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Walter+Turncoat + static TextStyle walterTurncoat({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ea002cd3a82b6686a400f26ba3da2fa47721b8300266adcc80cc3fbd52a86a3', + 153452, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'WalterTurncoat', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Walter Turncoat font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Walter+Turncoat + static TextTheme walterTurncoatTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.walterTurncoat(textStyle: textTheme.headline1), + headline2: GoogleFonts.walterTurncoat(textStyle: textTheme.headline2), + headline3: GoogleFonts.walterTurncoat(textStyle: textTheme.headline3), + headline4: GoogleFonts.walterTurncoat(textStyle: textTheme.headline4), + headline5: GoogleFonts.walterTurncoat(textStyle: textTheme.headline5), + headline6: GoogleFonts.walterTurncoat(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.walterTurncoat(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.walterTurncoat(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.walterTurncoat(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.walterTurncoat(textStyle: textTheme.bodyText2), + caption: GoogleFonts.walterTurncoat(textStyle: textTheme.caption), + button: GoogleFonts.walterTurncoat(textStyle: textTheme.button), + overline: GoogleFonts.walterTurncoat(textStyle: textTheme.overline), + ); + } + + /// Applies the Warnes font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Warnes + static TextStyle warnes({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '509079dd5c127782c43242772c6a327f4e16ede0d28f7d18b01e7092b4e902c8', + 41620, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Warnes', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Warnes font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Warnes + static TextTheme warnesTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.warnes(textStyle: textTheme.headline1), + headline2: GoogleFonts.warnes(textStyle: textTheme.headline2), + headline3: GoogleFonts.warnes(textStyle: textTheme.headline3), + headline4: GoogleFonts.warnes(textStyle: textTheme.headline4), + headline5: GoogleFonts.warnes(textStyle: textTheme.headline5), + headline6: GoogleFonts.warnes(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.warnes(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.warnes(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.warnes(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.warnes(textStyle: textTheme.bodyText2), + caption: GoogleFonts.warnes(textStyle: textTheme.caption), + button: GoogleFonts.warnes(textStyle: textTheme.button), + overline: GoogleFonts.warnes(textStyle: textTheme.overline), + ); + } + + /// Applies the Wellfleet font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Wellfleet + static TextStyle wellfleet({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9bdc76fbcd0c8aa30aa62c892008d4e6cf4a7df66502008137949866fc091693', + 81992, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Wellfleet', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Wellfleet font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Wellfleet + static TextTheme wellfleetTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.wellfleet(textStyle: textTheme.headline1), + headline2: GoogleFonts.wellfleet(textStyle: textTheme.headline2), + headline3: GoogleFonts.wellfleet(textStyle: textTheme.headline3), + headline4: GoogleFonts.wellfleet(textStyle: textTheme.headline4), + headline5: GoogleFonts.wellfleet(textStyle: textTheme.headline5), + headline6: GoogleFonts.wellfleet(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.wellfleet(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.wellfleet(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.wellfleet(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.wellfleet(textStyle: textTheme.bodyText2), + caption: GoogleFonts.wellfleet(textStyle: textTheme.caption), + button: GoogleFonts.wellfleet(textStyle: textTheme.button), + overline: GoogleFonts.wellfleet(textStyle: textTheme.overline), + ); + } + + /// Applies the Wendy One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Wendy+One + static TextStyle wendyOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dea9bd8409f75210fc0600c72f08d7b21019e5e663c7dcff913dc8f003587379', + 22724, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'WendyOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Wendy One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Wendy+One + static TextTheme wendyOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.wendyOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.wendyOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.wendyOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.wendyOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.wendyOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.wendyOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.wendyOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.wendyOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.wendyOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.wendyOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.wendyOne(textStyle: textTheme.caption), + button: GoogleFonts.wendyOne(textStyle: textTheme.button), + overline: GoogleFonts.wendyOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Wire One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Wire+One + static TextStyle wireOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6d9ba7749b319a53d24a41f6cbfd1b376305caee6bb226d4fb76fa6c9ccb2737', + 44392, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'WireOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Wire One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Wire+One + static TextTheme wireOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.wireOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.wireOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.wireOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.wireOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.wireOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.wireOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.wireOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.wireOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.wireOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.wireOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.wireOne(textStyle: textTheme.caption), + button: GoogleFonts.wireOne(textStyle: textTheme.button), + overline: GoogleFonts.wireOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Work Sans font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Work+Sans + static TextStyle workSans({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '54ff7c3cb9bfd181e1d18d089ab9bba3059dd6f49d35bfde19c23e0920ec6f2c', + 101768, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1fa02ec2601b669a35f4c2d946f2e52353bcf619ad2a080c8786f607f013359c', + 103092, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '63d2d7d98c9844e182c80865616936a3c0e95d9c9b7097e09401ccc07723afa7', + 102672, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cf9e214b6a140d6d260a7a91283acecf80168bd0b46628222447e9b5e01300a2', + 99188, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '1ca28e13541a38be971563ecc74ed68ad07134d3ea3afe92a9c120783868b69d', + 104640, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'a7415d89db9339059ee631263f3cd47af702c172d1b020fa359df0e5a4930e6b', + 104368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd41209fc541bdf9f9bac4659e46565edc93459f6c6f7213015af82b7d3e7e00b', + 103884, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w800, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c9cca774aabfe453b9c2759953dedeb20f16d6eb28c0ba7690a170580c338d72', + 104120, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '7cdc1c327ea835b192ef17b0f0bff1a16fc58f8ab00bc318b41912f4758b2905', + 97388, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'WorkSans', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Work Sans font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Work+Sans + static TextTheme workSansTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.workSans(textStyle: textTheme.headline1), + headline2: GoogleFonts.workSans(textStyle: textTheme.headline2), + headline3: GoogleFonts.workSans(textStyle: textTheme.headline3), + headline4: GoogleFonts.workSans(textStyle: textTheme.headline4), + headline5: GoogleFonts.workSans(textStyle: textTheme.headline5), + headline6: GoogleFonts.workSans(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.workSans(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.workSans(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.workSans(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.workSans(textStyle: textTheme.bodyText2), + caption: GoogleFonts.workSans(textStyle: textTheme.caption), + button: GoogleFonts.workSans(textStyle: textTheme.button), + overline: GoogleFonts.workSans(textStyle: textTheme.overline), + ); + } + + /// Applies the Xanh Mono font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Xanh+Mono + static TextStyle xanhMono({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bc590c4a0c719a3c555ab48c1de299db800f5ecdef7513b712a22392951ed119', + 38648, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '481a22208d7f528069ac13b1f1c67837e9cbad6e73b4feb6368a0dce2bf6faf1', + 41664, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'XanhMono', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Xanh Mono font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Xanh+Mono + static TextTheme xanhMonoTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.xanhMono(textStyle: textTheme.headline1), + headline2: GoogleFonts.xanhMono(textStyle: textTheme.headline2), + headline3: GoogleFonts.xanhMono(textStyle: textTheme.headline3), + headline4: GoogleFonts.xanhMono(textStyle: textTheme.headline4), + headline5: GoogleFonts.xanhMono(textStyle: textTheme.headline5), + headline6: GoogleFonts.xanhMono(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.xanhMono(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.xanhMono(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.xanhMono(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.xanhMono(textStyle: textTheme.bodyText2), + caption: GoogleFonts.xanhMono(textStyle: textTheme.caption), + button: GoogleFonts.xanhMono(textStyle: textTheme.button), + overline: GoogleFonts.xanhMono(textStyle: textTheme.overline), + ); + } + + /// Applies the Yanone Kaffeesatz font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yanone+Kaffeesatz + static TextStyle yanoneKaffeesatz({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w200, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9805245cc2de9c8da9ae786c7e17ac2da9f93c7b2ba3cc8f481e28eb05146193', + 73564, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'd9ed8432723bd4d507a98d52dc50b9852ac3d6456e0fbcf9bf639b19982af563', + 83844, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'c590a52e12f62af4fec495eae613bff7aa7763fb2c5bec48e1db96503ba91c1b', + 84008, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '5245342d46c5e01aaa2e808a7962687a57c7ffaad83ff05db327e9fbf28d79c0', + 84004, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'YanoneKaffeesatz', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yanone Kaffeesatz font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yanone+Kaffeesatz + static TextTheme yanoneKaffeesatzTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.headline1), + headline2: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.headline2), + headline3: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.headline3), + headline4: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.headline4), + headline5: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.headline5), + headline6: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.caption), + button: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.button), + overline: GoogleFonts.yanoneKaffeesatz(textStyle: textTheme.overline), + ); + } + + /// Applies the Yantramanav font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yantramanav + static TextStyle yantramanav({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '86689d7a0f2e854d67499f3b138d736bbc906760e4ce2965a494ede2bd7bebca', + 101432, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '4ab0f6ae96b7ee1e64385a964c2e10db696f46e64a3c7e9966131d0a0e2d4584', + 99760, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '41c02d7da7c104c3ea5207122b178f4cbcf308b4911dbc4e4a460b23ba64f09e', + 99620, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '14362b0efe1ebbde59b45ed4e1f345c1a41e777d03fce97684b6bd8b67ecc385', + 98608, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6036c39566fdfe4d7a96f8959775282729df41c691b5791efb80a530d96732e6', + 99004, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w900, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '117b18180127afc0bb9a28d0aa5d5aa9bcd8090b84d34a9adf571661c1896578', + 98880, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Yantramanav', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yantramanav font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yantramanav + static TextTheme yantramanavTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yantramanav(textStyle: textTheme.headline1), + headline2: GoogleFonts.yantramanav(textStyle: textTheme.headline2), + headline3: GoogleFonts.yantramanav(textStyle: textTheme.headline3), + headline4: GoogleFonts.yantramanav(textStyle: textTheme.headline4), + headline5: GoogleFonts.yantramanav(textStyle: textTheme.headline5), + headline6: GoogleFonts.yantramanav(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yantramanav(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yantramanav(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yantramanav(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yantramanav(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yantramanav(textStyle: textTheme.caption), + button: GoogleFonts.yantramanav(textStyle: textTheme.button), + overline: GoogleFonts.yantramanav(textStyle: textTheme.overline), + ); + } + + /// Applies the Yatra One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yatra+One + static TextStyle yatraOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '91d2a8a128a89559c899d8149591b1704546ba00b04c2d0f50dd252f57a00bfb', + 204892, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'YatraOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yatra One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yatra+One + static TextTheme yatraOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yatraOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.yatraOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.yatraOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.yatraOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.yatraOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.yatraOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yatraOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yatraOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yatraOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yatraOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yatraOne(textStyle: textTheme.caption), + button: GoogleFonts.yatraOne(textStyle: textTheme.button), + overline: GoogleFonts.yatraOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Yellowtail font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yellowtail + static TextStyle yellowtail({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f5afc3345b05f159df8c09f953eacbf365a0d81f5cecccb4fa7b7407284baca9', + 62400, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Yellowtail', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yellowtail font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yellowtail + static TextTheme yellowtailTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yellowtail(textStyle: textTheme.headline1), + headline2: GoogleFonts.yellowtail(textStyle: textTheme.headline2), + headline3: GoogleFonts.yellowtail(textStyle: textTheme.headline3), + headline4: GoogleFonts.yellowtail(textStyle: textTheme.headline4), + headline5: GoogleFonts.yellowtail(textStyle: textTheme.headline5), + headline6: GoogleFonts.yellowtail(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yellowtail(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yellowtail(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yellowtail(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yellowtail(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yellowtail(textStyle: textTheme.caption), + button: GoogleFonts.yellowtail(textStyle: textTheme.button), + overline: GoogleFonts.yellowtail(textStyle: textTheme.overline), + ); + } + + /// Applies the Yeon Sung font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yeon+Sung + static TextStyle yeonSung({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'cc6d366c352d7d897155bde07516cd01c0fcd308ff28d0d6545d6634046cecec', + 1698768, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'YeonSung', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yeon Sung font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yeon+Sung + static TextTheme yeonSungTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yeonSung(textStyle: textTheme.headline1), + headline2: GoogleFonts.yeonSung(textStyle: textTheme.headline2), + headline3: GoogleFonts.yeonSung(textStyle: textTheme.headline3), + headline4: GoogleFonts.yeonSung(textStyle: textTheme.headline4), + headline5: GoogleFonts.yeonSung(textStyle: textTheme.headline5), + headline6: GoogleFonts.yeonSung(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yeonSung(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yeonSung(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yeonSung(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yeonSung(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yeonSung(textStyle: textTheme.caption), + button: GoogleFonts.yeonSung(textStyle: textTheme.button), + overline: GoogleFonts.yeonSung(textStyle: textTheme.overline), + ); + } + + /// Applies the Yeseva One font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yeseva+One + static TextStyle yesevaOne({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '326eec1af27e3634bbf470c04d8127d985571a07b5b79696eb6424489e27e106', + 74612, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'YesevaOne', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yeseva One font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yeseva+One + static TextTheme yesevaOneTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yesevaOne(textStyle: textTheme.headline1), + headline2: GoogleFonts.yesevaOne(textStyle: textTheme.headline2), + headline3: GoogleFonts.yesevaOne(textStyle: textTheme.headline3), + headline4: GoogleFonts.yesevaOne(textStyle: textTheme.headline4), + headline5: GoogleFonts.yesevaOne(textStyle: textTheme.headline5), + headline6: GoogleFonts.yesevaOne(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yesevaOne(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yesevaOne(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yesevaOne(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yesevaOne(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yesevaOne(textStyle: textTheme.caption), + button: GoogleFonts.yesevaOne(textStyle: textTheme.button), + overline: GoogleFonts.yesevaOne(textStyle: textTheme.overline), + ); + } + + /// Applies the Yesteryear font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yesteryear + static TextStyle yesteryear({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'de930d7a2b4adea15c08668114a1672322e74ae93b6b134e78a953c6789ea86d', + 64440, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Yesteryear', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yesteryear font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yesteryear + static TextTheme yesteryearTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yesteryear(textStyle: textTheme.headline1), + headline2: GoogleFonts.yesteryear(textStyle: textTheme.headline2), + headline3: GoogleFonts.yesteryear(textStyle: textTheme.headline3), + headline4: GoogleFonts.yesteryear(textStyle: textTheme.headline4), + headline5: GoogleFonts.yesteryear(textStyle: textTheme.headline5), + headline6: GoogleFonts.yesteryear(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yesteryear(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yesteryear(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yesteryear(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yesteryear(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yesteryear(textStyle: textTheme.caption), + button: GoogleFonts.yesteryear(textStyle: textTheme.button), + overline: GoogleFonts.yesteryear(textStyle: textTheme.overline), + ); + } + + /// Applies the Yrsa font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yrsa + static TextStyle yrsa({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'b942444580e24561d6008f08b6b3145662d902d140408e9f6c92ee7cd5affa00', + 57928, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '9782370d37625db345595b8f48ae5156b4c8256cd4867b119af3114faa566686', + 58404, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '61c4e4c03498db5ec4f926576603b2102fac9f90b73b7aafe7e6ebadc30444b0', + 58364, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dd8f96acf795a40fc16730d309bc4a64f1f21d96ac4e93763611cee5539b77f9', + 58352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '94de8af1023c6dab0ffcb86966c85582afca7392a0c3377cd0f1cb536c9d095c', + 58252, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Yrsa', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yrsa font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yrsa + static TextTheme yrsaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yrsa(textStyle: textTheme.headline1), + headline2: GoogleFonts.yrsa(textStyle: textTheme.headline2), + headline3: GoogleFonts.yrsa(textStyle: textTheme.headline3), + headline4: GoogleFonts.yrsa(textStyle: textTheme.headline4), + headline5: GoogleFonts.yrsa(textStyle: textTheme.headline5), + headline6: GoogleFonts.yrsa(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yrsa(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yrsa(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yrsa(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yrsa(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yrsa(textStyle: textTheme.caption), + button: GoogleFonts.yrsa(textStyle: textTheme.button), + overline: GoogleFonts.yrsa(textStyle: textTheme.overline), + ); + } + + /// Applies the Yusei Magic font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yusei+Magic + static TextStyle yuseiMagic({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '16d55d48fe2bfe47ec060bfdd4c140508f2bfa0587db2478e1717aa2663880ca', + 3129996, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'YuseiMagic', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Yusei Magic font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Yusei+Magic + static TextTheme yuseiMagicTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.yuseiMagic(textStyle: textTheme.headline1), + headline2: GoogleFonts.yuseiMagic(textStyle: textTheme.headline2), + headline3: GoogleFonts.yuseiMagic(textStyle: textTheme.headline3), + headline4: GoogleFonts.yuseiMagic(textStyle: textTheme.headline4), + headline5: GoogleFonts.yuseiMagic(textStyle: textTheme.headline5), + headline6: GoogleFonts.yuseiMagic(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.yuseiMagic(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.yuseiMagic(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.yuseiMagic(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.yuseiMagic(textStyle: textTheme.bodyText2), + caption: GoogleFonts.yuseiMagic(textStyle: textTheme.caption), + button: GoogleFonts.yuseiMagic(textStyle: textTheme.button), + overline: GoogleFonts.yuseiMagic(textStyle: textTheme.overline), + ); + } + + /// Applies the ZCOOL KuaiLe font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/ZCOOL+KuaiLe + static TextStyle zcoolKuaiLe({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0809b4605f58fdd321743ae7e5b76d4ac6c2153fe0b5b7185dd12c1974659c00', + 1509564, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ZCOOLKuaiLe', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the ZCOOL KuaiLe font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/ZCOOL+KuaiLe + static TextTheme zcoolKuaiLeTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.headline1), + headline2: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.headline2), + headline3: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.headline3), + headline4: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.headline4), + headline5: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.headline5), + headline6: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.bodyText2), + caption: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.caption), + button: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.button), + overline: GoogleFonts.zcoolKuaiLe(textStyle: textTheme.overline), + ); + } + + /// Applies the ZCOOL QingKe HuangYou font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/ZCOOL+QingKe+HuangYou + static TextStyle zcoolQingKeHuangYou({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dca9156773f9e058aafeaded91d3d5e64e41a67187907e37a66210e708d3dc73', + 5827424, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ZCOOLQingKeHuangYou', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the ZCOOL QingKe HuangYou font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/ZCOOL+QingKe+HuangYou + static TextTheme zcoolQingKeHuangYouTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.headline1), + headline2: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.headline2), + headline3: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.headline3), + headline4: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.headline4), + headline5: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.headline5), + headline6: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.headline6), + subtitle1: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.subtitle1), + subtitle2: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.subtitle2), + bodyText1: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.bodyText1), + bodyText2: + GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.bodyText2), + caption: GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.caption), + button: GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.button), + overline: GoogleFonts.zcoolQingKeHuangYou(textStyle: textTheme.overline), + ); + } + + /// Applies the ZCOOL XiaoWei font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/ZCOOL+XiaoWei + static TextStyle zcoolXiaoWei({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'e00b956bf9846285496c54d15ad3e2d6302a4c7d6f7a09c4afd4827744d626e9', + 3917592, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ZCOOLXiaoWei', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the ZCOOL XiaoWei font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/ZCOOL+XiaoWei + static TextTheme zcoolXiaoWeiTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.headline1), + headline2: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.headline2), + headline3: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.headline3), + headline4: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.headline4), + headline5: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.headline5), + headline6: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.bodyText2), + caption: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.caption), + button: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.button), + overline: GoogleFonts.zcoolXiaoWei(textStyle: textTheme.overline), + ); + } + + /// Applies the Zeyada font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Zeyada + static TextStyle zeyada({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '06ad6445bf0014c963d0b72e3dcd1defc66132033878f2b1cee5be9bdb807c93', + 63040, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'Zeyada', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Zeyada font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Zeyada + static TextTheme zeyadaTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.zeyada(textStyle: textTheme.headline1), + headline2: GoogleFonts.zeyada(textStyle: textTheme.headline2), + headline3: GoogleFonts.zeyada(textStyle: textTheme.headline3), + headline4: GoogleFonts.zeyada(textStyle: textTheme.headline4), + headline5: GoogleFonts.zeyada(textStyle: textTheme.headline5), + headline6: GoogleFonts.zeyada(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.zeyada(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.zeyada(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.zeyada(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.zeyada(textStyle: textTheme.bodyText2), + caption: GoogleFonts.zeyada(textStyle: textTheme.caption), + button: GoogleFonts.zeyada(textStyle: textTheme.button), + overline: GoogleFonts.zeyada(textStyle: textTheme.overline), + ); + } + + /// Applies the Zhi Mang Xing font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Zhi+Mang+Xing + static TextStyle zhiMangXing({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f1191a3228f8532e0c3269311dad5b9b1fcdc6dbcfe7f9e3cc506a30fda24d1b', + 4051716, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ZhiMangXing', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Zhi Mang Xing font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Zhi+Mang+Xing + static TextTheme zhiMangXingTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.zhiMangXing(textStyle: textTheme.headline1), + headline2: GoogleFonts.zhiMangXing(textStyle: textTheme.headline2), + headline3: GoogleFonts.zhiMangXing(textStyle: textTheme.headline3), + headline4: GoogleFonts.zhiMangXing(textStyle: textTheme.headline4), + headline5: GoogleFonts.zhiMangXing(textStyle: textTheme.headline5), + headline6: GoogleFonts.zhiMangXing(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.zhiMangXing(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.zhiMangXing(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.zhiMangXing(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.zhiMangXing(textStyle: textTheme.bodyText2), + caption: GoogleFonts.zhiMangXing(textStyle: textTheme.caption), + button: GoogleFonts.zhiMangXing(textStyle: textTheme.button), + overline: GoogleFonts.zhiMangXing(textStyle: textTheme.overline), + ); + } + + /// Applies the Zilla Slab font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Zilla+Slab + static TextStyle zillaSlab({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '37849ab854bf1dfd4a6d1cf5fe02365f214a0b5230a2473ddba5beea422d42c1', + 177352, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'f805ebf60f65467cf901f63c9e81742e68857ccd9321f154a664dc86e4f74d04', + 183780, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '6800e794aef26166782eccbaea44836363524c049b943e1ff5e7f3c662ee15db', + 177856, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '877668221b5887330f20b0c49f66807696026ce3edcc2930f86a6681f8bb0b66', + 185116, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'f84370da8e3c9d4ff36363df373f16bd9dff9bc4fec9d1bd98c58e5450fe7a94', + 177808, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w500, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + '382cc00753755b73c9b5c3c729fc28e639a7f0ec05d7f4f1eb078bed8b053e2c', + 185368, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + '0f65abeeaa62b1131fa31eb90d1ac6630bc73de55414482fd373559e7c8b56d2', + 177848, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w600, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'e893fedd56d416197cd6fb662dee7a611d5a5fc4216d271fa075316524ea4ff4', + 185160, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'bc0bb0d6f2a2f1edd4520a1e0e6fc779921dd929b7343dc03450a80ca514bb03', + 178644, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ): GoogleFontsFile( + 'd65ad541dbb872b4bd977f2dbfdf396a44ac0ec063b7921aba6e76dda85a4b05', + 185704, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ZillaSlab', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Zilla Slab font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Zilla+Slab + static TextTheme zillaSlabTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.zillaSlab(textStyle: textTheme.headline1), + headline2: GoogleFonts.zillaSlab(textStyle: textTheme.headline2), + headline3: GoogleFonts.zillaSlab(textStyle: textTheme.headline3), + headline4: GoogleFonts.zillaSlab(textStyle: textTheme.headline4), + headline5: GoogleFonts.zillaSlab(textStyle: textTheme.headline5), + headline6: GoogleFonts.zillaSlab(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.zillaSlab(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.zillaSlab(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.zillaSlab(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.zillaSlab(textStyle: textTheme.bodyText2), + caption: GoogleFonts.zillaSlab(textStyle: textTheme.caption), + button: GoogleFonts.zillaSlab(textStyle: textTheme.button), + overline: GoogleFonts.zillaSlab(textStyle: textTheme.overline), + ); + } + + /// Applies the Zilla Slab Highlight font family from Google Fonts to the + /// given [textStyle]. + /// + /// See: + /// * https://fonts.google.com/specimen/Zilla+Slab+Highlight + static TextStyle zillaSlabHighlight({ + TextStyle? textStyle, + Color? color, + Color? backgroundColor, + double? fontSize, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + double? height, + Locale? locale, + Paint? foreground, + Paint? background, + List? shadows, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + double? decorationThickness, + }) { + final fonts = { + GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'dbd546264c0d549b6c3cd17c1acf40b35bbe910885e09b5e2a270aa090b6ee53', + 71996, + ), + GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + ): GoogleFontsFile( + 'be3605b5e26a2439fde6293b4159f4c401273e65483cab10505e6c4010523ece', + 71064, + ), + }; + + return googleFontsTextStyle( + textStyle: textStyle, + fontFamily: 'ZillaSlabHighlight', + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fonts: fonts, + ); + } + + /// Applies the Zilla Slab Highlight font family from Google Fonts to every + /// [TextStyle] in the given [textTheme]. + /// + /// See: + /// * https://fonts.google.com/specimen/Zilla+Slab+Highlight + static TextTheme zillaSlabHighlightTextTheme([TextTheme? textTheme]) { + textTheme ??= ThemeData.light().textTheme; + return TextTheme( + headline1: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.headline1), + headline2: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.headline2), + headline3: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.headline3), + headline4: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.headline4), + headline5: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.headline5), + headline6: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.headline6), + subtitle1: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.subtitle1), + subtitle2: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.subtitle2), + bodyText1: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.bodyText1), + bodyText2: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.bodyText2), + caption: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.caption), + button: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.button), + overline: GoogleFonts.zillaSlabHighlight(textStyle: textTheme.overline), + ); + } +} +2 \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/asset_manifest.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/asset_manifest.dart new file mode 100644 index 00000000..91941f2f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/asset_manifest.dart @@ -0,0 +1,54 @@ +// Copyright 2019 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert' as convert; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +/// A class to obtain and memoize the app's asset manifest. +/// +/// Used to check whether a font is provided as an asset. +class AssetManifest { + AssetManifest({this.enableCache = true}); + + static Future>> _jsonFuture; + + /// Whether the rootBundle should cache AssetManifest.json. + /// + /// Enabled by default. Should only be disabled during tests. + final bool enableCache; + + Future>> json() { + _jsonFuture ??= _loadAssetManifestJson(); + return _jsonFuture; + } + + Future>> _loadAssetManifestJson() async { + try { + final jsonString = + await rootBundle.loadString('AssetManifest.json', cache: enableCache); + return _manifestParser(jsonString); + } catch (e) { + print('Error loading AssetManifest.json, e: $e'); + rootBundle.evict('AssetManifest.json'); + } + return null; + } + + static Future>> _manifestParser(String jsonData) { + if (jsonData == null) { + return SynchronousFuture(null); + } + final parsedJson = convert.json.decode(jsonData) as Map; + final parsedManifest = >{ + for (final entry in parsedJson.entries) + entry.key: (entry.value as List).cast(), + }; + return SynchronousFuture(parsedManifest); + } + + @visibleForTesting + static void reset() => _jsonFuture = null; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/file_io.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/file_io.dart new file mode 100644 index 00000000..755985e6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/file_io.dart @@ -0,0 +1,16 @@ +import 'dart:typed_data' show ByteData; + +/// By default, file IO is stubbed out. +/// +/// If the path provider library is available (on mobile or desktop), then the +/// implementation in `file_io_desktop_and_mobile.dart` is used. + +/// Stubbed out version of saveFontToDeviceFileSystem from +/// `file_io_desktop_and_mobile.dart`. +Future saveFontToDeviceFileSystem(String name, List bytes) => + Future.value(null); + +/// Stubbed out version of loadFontFromDeviceFileSystem from +/// `file_io_desktop_and_mobile.dart`. +Future loadFontFromDeviceFileSystem(String name) => + Future.value(null); diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/file_io_desktop_and_mobile.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/file_io_desktop_and_mobile.dart new file mode 100644 index 00000000..d0b0f763 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/file_io_desktop_and_mobile.dart @@ -0,0 +1,38 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:path_provider/path_provider.dart'; + +Future saveFontToDeviceFileSystem(String name, List bytes) async { + final file = await _localFile(name); + await file.writeAsBytes(bytes); +} + +Future loadFontFromDeviceFileSystem(String name) async { + try { + final file = await _localFile(name); + final fileExists = file.existsSync(); + if (fileExists) { + List contents = await file.readAsBytes(); + if (contents.isNotEmpty) { + return ByteData.view(Uint8List.fromList(contents).buffer); + } + } + } catch (e) { + return null; + } + return null; +} + +Future get _localPath async { + final directory = await getApplicationSupportDirectory(); + return directory.path; +} + +Future _localFile(String name) async { + final path = await _localPath; + // We expect only ttf files to be provided to us by the Google Fonts API. + // That's why we can be sure a previously saved Google Font is in the ttf + // format instead of, for example, otf. + return File('$path/$name.ttf'); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_base.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_base.dart new file mode 100755 index 00000000..0c8f122d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_base.dart @@ -0,0 +1,298 @@ +// Copyright 2019 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:crypto/crypto.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:http/http.dart' as http; + +import '../google_fonts.dart'; +import 'asset_manifest.dart'; +import 'file_io.dart' // Stubbed implementation by default. + // Concrete implementation if File IO is available. + if (dart.library.io) 'file_io_desktop_and_mobile.dart' as file_io; +import 'google_fonts_descriptor.dart'; +import 'google_fonts_family_with_variant.dart'; +import 'google_fonts_variant.dart'; + +// Keep track of the fonts that are loaded or currently loading in FontLoader +// for the life of the app instance. Once a font is attempted to load, it does +// not need to be attempted to load again, unless the attempted load resulted +// in an error. +final Set _loadedFonts = {}; + +@visibleForTesting +http.Client httpClient = http.Client(); + +@visibleForTesting +AssetManifest assetManifest = AssetManifest(); + +@visibleForTesting +void clearCache() => _loadedFonts.clear(); + +/// Creates a [TextStyle] that either uses the [fontFamily] for the requested +/// GoogleFont, or falls back to the pre-bundled [fontFamily]. +/// +/// This function has a side effect of loading the font into the [FontLoader], +/// either by network or from the device file system. +TextStyle googleFontsTextStyle({ + @required String fontFamily, + TextStyle textStyle, + Color color, + Color backgroundColor, + double fontSize, + FontWeight fontWeight, + FontStyle fontStyle, + double letterSpacing, + double wordSpacing, + TextBaseline textBaseline, + double height, + Locale locale, + Paint foreground, + Paint background, + List shadows, + List fontFeatures, + TextDecoration decoration, + Color decorationColor, + TextDecorationStyle decorationStyle, + double decorationThickness, + @required Map fonts, +}) { + textStyle ??= TextStyle(); + textStyle = textStyle.copyWith( + color: color, + backgroundColor: backgroundColor, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows, + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + ); + + final variant = GoogleFontsVariant( + fontWeight: textStyle.fontWeight ?? FontWeight.w400, + fontStyle: textStyle.fontStyle ?? FontStyle.normal, + ); + final matchedVariant = _closestMatch(variant, fonts.keys); + final familyWithVariant = GoogleFontsFamilyWithVariant( + family: fontFamily, + googleFontsVariant: matchedVariant, + ); + + final descriptor = GoogleFontsDescriptor( + familyWithVariant: familyWithVariant, + file: fonts[matchedVariant], + ); + + loadFontIfNecessary(descriptor); + + return textStyle.copyWith( + fontFamily: familyWithVariant.toString(), + fontFamilyFallback: [fontFamily], + ); +} + +/// Loads a font into the [FontLoader] with [googleFontsFamilyName] for the +/// matching [expectedFileHash]. +/// +/// If a font with the [fontName] has already been loaded into memory, then +/// this method does nothing as there is no need to load it a second time. +/// +/// Otherwise, this method will first check to see if the font is available +/// as an asset, then on the device file system. If it isn't, it is fetched via +/// the [fontUrl] and stored on device. In all cases, the font is loaded into +/// the [FontLoader]. +Future loadFontIfNecessary(GoogleFontsDescriptor descriptor) async { + final familyWithVariantString = descriptor.familyWithVariant.toString(); + final fontName = descriptor.familyWithVariant.toApiFilenamePrefix(); + // If this font has already already loaded or is loading, then there is no + // need to attempt to load it again, unless the attempted load results in an + // error. + if (_loadedFonts.contains(familyWithVariantString)) { + return; + } else { + _loadedFonts.add(familyWithVariantString); + } + + try { + Future byteData; + + // Check if this font can be loaded by the pre-bundled assets. + final assetManifestJson = await assetManifest.json(); + final assetPath = _findFamilyWithVariantAssetPath( + descriptor.familyWithVariant, + assetManifestJson, + ); + if (assetPath != null) { + byteData = rootBundle.load(assetPath); + } + if (await byteData != null) { + return loadFontByteData(familyWithVariantString, byteData); + } + + // Check if this font can be loaded from the device file system. + byteData = file_io.loadFontFromDeviceFileSystem(familyWithVariantString); + + if (await byteData != null) { + return loadFontByteData(familyWithVariantString, byteData); + } + + // Attempt to load this font via http, unless disallowed. + if (GoogleFonts.config.allowRuntimeFetching) { + byteData = _httpFetchFontAndSaveToDevice( + familyWithVariantString, + descriptor.file, + ); + if (await byteData != null) { + return loadFontByteData(familyWithVariantString, byteData); + } + } else { + throw Exception( + "GoogleFonts.config.allowRuntimeFetching is false but font $fontName was not " + "found in the application assets. Ensure $fontName.otf exists in a " + "folder that is included in your pubspec's assets.", + ); + } + } catch (e) { + _loadedFonts.remove(familyWithVariantString); + print('Error: google_fonts was unable to load font $fontName because the ' + 'following exception occured:\n$e'); + } +} + +/// Loads a font with [FontLoader], given its name and byte-representation. +@visibleForTesting +Future loadFontByteData( + String familyWithVariantString, + Future byteData, +) async { + if (byteData == null) return; + final fontData = await byteData; + if (fontData == null) return; + + final fontLoader = FontLoader(familyWithVariantString); + fontLoader.addFont(Future.value(fontData)); + await fontLoader.load(); +} + +/// Returns [GoogleFontsVariant] from [variantsToCompare] that most closely +/// matches [sourceVariant] according to the [_computeMatch] scoring function. +/// +/// This logic is derived from the following section of the minikin library, +/// which is ultimately how flutter handles matching fonts. +/// https://github.com/flutter/engine/blob/master/third_party/txt/src/minikin/FontFamily.cpp#L149 +GoogleFontsVariant _closestMatch( + GoogleFontsVariant sourceVariant, + Iterable variantsToCompare, +) { + int bestScore; + GoogleFontsVariant bestMatch; + for (final variantToCompare in variantsToCompare) { + final score = _computeMatch(sourceVariant, variantToCompare); + if (bestScore == null || score < bestScore) { + bestScore = score; + bestMatch = variantToCompare; + } + } + return bestMatch; +} + +/// Fetches a font with [fontName] from the [fontUrl] and saves it locally if +/// it is the first time it is being loaded. +/// +/// This function can return `null` if the font fails to load from the URL. +Future _httpFetchFontAndSaveToDevice( + String fontName, + GoogleFontsFile file, +) async { + final uri = Uri.tryParse(file.url); + if (uri == null) { + throw Exception('Invalid fontUrl: ${file.url}'); + } + + http.Response response; + try { + response = await httpClient.get(uri); + } catch (e) { + throw Exception('Failed to load font with url: ${file.url}'); + } + if (response.statusCode == 200) { + if (!_isFileSecure(file, response.bodyBytes)) { + throw Exception( + 'File from ${file.url} did not match expected length and checksum.', + ); + } + + _unawaited( + file_io.saveFontToDeviceFileSystem(fontName, response.bodyBytes)); + + return ByteData.view(response.bodyBytes.buffer); + } else { + // If that call was not successful, throw an error. + throw Exception('Failed to load font with url: ${file.url}'); + } +} + +// This logic is taken from the following section of the minikin library, which +// is ultimately how flutter handles matching fonts. +// * https://github.com/flutter/engine/blob/master/third_party/txt/src/minikin/FontFamily.cpp#L128 +int _computeMatch(GoogleFontsVariant a, GoogleFontsVariant b) { + if (a == b) { + return 0; + } + int score = (a.fontWeight.index - b.fontWeight.index).abs(); + if (a.fontStyle != b.fontStyle) { + score += 2; + } + return score; +} + +/// Looks for a matching [familyWithVariant] font, provided the asset manifest. +/// Returns the path of the font asset if found, otherwise an empty string. +String _findFamilyWithVariantAssetPath( + GoogleFontsFamilyWithVariant familyWithVariant, + Map> manifestJson, +) { + if (manifestJson == null) return null; + + final apiFilenamePrefix = familyWithVariant.toApiFilenamePrefix(); + + for (final assetList in manifestJson.values) { + for (final String asset in assetList) { + for (final matchingSuffix in ['.ttf', '.otf'].where(asset.endsWith)) { + final assetWithoutExtension = + asset.substring(0, asset.length - matchingSuffix.length); + if (assetWithoutExtension.endsWith(apiFilenamePrefix)) { + return asset; + } + } + } + } + + return null; +} + +bool _isFileSecure(GoogleFontsFile file, Uint8List bytes) { + final actualFileLength = bytes.length; + final actualFileHash = sha256.convert(bytes).toString(); + return file.expectedLength == actualFileLength && + file.expectedFileHash == actualFileHash; +} + +void _unawaited(Future future) {} diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_descriptor.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_descriptor.dart new file mode 100644 index 00000000..53b2d5cd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_descriptor.dart @@ -0,0 +1,35 @@ +// Copyright 2020 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import 'google_fonts_family_with_variant.dart'; + +/// Describes a Google Fonts API font. +/// +/// This class mostly serves as a simple way to keep the connected font +/// information together. +class GoogleFontsDescriptor { + const GoogleFontsDescriptor({ + @required this.familyWithVariant, + @required this.file, + }); + + final GoogleFontsFamilyWithVariant familyWithVariant; + final GoogleFontsFile file; +} + +/// Describes a font file as it is _expected_ to be received from the server. +/// +/// If a file is retrieved and its hash does not match [expectedFileHash], or it +/// is not of [expectedLength] bytes length, the font will not be loaded, and +/// the file will not be stored on the device. +class GoogleFontsFile { + GoogleFontsFile(this.expectedFileHash, this.expectedLength); + + final String expectedFileHash; + final int expectedLength; + + String get url => 'https://fonts.gstatic.com/s/a/$expectedFileHash.ttf'; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_family_with_variant.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_family_with_variant.dart new file mode 100644 index 00000000..caf5b2e2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_family_with_variant.dart @@ -0,0 +1,30 @@ +// Copyright 2020 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'google_fonts_variant.dart'; + +/// Represents a Google Fonts API variant in Flutter-specific types. +class GoogleFontsFamilyWithVariant { + const GoogleFontsFamilyWithVariant({ + @required this.family, + @required this.googleFontsVariant, + }); + + final String family; + final GoogleFontsVariant googleFontsVariant; + + String toApiFilenamePrefix() { + return '$family-${googleFontsVariant.toApiFilenamePart()}'; + } + + /// Returns a font family name that is modified with additional [fontWeight] + /// and [fontStyle] descriptions. + /// + /// This string is used as a key to the loaded or stored fonts that come + /// from the Google Fonts API. + @override + String toString() => '${family}_$googleFontsVariant'; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_variant.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_variant.dart new file mode 100644 index 00000000..4bf6f33c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/lib/src/google_fonts_variant.dart @@ -0,0 +1,162 @@ +// Copyright 2020 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +/// Represents a Google Fonts API variant in Flutter-specific types. +class GoogleFontsVariant { + const GoogleFontsVariant({ + @required this.fontWeight, + @required this.fontStyle, + }); + + /// Creates a [GoogleFontsVariant] from a Google Fonts API specific + /// filename part. + /// + /// A filename part is the part of the filename that does not include the + /// font family. For example, for the filename "Lato-Regular.ttf", the + /// filename part is "Regular". + /// + /// The following table shows how these filename parts convert: + /// 'Regular' -> weight: 400, style: normal + /// 'Italic' -> weight: 400, style: italic + /// 'Bold' -> weight: 700, style: normal + /// 'BoldItalic' -> weight: 700, style: italic + /// + /// See [GoogleFontsVariant.toApiFilenamePart] for the inverse function. + GoogleFontsVariant.fromApiFilenamePart(String filenamePart) + : this.fontWeight = _extractFontWeightFromApiFilenamePart(filenamePart), + this.fontStyle = _extractFontStyleFromApiFilenamePart(filenamePart); + + /// Creates a [GoogleFontsVariant] from a Google Fonts API specific + /// variant name. + /// + /// The following table shows how these variant strings convert: + /// 'regular' -> weight: 400, style: normal + /// 'italic' -> weight: 400, style: italic + /// '700' -> weight: 700, style: normal + /// '700italic' -> weight: 700, style: italic + /// + /// See [GoogleFontsVariant.toString] for the inverse function. + GoogleFontsVariant.fromString(String variantString) + : this.fontWeight = FontWeight.values[variantString == _regular || + variantString == _italic + ? 3 + : (int.parse(variantString.replaceAll(_italic, '')) ~/ 100) - 1], + this.fontStyle = variantString.contains(_italic) + ? FontStyle.italic + : FontStyle.normal; + + final FontWeight fontWeight; + final FontStyle fontStyle; + + static FontWeight _extractFontWeightFromApiFilenamePart(String filenamePart) { + if (filenamePart.contains('Thin')) return FontWeight.w100; + + // ExtraLight must be checked before Light because of the substring match. + if (filenamePart.contains('ExtraLight')) return FontWeight.w200; + if (filenamePart.contains('Light')) return FontWeight.w300; + + if (filenamePart.contains('Medium')) return FontWeight.w500; + + // SemiBold and ExtraBold must be checked before Bold because of the + // substring match. + if (filenamePart.contains('SemiBold')) return FontWeight.w600; + if (filenamePart.contains('ExtraBold')) return FontWeight.w800; + if (filenamePart.contains('Bold')) return FontWeight.w700; + + if (filenamePart.contains('Black')) return FontWeight.w900; + return FontWeight.w400; + } + + static FontStyle _extractFontStyleFromApiFilenamePart(String filenamePart) { + if (filenamePart.contains('Italic')) return FontStyle.italic; + return FontStyle.normal; + } + + /// Converts this [GoogleFontsVariant] to a Google Fonts API specific filename + /// part. + /// + /// A Filename part is the part of the filename that does not include the + /// font family. For example: for the filename "Lato-Regular.ttf", the + /// filename part is "Regular". + /// + /// The following table shows how these [GoogleFontsVariant]s convert: + /// weight: 400, style: normal -> 'Regular' + /// weight: 400, style: italic -> 'Italic' + /// weight: 700, style: normal -> 'Bold' + /// weight: 700, style: italic -> 'BoldItalic' + /// + /// See [GoogleFontsVariant.fromApiFilenamePart] for the inverse function. + String toApiFilenamePart() { + final weightPrefix = _fontWeightToFilenameWeightParts[fontWeight] ?? + _fontWeightToFilenameWeightParts[FontWeight.w400]; + final italicSuffix = fontStyle == FontStyle.italic ? 'Italic' : ''; + if (weightPrefix == 'Regular') { + return italicSuffix == '' ? weightPrefix : italicSuffix; + } + return '$weightPrefix$italicSuffix'; + } + + /// Converts this [GoogleFontsVariant] to a Google Fonts API specific variant + /// name string. + /// + /// The following table shows how these variant strings convert: + /// weight: 400, style: normal -> 'regular' + /// weight: 400, style: italic -> 'italic' + /// weight: 700, style: normal -> '700' + /// weight: 700, style: italic -> '700italic' + /// + /// See [GoogleFontsVariant.toString] for the inverse function. + @override + String toString() { + final fontWeightString = + fontWeight.index == 3 ? '' : (fontWeight.index + 1) * 100; + final fontStyleString = fontStyle + .toString() + .replaceAll('FontStyle.', '') + .replaceFirst(_normal, fontWeight.index == 3 ? _regular : ''); + return '$fontWeightString$fontStyleString'; + } + + @override + int get hashCode => hashValues(fontWeight, fontStyle); + + @override + bool operator ==(dynamic other) { + if (identical(this, other)) { + return true; + } + if (other.runtimeType != runtimeType) { + return false; + } + return other.fontWeight == fontWeight && other.fontStyle == fontStyle; + } +} + +/// What the Flutter API calls a font style of normal/regular. +const _normal = 'normal'; + +/// What the Google Fonts API calls a font style of normal/regular. +const _regular = 'regular'; + +/// Both the Flutter API and the Google API have the same name for a font style +/// of italic. +const _italic = 'italic'; + +/// Mapping from font weight types to the 'weight' part of the Google Fonts API +/// specific filename. +const _fontWeightToFilenameWeightParts = { + FontWeight.w100: 'Thin', + FontWeight.w200: 'ExtraLight', + FontWeight.w300: 'Light', + FontWeight.w400: 'Regular', + FontWeight.w500: 'Medium', + FontWeight.w600: 'SemiBold', + FontWeight.w700: 'Bold', + FontWeight.w800: 'ExtraBold', + FontWeight.w900: 'Black', +}; diff --git a/FlutterHelper/flutter_helper/lib/templates/fonts/main.dart b/FlutterHelper/flutter_helper/lib/templates/fonts/main.dart new file mode 100644 index 00000000..24614099 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/fonts/main.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +void main() => runApp(GoogleFontsApp()); + +class GoogleFontsApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, @required this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + int _counter = 0; + + void _incrementCounter() { + setState(() { + _counter++; + }); + } + + @override + Widget build(BuildContext context) { + final TextStyle headline4 = Theme.of(context).textTheme.headline4; + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'You have pushed the button this many times:', + style: GoogleFonts.oswald(textStyle: headline4), + ), + Text( + '$_counter', + style: GoogleFonts.lato(fontStyle: FontStyle.italic), + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: Icon(Icons.add), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/main.dart b/FlutterHelper/flutter_helper/lib/templates/main.dart new file mode 100644 index 00000000..2cd13832 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/main.dart @@ -0,0 +1,190 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/boss/utils.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/utils/util_log.dart'; +import 'package:flutter_helper/widgets2/search_appbar.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +import 'movie_details_ui/main.dart'; +import 'profileapp/main.dart'; + +void main() { + LogUtil.init(isDebug: true); + + runApp(TemplatesApp()); +} + +class TemplatesApp extends StatefulWidget { + @override + _TemplatesAppState createState() => _TemplatesAppState(); +} + +class _TemplatesAppState extends State { + + var _simpleItem = false; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: Scaffold( + appBar: _searchAppBarWidget, + body: Column( + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(right: 30), + child: + _simpleItem ? _buildSImpleGridView(context) : _buildGrid(), + ), + ), + ], + ), + ), + ); + } + + List _mwidgets = [ + ProfileApp(), + MovieDetailsUiApp(), + ]; + + ScrollController _scrollController = ScrollController(); + + var _listDisplay ; + FocusNode _focusNode = new FocusNode(); + TextEditingController _controller = TextEditingController(); + + PreferredSizeWidget get _searchAppBarWidget => SearchAppBarWidget( + focusNode: _focusNode, + controller: _controller, + elevation: 2.0, + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Icon(Icons.arrow_back), + ), + inputFormatters: [LengthLimitingTextInputFormatter(50)], + onChangedCallback: (str) { + if(str.isNotEmpty) { + setState(() { + // double _items.clear() + LogUtil.e('onChangeCallBack -> $str'); + var tmp = _mwidgets + .where((e) => + e.toStringShort().toLowerCase().contains(str.toLowerCase())) + .toList(); + _listDisplay = tmp; + }); + } else { + setState(() { + _listDisplay = null; + }); + } + }, + onEditingComplete: () { + showToast('onEditingComplete!'); + setState(() { + _listDisplay = null; + }); + }, + ); + + + + _buildSImpleGridView(BuildContext context) { + if(_listDisplay == null) { + _listDisplay = _mwidgets; + } + return GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, //每行三列 + childAspectRatio: 1.0 //显示区域宽高相等 + ), + itemCount: _listDisplay.length, + itemBuilder: (context, index) { + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) { + return _listDisplay[index]; + }), + ); + }, + child: Text("${_listDisplay[index].toStringShort()}"), + ); + }, + ); + } + + _buildGrid() { + return StaggeredGridView.countBuilder( + controller: _scrollController, + crossAxisCount: 4, + itemCount: _mwidgets.length, + itemBuilder: _builtItem, + staggeredTileBuilder: (int index) => new StaggeredTile.fit(2), + ); + } + + Widget _builtItem(BuildContext context, int index) { + Widget w = _mwidgets[index]; + High high; + if (w is HighMixin) { + high = (w as HighMixin).getHigh(); + } else { + high = High(w.toStringShort(), "没有实现minxin"); + } + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) { + return w; + }), + ); + }, + child: Card( + color: Colors.transparent, + child: Container( + color: Colors.white, + width: 20, + height: 280, + child: Column( + children: [ + Text(high.title), + SizedBox(height: 5), + ConstrainedBox( + constraints: BoxConstraints( + // maxWidth: 150, + maxHeight: 250, + ), + child: w, + ), + ], + ), + ), + ), + ); + } +} + +class AppData { + final String name; + final String imageUrl; + final Widget app; + + AppData({ + Key key, + this.app, + this.imageUrl = 'images/bossapp2x.png', + this.name = "app", + }); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/main.dart b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/main.dart new file mode 100644 index 00000000..4b01be83 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/main.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/movie_details_ui/models.dart'; +import 'package:flutter_helper/templates/movie_details_ui/movie_detail_actors.dart'; +import 'package:flutter_helper/templates/movie_details_ui/movie_detail_header.dart'; +import 'package:flutter_helper/templates/movie_details_ui/movie_detail_photos.dart'; +import 'package:flutter_helper/templates/movie_details_ui/movie_detail_storyline.dart'; +import 'package:flutter_helper/templates/movie_details_ui/utils.dart'; + +void main() => runApp(MovieDetailsUiApp()); + +class MovieDetailsUiApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + accentColor: const Color(0xFFFF5959), + ), + home: MovieDetailsPage(movie: testMovie), + ); + } +} + +class MovieDetailsPage extends StatelessWidget { + final Movie movie; + + const MovieDetailsPage({Key key, this.movie}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SingleChildScrollView( + child: Column( + children: [ + //Header + MovieDetailHeader(movie), + SizedBox(height: 20), + // Story line + _padding(MovieDetailStoryLine(stroyline: movie.storyline)), + SizedBox(height: 20), + // Photos + _padding(MovieDetailPhotos(photoUrls: movie.photoUrls)), + SizedBox(height: 20), + // Actors + _padding(MovieDetailActors(actors: movie.actors)), + ], + ), + ), + ); + } + + _padding(Widget widget) { + var ei = EdgeInsets.only(left: 10, right: 10); + return Padding(padding: ei, child: widget); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/models.dart b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/models.dart new file mode 100644 index 00000000..ca87173d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/models.dart @@ -0,0 +1,33 @@ +class Movie { + Movie({ + this.bannerUrl, + this.posterUrl, + this.title, + this.rating, + this.starRating, + this.categories, + this.storyline, + this.photoUrls, + this.actors, + }); + + final String bannerUrl; + final String posterUrl; + final String title; + final double rating; + final int starRating; + final List categories; + final String storyline; + final List photoUrls; + final List actors; +} + +class Actor { + Actor({ + this.name, + this.avatarUrl, + }); + + final String name; + final String avatarUrl; +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_actors.dart b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_actors.dart new file mode 100644 index 00000000..de883658 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_actors.dart @@ -0,0 +1,44 @@ + +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; +import 'package:flutter_helper/templates/movie_details_ui/models.dart'; + +class MovieDetailActors extends StatelessWidget { + final List actors; + + const MovieDetailActors({Key key, this.actors}) : super(key: key); + + @override + Widget build(BuildContext context) { + var textTheme = Theme.of(context).textTheme; + var textStyle = textTheme.subhead.copyWith(fontSize: 18.0); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Actors', style: textStyle), + SizedBox(height: 10), + SizedBox.fromSize( + size: const Size.fromHeight(120.0), + child: ListView.builder( + itemCount: actors.length, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + var actor = actors[index]; + return Padding( + padding: EdgeInsets.only(right: 16.0), + child: Column( + children: [ + CircleAvatar( + backgroundImage: AssetImage(actor.avatarUrl), + radius: 40.0, + ), + Text(actor.name), + ], + ), + ); + }, + ), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_header.dart b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_header.dart new file mode 100644 index 00000000..0d02e6ac --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_header.dart @@ -0,0 +1,181 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; +import 'package:flutter_helper/templates/movie_details_ui/models.dart'; + +class MovieDetailHeader extends StatelessWidget { + final Movie movie; + + MovieDetailHeader(this.movie); + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 140.0), + child: ArcBannerImage(imageUrl: movie.bannerUrl), + ), + Positioned( + bottom: 0.0, + left: 10.0, + right: 10.0, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Poster(posterUrl: movie.posterUrl, height: 180.0), + SizedBox(width: 10), + Expanded(child: _movieInformation(context, movie)), + ], + ), + ), + ], + ); + } + + _movieInformation(BuildContext context, Movie movie) { + var textTheme = Theme.of(context).textTheme; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(movie.title, style: textTheme.title, maxLines: 1), + //The Secret Life of Pets + SizedBox(height: 6), + _ratingInformation(context, movie), + SizedBox(height: 6), + _rowChips(textTheme, movie), + ], + ); + } + + _rowChips(TextTheme textTheme, Movie movie) { + return Row( + children: movie.categories + .map( + (category) => Padding( + padding: EdgeInsets.only(right: 8.0), + child: Chip( + label: Text(category), + labelStyle: textTheme.caption, + backgroundColor: Colors.black12, + ), + ), + ) + .toList(), + ); + } + + _ratingInformation(BuildContext context, Movie movie) { + var theme = Theme.of(context); + var textTheme = theme.textTheme; + var ratingCaptionStyle = textTheme.caption.copyWith(color: Colors.black45); + + var textStyle = textTheme.title + .copyWith(fontWeight: FontWeight.w400, color: theme.accentColor); + var numbericRating = Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(movie.rating.toString(), style: textStyle), + SizedBox(height: 4.0), + Text('Ratings', style: ratingCaptionStyle), + ], + ); + + _buildRatingBar(ThemeData theme) { + var stars = []; + for (int i = 1; i < 6; i++) { + var color = i <= movie.starRating ? theme.accentColor : Colors.black12; + var star = Icon(Icons.star, color: color); + stars.add(star); + } + return Row(children: stars); + } + + var starRating = Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildRatingBar(theme), + SizedBox(height: 4), + Text('Grade now', style: ratingCaptionStyle), + ], + ); + + return Row( + children: [ + numbericRating, + SizedBox(width: 14.0), + starRating, + ], + ); + } +} + +class ArcBannerImage extends StatelessWidget { + final String imageUrl; + + const ArcBannerImage({Key key, this.imageUrl}) : super(key: key); + + @override + Widget build(BuildContext context) { + var screenWidth = MediaQuery.of(context).size.width; + return ClipPath( + clipper: ArcClipper(), + child: Image.asset( + imageUrl, + width: screenWidth, + height: 230.0, + fit: BoxFit.cover, + ), + ); + } +} + +class ArcClipper extends CustomClipper { + @override + Path getClip(Size size) { + var path = Path(); + path.lineTo(0.0, size.height - 30); + var firstControlPoint = Offset(size.width / 4, size.height); + var firstPoint = Offset(size.width / 2, size.height); + path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy, + firstPoint.dx, firstPoint.dy); + + var secondControlPoint = Offset(size.width - (size.width / 4), size.height); + var secondPoint = Offset(size.width, size.height - 30); + path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy, + secondPoint.dx, secondPoint.dy); + + path.lineTo(size.width, 0.0); + path.close(); + + return path; + } + + @override + bool shouldReclip(covariant CustomClipper oldClipper) { + return false; + } +} + +class Poster extends StatelessWidget { + static const POSTER_RATIO = 0.7; + final String posterUrl; + final double height; + + const Poster({Key key, this.posterUrl, this.height = 100.0}) + : super(key: key); + + @override + Widget build(BuildContext context) { + var width = POSTER_RATIO * height; + return Material( + borderRadius: BorderRadius.circular(4.0), + elevation: 2.0, + child: Image.asset( + posterUrl, + fit: BoxFit.cover, + width: width, + height: height, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_photos.dart b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_photos.dart new file mode 100644 index 00000000..7cc2aef3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_photos.dart @@ -0,0 +1,43 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +class MovieDetailPhotos extends StatelessWidget { + final List photoUrls; + + const MovieDetailPhotos({Key key, this.photoUrls}) : super(key: key); + + @override + Widget build(BuildContext context) { + var textTheme = Theme.of(context).textTheme; + var textStyle = textTheme.subhead.copyWith(fontSize: 20.0); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Photos', style: textStyle), + SizedBox(height: 10), + SizedBox.fromSize( + size: const Size.fromHeight(100.0), + child: ListView.builder( + itemCount: photoUrls.length, + scrollDirection: Axis.horizontal, + itemBuilder: (BuildContext context, int index) { + var photo = photoUrls[index]; + + return Padding( + padding: const EdgeInsets.only(right: 16.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(4.0), + child: Image.asset( + photo, + width: 160.0, + height: 120.0, + fit: BoxFit.cover, + ), + ), + ); + }, + ), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_storyline.dart b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_storyline.dart new file mode 100644 index 00000000..94b422eb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/movie_detail_storyline.dart @@ -0,0 +1,36 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +class MovieDetailStoryLine extends StatelessWidget { + final String stroyline; + + const MovieDetailStoryLine({Key key, this.stroyline}) : super(key: key); + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + var textTheme = Theme.of(context).textTheme; + var textStyle = textTheme.subhead.copyWith(fontSize: 20.0); + var textStyle2 = + textTheme.body1.copyWith(color: Colors.black45, fontSize: 16.0); + var textStyle3 = + textTheme.body1.copyWith(fontSize: 16.0, color: theme.accentColor); + var accentColor = theme.accentColor; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Story line', style: textStyle), + SizedBox(height: 10), + Text(stroyline, style: textStyle2), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text('more', style: textStyle3), + Icon(Icons.keyboard_arrow_down, size: 18.0, color: accentColor), + ], + ), //more + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/utils.dart b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/utils.dart new file mode 100644 index 00000000..39e6c1f3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/movie_details_ui/utils.dart @@ -0,0 +1,42 @@ +import 'models.dart'; + +final Movie testMovie = Movie( + bannerUrl: 'images/banner.png', + posterUrl: 'images/poster.png', + title: 'The Secret Life of Pets', + rating: 8.0, + starRating: 4, + categories: ['Animation', 'Comedy'], + storyline: 'For their fifth fully-animated feature-film ' + 'collaboration, Illumination Entertainment and Universal ' + 'Pictures present The Secret Life of Pets, a comedy about ' + 'the lives our...', + photoUrls: [ + 'images/1.png', + 'images/2.png', + 'images/3.png', + 'images/4.png', + ], + actors: [ + Actor( + name: 'Louis C.K.', + avatarUrl: 'images/louis.png', + ), + Actor( + name: 'Eric Stonestreet', + avatarUrl: 'images/eric.png', + ), + Actor( + name: 'Kevin Hart', + avatarUrl: 'images/kevin.png', + ), + Actor( + name: 'Jenny Slate', + avatarUrl: 'images/jenny.png', + ), + Actor( + name: 'Ellie Kemper', + avatarUrl: 'images/ellie.png', + ), + ], +); diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/data/local_veggie_provider.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/data/local_veggie_provider.dart new file mode 100755 index 00000000..2acdff57 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/data/local_veggie_provider.dart @@ -0,0 +1,1398 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'veggie.dart'; + +class LocalVeggieProvider { + static List veggies = [ + Veggie( + id: 1, + name: 'Apples', + imageAssetPath: 'assets/images/apple.jpg', + category: VeggieCategory.fruit, + shortDescription: 'Green or red, they\'re generally round and tasty.', + accentColor: Color(0x40de8c66), + seasons: [Season.winter, Season.spring, Season.summer, Season.autumn], + vitaminAPercentage: 2, + vitaminCPercentage: 8, + servingSize: 'One large apple', + caloriesPerServing: 130, + trivia: [ + Trivia( + 'A peck of apples (that\'s a real unit of mesaurement!) weighs approximately how many pounds?', + [ + '10 pounds', + '20 pounds', + '30 pounds', + ], + 0, + ), + Trivia( + 'Which of these is an actual variety of apples?', + [ + 'Dancing Turkey', + 'Winter Banana', + 'Red Sloth', + ], + 1, + ), + Trivia( + 'In Greek mythology, Paris gives a golden apple marked "To the Fairest" to a goddess. Which one?', + [ + 'Hera', + 'Athena', + 'Aphrodite', + ], + 2, + ), + Trivia( + 'Apples in the supermarket can be up to how old?', + [ + '1 week', + '1 month', + '1 year', + ], + 2, + ), + Trivia( + 'How long does it take a typical apple tree to produce its first fruit?', + [ + 'One to two years', + 'Four or five years', + 'Eight to ten years', + ], + 1, + ), + Trivia( + 'Archaeological evidence of humans eating apples dates back how far?', + [ + '500 C.E.', + '2000 B.C.E.', + '6500 B.C.E.', + ], + 2, + ), + Trivia( + 'What are the seed pockets inside an apple called?', + [ + 'Tarsals', + 'Carpels', + 'Sacs', + ], + 1, + ), + ], + ), + Veggie( + id: 2, + name: 'Artichokes', + imageAssetPath: 'assets/images/artichoke.jpg', + category: VeggieCategory.flower, + shortDescription: 'The armadillo of vegetables.', + accentColor: Color(0x408ea26d), + seasons: [Season.spring, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 25, + servingSize: '1 medium artichoke', + caloriesPerServing: 60, + trivia: [ + Trivia( + 'Artichokes are which part of the plant?', + [ + 'Flower bud', + 'Root', + 'Seed', + ], + 0, + ), + Trivia( + '"Jerusalem artichoke" is another term for which vegetable?', + [ + 'Potato', + 'Cabbage', + 'Sunchoke', + ], + 2, + ), + Trivia( + 'Which city claims to be The Artichoke Capital of the World?', + [ + 'Castroville, California', + 'Galveston, Texas', + 'London, England', + ], + 0, + ), + Trivia( + 'Artichokes are technically which type of plant?', + [ + 'Thistle', + 'Azalea', + 'Tulip', + ], + 0, + ), + ], + ), + Veggie( + id: 3, + name: 'Asparagus', + imageAssetPath: 'assets/images/asparagus.jpg', + category: VeggieCategory.fern, + shortDescription: 'It\'s been used a food and medicine for millenia.', + accentColor: Color(0x408cb437), + seasons: [Season.spring], + vitaminAPercentage: 10, + vitaminCPercentage: 15, + servingSize: '5 spears', + caloriesPerServing: 20, + trivia: [ + Trivia( + 'The nodules at the tip of an asparagus spear are actually which part of the plant?', + [ + 'Seeds', + 'Leaves', + 'Potective scales', + ], + 1, + ), + Trivia( + 'How is white asparagus made?', + [ + 'It\'s watered with milk', + 'It\'s a different species', + 'It\'s grown in the shade', + ], + 2, + ), + Trivia( + 'Asapragus spears have been observed growing how many inches in a single day?', + [ + '1', + '3', + '6', + ], + 2, + ), + Trivia( + 'To which flower is asparagus related?', + [ + 'Lily', + 'Rose', + 'Whole wheat', + ], + 0, + ), + ], + ), + Veggie( + id: 4, + name: 'Avocado', + imageAssetPath: 'assets/images/avocado.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'One of the oiliest, richest fruits money can buy.', + accentColor: Color(0x40b0ba59), + seasons: [Season.winter, Season.spring, Season.summer], + vitaminAPercentage: 0, + vitaminCPercentage: 4, + servingSize: '1/5 medium avocado', + caloriesPerServing: 50, + trivia: [ + Trivia( + 'What\'s the most popular variety of avocado?', + [ + 'Stevenson', + 'Hass', + 'Juicy Lucy', + ], + 1, + ), + Trivia( + 'The word avocado derives from "ahuacatl," found in which civilization?', + [ + 'Aztec', + 'Incan', + 'Sumerian', + ], + 0, + ), + Trivia( + 'What percentage of an avocado is nutritional fat?', + [ + '10', + '25', + '50', + ], + 1, + ), + Trivia( + 'The first evidence of avocado consumption by humans dates back to what year?', + [ + '2,000 B.C.', + '6,000 B.C.', + '10,000 B.C.', + ], + 2, + ), + ], + ), + Veggie( + id: 5, + name: 'Blackberries', + imageAssetPath: 'assets/images/blackberry.jpg', + category: VeggieCategory.berry, + shortDescription: 'Find them on backroads and fences in the Northwest.', + accentColor: Color(0x409d5adb), + seasons: [Season.summer], + vitaminAPercentage: 6, + vitaminCPercentage: 4, + servingSize: '1 cup', + caloriesPerServing: 62, + trivia: [ + Trivia( + 'What color are unripe blackberries?', + [ + 'Red', + 'White', + 'Brown', + ], + 0, + ), + Trivia( + 'The blackberry is the official fruit of which American state?', + [ + 'Washington', + 'Colorado', + 'Alabama', + ], + 2, + ), + Trivia( + 'How many varieties of blackberries are known to exist?', + [ + '500', + '1000', + '2000', + ], + 2, + ), + ], + ), + Veggie( + id: 6, + name: 'Cantaloupe', + imageAssetPath: 'assets/images/cantaloupe.jpg', + category: VeggieCategory.melon, + shortDescription: 'A fruit so tasty there\'s a utensil just for it.', + accentColor: Color(0x40f6bd56), + seasons: [Season.summer], + vitaminAPercentage: 120, + vitaminCPercentage: 80, + servingSize: '1/4 medium cantaloupe', + caloriesPerServing: 50, + trivia: [ + Trivia( + 'Which of these is another name for cantaloupe?', + [ + 'Muskmelon', + 'Crenshaw melon', + 'Rindfruit', + ], + 0, + ), + Trivia( + 'The word "cantaloupe" is a reference to what?', + [ + 'The Latin word for a ring of seeds', + 'The gardens of a castle in Italy', + 'An aphid species that feeds on cantaloupe leaves', + ], + 1, + ), + Trivia( + 'Cantaloupes grow on what kind of plant?', + [ + 'Tree', + 'Shrub', + 'Vine', + ], + 2, + ), + Trivia( + 'The most expensive melons in Japan can sell for up to how much?', + [ + '\$100', + '\$1,000', + '\$10,000', + ], + 2, + ), + ], + ), + Veggie( + id: 7, + name: 'Cauliflower', + imageAssetPath: 'assets/images/cauliflower.jpg', + category: VeggieCategory.cruciferous, + shortDescription: 'Looks like white broccoli and explodes when cut.', + accentColor: Color(0x40c891a8), + seasons: [Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 100, + servingSize: '1/6 medium head', + caloriesPerServing: 25, + trivia: [ + Trivia( + 'The quote "Cauliflower is nothing but cabbage with a college education" is attributed to whom?', + [ + 'Cesar Romero', + 'Mark Twain', + 'Lucille Ball', + ], + 1, + ), + Trivia( + 'The edible head of a cauliflower plant is sometimes called what?', + [ + 'The curd', + 'The cow', + 'The cudgel', + ], + 0, + ), + Trivia( + 'Cauliflower is related closest to which of these other plants?', + [ + 'Mustard greens', + 'Apples', + 'Potatoes', + ], + 0, + ), + Trivia( + 'Cauliflower\'s green spiral-shaped cousin is known as what?', + [ + 'Romesco', + 'Brittany cabbage', + 'Muscle sprouts', + ], + 0, + ), + Trivia( + 'Green cauliflower is sometimes called what?', + [ + 'Broccoflower', + 'Avocadoflower', + 'Gross', + ], + 0, + ), + ], + ), + Veggie( + id: 8, + name: 'Endive', + imageAssetPath: 'assets/images/endive.jpg', + category: VeggieCategory.leafy, + shortDescription: 'It\'s basically the veal of lettuce.', + accentColor: Color(0x40c5be53), + seasons: [Season.winter, Season.spring, Season.autumn], + vitaminAPercentage: 10, + vitaminCPercentage: 2, + servingSize: '1/2 cup, chopped', + caloriesPerServing: 4, + trivia: [ + Trivia( + 'What\'s another name for Belgian endive?', + [ + 'Radicchio', + 'St. Paul\'s lettuce', + 'Witloof chicory', + ], + 2, + ), + Trivia( + 'How does endive propagate itself?', + [ + 'By seed', + 'By rhizome', + 'By packing up and moving to Des Moines', + ], + 0, + ), + Trivia( + 'Some farmers cover their endive with shade to reduce what?', + [ + 'Size', + 'Toughness', + 'Bitterness', + ], + 2, + ), + ], + ), + Veggie( + id: 9, + name: 'Figs', + imageAssetPath: 'assets/images/fig.jpg', + category: VeggieCategory.fruit, + shortDescription: 'Delicious when sliced and wrapped in prosciutto.', + accentColor: Color(0x40aa6d7c), + seasons: [Season.summer, Season.autumn], + vitaminAPercentage: 2, + vitaminCPercentage: 2, + servingSize: '1 large fig', + caloriesPerServing: 50, + trivia: [ + Trivia( + 'Which of these isn\'t a variety of figs?', + [ + 'Brown Turkey', + 'Green Ischia', + 'Red Racer', + ], + 2, + ), + Trivia( + 'A fig\'s natural sugar content is around what?', + [ + '25%', + '50%', + '75%', + ], + 1, + ), + Trivia( + 'How much sun should be used to ripen figs?', + [ + 'Shade', + 'Partial shade', + 'Full sun', + ], + 2, + ), + ], + ), + Veggie( + id: 10, + name: 'Grapes', + imageAssetPath: 'assets/images/grape.jpg', + category: VeggieCategory.berry, + shortDescription: 'Couldn\'t have wine without them.', + accentColor: Color(0x40ac708a), + seasons: [Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 2, + servingSize: '3/4 cup', + caloriesPerServing: 90, + trivia: [ + Trivia( + 'How long ago were grapes introduced to the Americas?', + [ + '100 years', + '200 years', + '300 years', + ], + 2, + ), + Trivia( + 'Which of these is not an actual color of grapes?', + [ + 'Pink', + 'Yellow', + 'Brown', + ], + 2, + ), + Trivia( + 'About how many millions of tons of grapes are produced each year?', + [ + '40', + '80', + '120', + ], + 1, + ), + Trivia( + 'There are about how many known varieties of grapes?', + [ + '2,000', + '4,000', + '8,000', + ], + 2, + ), + ], + ), + Veggie( + id: 11, + name: 'Green Pepper', + imageAssetPath: 'assets/images/green_bell_pepper.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'Pleasantly bitter, like a sad movie.', + accentColor: Color(0x408eb332), + seasons: [Season.summer], + vitaminAPercentage: 4, + vitaminCPercentage: 190, + servingSize: '1 medium pepper', + caloriesPerServing: 25, + trivia: [ + Trivia( + 'What\'s the Australian term for a bell pepper?', + [ + 'Capsicum', + 'Ringer', + 'John Dobbins', + ], + 0, + ), + Trivia( + 'How are green peppers produced?', + [ + 'They\'re picked before ripening', + 'They\'re grown in the shade', + 'They\'re a distinct species', + ], + 0, + ), + Trivia( + 'How quickly can a green pepper grow from seed to harvest?', + [ + '10 weeks', + '20 weeks', + '30 weeks', + ], + 0, + ), + ], + ), + Veggie( + id: 12, + name: 'Habanero', + imageAssetPath: 'assets/images/habanero.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'Delicious... in extremely small quantities.', + accentColor: Color(0x40ff7a01), + seasons: [Season.summer, Season.autumn], + vitaminAPercentage: 9, + vitaminCPercentage: 100, + servingSize: '1 pepper', + caloriesPerServing: 20, + trivia: [ + Trivia( + 'How high can habaneros rate on the Scoville scale?', + [ + '200,000 units', + '600,000 units', + '1,000,000 units', + ], + 1, + ), + Trivia( + 'Which of these is a pepper known to be hotter than the habanero?', + [ + 'Serrano pepper', + 'Hatch chile', + 'Pepper X', + ], + 2, + ), + Trivia( + 'Which of these isn\'t a variety of habaneros?', + [ + 'White giant', + 'Condor\'s beak', + 'Saucy tyrant', + ], + 2, + ), + ], + ), + Veggie( + id: 13, + name: 'Kale', + imageAssetPath: 'assets/images/kale.jpg', + category: VeggieCategory.cruciferous, + shortDescription: 'The meanest vegetable. Does not want to be eaten.', + accentColor: Color(0x40a86bd8), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 133, + vitaminCPercentage: 134, + servingSize: '1 cup, chopped', + caloriesPerServing: 33, + trivia: [ + Trivia( + 'Kale is sweeter when harvested after what?', + [ + 'Sundown', + 'The first frost', + 'Reading it a sad story', + ], + 1, + ), + Trivia( + 'Which of these isn\'t a color in which Kale can be found?', + [ + 'Purple', + 'White', + 'Orange', + ], + 2, + ), + Trivia( + 'One serving of kale provides what percentage of a typical person\'s requirement for vitamin K?', + [ + '100%', + '300%', + '900%', + ], + 2, + ), + ], + ), + Veggie( + id: 14, + name: 'Kiwi', + imageAssetPath: 'assets/images/kiwi.jpg', + category: VeggieCategory.berry, + shortDescription: 'Also known as Chinese gooseberry.', + accentColor: Color(0x40b47b37), + seasons: [Season.summer], + vitaminAPercentage: 2, + vitaminCPercentage: 240, + servingSize: '2 medium kiwis', + caloriesPerServing: 90, + trivia: [ + Trivia( + 'Europeans sometimes refer to kiwi as what?', + [ + 'Chinese gooseberry', + 'Gem berries', + 'Bulbfruit', + ], + 0, + ), + Trivia( + 'On what type of plant do kiwi grow?', + [ + 'Tree', + 'Shrub', + 'Vine', + ], + 2, + ), + Trivia( + 'Compared to oranges, kiwi typically contain how much vitamin C?', + [ + 'Half as much', + 'About the same', + 'Twice as much', + ], + 2, + ), + ], + ), + Veggie( + id: 15, + name: 'Lemons', + imageAssetPath: 'assets/images/lemon.jpg', + category: VeggieCategory.citrus, + shortDescription: 'Similar to limes, only yellow.', + accentColor: Color(0x40e2a500), + seasons: [Season.winter], + vitaminAPercentage: 0, + vitaminCPercentage: 40, + servingSize: '1 medium lemon', + caloriesPerServing: 15, + trivia: [ + Trivia( + 'A lemon tree can produce up to how many pounds of fruit each year?', + [ + '100', + '300', + '600', + ], + 2, + ), + Trivia( + 'Which of these isn\'t a type of lemon?', + [ + 'Acid', + 'Sarcastic', + 'Sweet', + ], + 1, + ), + Trivia( + 'What percent of a typical lemon is composed of juice?', + [ + '20%', + '40%', + '60%', + ], + 0, + ), + Trivia( + 'Which lemon variety is prized for its sweeter-than-averga flavor?', + [ + 'Hookeye', + 'Meyer', + 'Minnesota Stomp', + ], + 1, + ), + ], + ), + Veggie( + id: 16, + name: 'Limes', + imageAssetPath: 'assets/images/lime.jpg', + category: VeggieCategory.citrus, + shortDescription: 'Couldn\'t have ceviche and margaritas without them.', + accentColor: Color(0x4089b733), + seasons: [Season.winter], + vitaminAPercentage: 0, + vitaminCPercentage: 35, + servingSize: '1 medium lime', + caloriesPerServing: 20, + trivia: [ + Trivia( + 'Which American state is famous for its Key Lime Pie?', + [ + 'Pennsylvania', + 'Arizona', + 'Florida', + ], + 2, + ), + Trivia( + 'Dried limes are a particularly popular soup ingredient in which part of the world?', + [ + 'Middle East', + 'Africa', + 'Australia', + ], + 0, + ), + Trivia( + 'Sailors once carried limes on their ships to help against which condition?', + [ + 'Influenza', + 'Scurvy', + 'Boredom', + ], + 1, + ), + ], + ), + Veggie( + id: 17, + name: 'Mangos', + imageAssetPath: 'assets/images/mango.jpg', + category: VeggieCategory.tropical, + shortDescription: 'A fun orange fruit popular with smoothie enthusiasts.', + accentColor: Color(0x40fcc93c), + seasons: [Season.summer, Season.autumn], + vitaminAPercentage: 72, + vitaminCPercentage: 203, + servingSize: '1 fruit', + caloriesPerServing: 201, + trivia: [ + Trivia( + 'In Mexico, mangos are frequently dusted with what spices before being eaten as a snack?', + [ + 'Black pepper and sugar', + 'Chile pepper and lime juice', + 'Cumin and salt', + ], + 1, + ), + Trivia( + 'To which nut is the mango closely related?', + [ + 'Cashew', + 'Peanut', + 'Walnut', + ], + 0, + ), + Trivia( + 'In which country did mangos originate?', + [ + 'India', + 'Madagascar', + 'Belize', + ], + 0, + ), + ], + ), + Veggie( + id: 18, + name: 'Mushrooms', + imageAssetPath: 'assets/images/mushroom.jpg', + category: VeggieCategory.fungus, + shortDescription: 'They\'re not truffles, but they\'re still tasty.', + accentColor: Color(0x40ba754b), + seasons: [Season.spring, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 2, + servingSize: '5 medium \'shrooms', + caloriesPerServing: 20, + trivia: [ + Trivia( + 'Someone who loves eating mushrooms is called what?', + [ + 'A mycophagist', + 'A philologist', + 'A phlebotomist', + ], + 0, + ), + Trivia( + 'Morel mushrooms are particulary prized by cooks of which style of cuisine?', + [ + 'French', + 'Italian', + 'Japanese', + ], + 0, + ), + Trivia( + 'The largest living organism ever identified is what type of mushroom?', + [ + 'Shiitake mushroom', + 'Honey mushroom', + 'Glory mushroom', + ], + 1, + ), + Trivia( + 'One mushroom cousin is the truffle. Which color truffle is the most prized?', + [ + 'White', + 'Black', + 'Brown', + ], + 0, + ), + ], + ), + Veggie( + id: 19, + name: 'Nectarines', + imageAssetPath: 'assets/images/nectarine.jpg', + category: VeggieCategory.stoneFruit, + shortDescription: 'Tiny, bald peaches.', + accentColor: Color(0x40e45b3b), + seasons: [Season.summer], + vitaminAPercentage: 8, + vitaminCPercentage: 15, + servingSize: '1 medium nectarine', + caloriesPerServing: 60, + trivia: [ + Trivia( + 'Nectarines are technically a variety of which other fruit?', + [ + 'Peach', + 'Plum', + 'Cherry', + ], + 0, + ), + Trivia( + 'Nectarines are sometimes called what?', + [ + 'Neckless geese', + 'Giant grapes', + 'Shaved peaches', + ], + 2, + ), + Trivia( + 'Nectarines are thought to have originated in which country?', + [ + 'China', + 'Italy', + 'Ethiopia', + ], + 0, + ), + ], + ), + Veggie( + id: 20, + name: 'Persimmons', + imageAssetPath: 'assets/images/persimmon.jpg', + category: VeggieCategory.fruit, + shortDescription: 'It\'s like a plum and an apple had a baby together.', + accentColor: Color(0x40979852), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 27, + servingSize: '1 fruit', + caloriesPerServing: 32, + trivia: [ + Trivia( + 'What\'s the most commonly grown variety of persimmon?', + [ + 'Sugar', + 'Yellowbird', + 'Kaki', + ], + 2, + ), + Trivia( + 'The word "persimmon" is derived from which language?', + [ + 'Latin', + 'Indo-European', + 'Powhatan', + ], + 2, + ), + Trivia( + 'Which of these is an alternate variety of persimmon?', + [ + 'Black Sapote', + 'Green Troubador', + 'Red Captain', + ], + 0, + ), + ], + ), + Veggie( + id: 21, + name: 'Plums', + imageAssetPath: 'assets/images/plum.jpg', + category: VeggieCategory.stoneFruit, + shortDescription: 'Popular in fruit salads and children\'s tales.', + accentColor: Color(0x40e48b47), + seasons: [Season.summer], + vitaminAPercentage: 8, + vitaminCPercentage: 10, + servingSize: '2 medium plums', + caloriesPerServing: 70, + trivia: [ + Trivia( + 'Plums should be handled with care because...?', + [ + 'They\'re particularly sticky', + 'They bruise easily', + 'It\'s easy to hurt their feelings', + ], + 1, + ), + Trivia( + 'A dried plum is known as what?', + [ + 'A prune', + 'An apricot', + 'A raisin', + ], + 0, + ), + Trivia( + 'A sugar plum typically contains how much plum juice?', + [ + '0%', + '25%', + '50%', + ], + 0, + ), + ], + ), + Veggie( + id: 22, + name: 'Potatoes', + imageAssetPath: 'assets/images/potato.jpg', + category: VeggieCategory.tuber, + shortDescription: 'King of starches and giver of french fries.', + accentColor: Color(0x40c65c63), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 45, + servingSize: '1 medium spud', + caloriesPerServing: 110, + trivia: [ + Trivia( + 'Which country consumes the most fried potatoes per capita?', + [ + 'United States', + 'Belgium', + 'Ireland', + ], + 1, + ), + Trivia( + 'Who is credited with introducing French Fries to the United States?', + [ + 'Thomas Jefferson', + 'Betsy Ross', + 'Alexander Hamilton', + ], + 0, + ), + Trivia( + 'The world record for loongest curly fry stands at how many inches?', + [ + '38', + '58', + '78', + ], + 0, + ), + ], + ), + Veggie( + id: 23, + name: 'Radicchio', + imageAssetPath: 'assets/images/radicchio.jpg', + category: VeggieCategory.leafy, + shortDescription: 'It\'s that bitter taste in the salad you\'re eating.', + accentColor: Color(0x40d75875), + seasons: [Season.spring, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 10, + servingSize: '2 cups shredded', + caloriesPerServing: 20, + trivia: [ + Trivia( + 'Radicchio is a particuarly good source of which mineral?', + [ + 'Manganese', + 'Mercury', + 'Molybdenum', + ], + 0, + ), + Trivia( + 'Radicchio should be stored at what temperature?', + [ + 'Room temperature', + 'Refrigerator temperature', + 'Freezer temperature', + ], + 1, + ), + Trivia( + 'What happens to the taste of radicchio once the plant flowers?', + [ + 'It becomes bitter', + 'It becomes sweeter', + 'Nothing. It just looks nicer!', + ], + 0, + ), + ], + ), + Veggie( + id: 24, + name: 'Radishes', + imageAssetPath: 'assets/images/radish.jpg', + category: VeggieCategory.root, + shortDescription: 'Try roasting them in addition to slicing them up raw.', + accentColor: Color(0x40819e4e), + seasons: [Season.spring, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 30, + servingSize: '7 radishes', + caloriesPerServing: 10, + trivia: [ + Trivia( + 'Which ancient civilization is known to have used radish oil?', + [ + 'Egyptian', + 'Sumerian', + 'Incan', + ], + 0, + ), + Trivia( + 'What\'s the name of the radish commonly used in Japanese cuisine?', + [ + 'Daisuki', + 'Daijin', + 'Daikon', + ], + 2, + ), + Trivia( + 'The annual "Night of the Radishes" festival takes place just before Christmas Eve in which country?', + [ + 'Mexico', + 'France', + 'South Korea', + ], + 0, + ), + ], + ), + Veggie( + id: 25, + name: 'Squash', + imageAssetPath: 'assets/images/squash.jpg', + category: VeggieCategory.gourd, + shortDescription: 'Just slather them in butter and pop \'em in the oven.', + accentColor: Color(0x40dbb721), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 297, + vitaminCPercentage: 48, + servingSize: '1 cup diced butternut', + caloriesPerServing: 63, + trivia: [ + Trivia( + 'Which of these is not a type of squash?', + [ + 'Zucchini', + 'Spaghetti', + 'Martini', + ], + 2, + ), + Trivia( + 'Gourds like squash are also handy as what?', + [ + 'Containers', + 'Furniture', + 'Musical instruments', + ], + 0, + ), + Trivia( + 'Which country is the world\'s largest importer of squashes?', + [ + 'China', + 'United States', + 'Russia', + ], + 1, + ), + ], + ), + Veggie( + id: 26, + name: 'Strawberries', + imageAssetPath: 'assets/images/strawberry.jpg', + category: VeggieCategory.berry, + shortDescription: + 'A delicious fruit that keeps its seeds on the outside.', + accentColor: Color(0x40f06a44), + seasons: [Season.spring, Season.summer], + vitaminAPercentage: 0, + vitaminCPercentage: 160, + servingSize: '8 medium strawberries', + caloriesPerServing: 50, + trivia: [ + Trivia( + 'How many seeds are in the average strawberry?', + [ + '50', + '100', + '200', + ], + 2, + ), + Trivia( + 'Strawberries are closely related to which type of flower?', + [ + 'The rose', + 'The daisy', + 'The tulip', + ], + 0, + ), + Trivia( + 'Strawberries are unique among fruit for what reason?', + [ + 'Their seeds are on the outside', + 'Their flowers are striped', + 'Their plants have a taproot', + ], + 0, + ), + ], + ), + Veggie( + id: 27, + name: 'Tangelo', + imageAssetPath: 'assets/images/tangelo.jpg', + category: VeggieCategory.citrus, + shortDescription: 'No one\'s sure what they are or where they came from.', + accentColor: Color(0x40f88c06), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 6, + vitaminCPercentage: 181, + servingSize: '1 medium tangelo', + caloriesPerServing: 60, + trivia: [ + Trivia( + 'The tangelo is thought to be a cross between oranges and which other fruit?', + [ + 'Peach', + 'Plum', + 'Pummelo', + ], + 2, + ), + Trivia( + 'Which of these is a variety of tangelo?', + [ + 'Orlando', + 'Bluebonnet', + 'Creakey Pete', + ], + 0, + ), + Trivia( + 'A typical tangelo is about what size?', + [ + 'Golf ball', + 'Baseball', + 'Bowling ball', + ], + 1, + ), + ], + ), + Veggie( + id: 28, + name: 'Tomatoes', + imageAssetPath: 'assets/images/tomato.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'A new world food with old world tradition.', + accentColor: Color(0x40ea3628), + seasons: [Season.summer], + vitaminAPercentage: 20, + vitaminCPercentage: 40, + servingSize: '1 medium tomato', + caloriesPerServing: 25, + trivia: [ + Trivia( + 'French speakers sometimes refer to tomatoes with which name?', + [ + 'Piet de terre', + 'Mille-feuille', + 'Pomme d\'amour', + ], + 2, + ), + Trivia( + 'The largest tomato known to have been grown weighed in at how many pounds?', + [ + '8', + '10', + '12', + ], + 0, + ), + Trivia( + 'Which country is the world\'s largest producer of tomatoes?', + [ + 'China', + 'Italy', + 'Ecuador', + ], + 0, + ), + ], + ), + Veggie( + id: 29, + name: 'Watermelon', + imageAssetPath: 'assets/images/watermelon.jpg', + category: VeggieCategory.melon, + shortDescription: 'Everyone\'s favorite closing act at the picnic.', + accentColor: Color(0x40fa8c75), + seasons: [Season.summer], + vitaminAPercentage: 30, + vitaminCPercentage: 25, + servingSize: '2 cups diced', + caloriesPerServing: 80, + trivia: [ + Trivia( + 'How much of a watermelon is water?', + [ + '50%', + '75%', + '90%', + ], + 2, + ), + Trivia( + 'Which nation is famous for growing watermelons in unsual shapes like cubes and hearts?', + [ + 'Armenia', + 'Japan', + 'Saudi Arabia', + ], + 1, + ), + Trivia( + 'Which U.S. state declared the watermelon to be its state vegetable (that\'s right, vegetable)?', + [ + 'Kansas', + 'Iowa', + 'Oklahoma', + ], + 2, + ), + Trivia( + 'Early explorers to the Americas used watermelons as which piece of equipment?', + [ + 'Stools', + 'Pillows', + 'Canteens', + ], + 2, + ), + ], + ), + Veggie( + id: 30, + name: 'Orange Bell Pepper', + imageAssetPath: 'assets/images/orange_bell_pepper.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'Like green pepper, but nicer.', + accentColor: Color(0x40fd8e00), + seasons: [Season.summer], + vitaminAPercentage: 4, + vitaminCPercentage: 190, + servingSize: '1 medium pepper', + caloriesPerServing: 25, + trivia: [ + Trivia( + 'Which compound (not found in bell peppers) is responsible for many peppers\' spicy taste?', + [ + 'Alum', + 'Capsacin', + 'Calcium', + ], + 1, + ), + Trivia( + 'In comparison to green peppers, how expensive are their orange cousins?', + [ + 'Cheaper', + 'About the same', + 'More expensive', + ], + 2, + ), + Trivia( + 'Who is generally credited with giving bell peppers their peppery name?', + [ + 'Christopher Columbus', + 'Benjamin Franklin', + 'Eleanor Roosevelt', + ], + 0, + ), + ], + ), + ]; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/data/veggie.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/data/veggie.dart new file mode 100755 index 00000000..3161a653 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/data/veggie.dart @@ -0,0 +1,131 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:meta/meta.dart'; + +enum VeggieCategory { + allium, + berry, + citrus, + cruciferous, + fern, + flower, + fruit, + fungus, + gourd, + leafy, + legume, + melon, + root, + stealthFruit, + stoneFruit, + tropical, + tuber, + vegetable, +} + +enum Season { + winter, + spring, + summer, + autumn, +} + +class Trivia { + final String question; + final List answers; + final int correctAnswerIndex; + + const Trivia(this.question, this.answers, this.correctAnswerIndex); +} + +const Map veggieCategoryNames = { + VeggieCategory.allium: 'Allium', + VeggieCategory.berry: 'Berry', + VeggieCategory.citrus: 'Citrus', + VeggieCategory.cruciferous: 'Cruciferous', + VeggieCategory.fern: 'Technically a fern', + VeggieCategory.flower: 'Flower', + VeggieCategory.fruit: 'Fruit', + VeggieCategory.fungus: 'Fungus', + VeggieCategory.gourd: 'Gourd', + VeggieCategory.leafy: 'Leafy', + VeggieCategory.legume: 'Legume', + VeggieCategory.melon: 'Melon', + VeggieCategory.root: 'Root vegetable', + VeggieCategory.stealthFruit: 'Stealth fruit', + VeggieCategory.stoneFruit: 'Stone fruit', + VeggieCategory.tropical: 'Tropical', + VeggieCategory.tuber: 'Tuber', + VeggieCategory.vegetable: 'Vegetable', +}; + +const Map seasonNames = { + Season.winter: 'Winter', + Season.spring: 'Spring', + Season.summer: 'Summer', + Season.autumn: 'Autumn', +}; + +class Veggie { + Veggie({ + @required this.id, + @required this.name, + @required this.imageAssetPath, + @required this.category, + @required this.shortDescription, + @required this.accentColor, + @required this.seasons, + @required this.vitaminAPercentage, + @required this.vitaminCPercentage, + @required this.servingSize, + @required this.caloriesPerServing, + @required this.trivia, + this.isFavorite = false, + }); + + final int id; + + final String name; + + /// Each veggie has an associated image asset that's used as a background + /// image and icon. + final String imageAssetPath; + + final VeggieCategory category; + + /// A short, snappy line. + final String shortDescription; + + /// A color value to use when constructing UI elements to match the image + /// found at [imageAssetPath]. + final Color accentColor; + + /// Seasons during which a veggie is harvested. + final List seasons; + + /// Percentage of the FDA's recommended daily value of vitamin A for someone + /// with a 2,000 calorie diet. + final int vitaminAPercentage; + + /// Percentage of the FDA's recommended daily value of vitamin C for someone + /// with a 2,000 calorie diet. + final int vitaminCPercentage; + + /// A text description of a single serving (e.g. '1 apple' or '1/2 cup'). + final String servingSize; + + /// Calories per serving (as described in [servingSize]). + final int caloriesPerServing; + + /// Whether or not the veggie has been saved to the user's garden (i.e. marked + /// as a favorite). + bool isFavorite; + + /// A set of trivia questions and answers related to the veggie. + final List trivia; + + String get categoryName => veggieCategoryNames[category]; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/main.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/main.dart new file mode 100644 index 00000000..08a3cb09 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/main.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'navigator_v2/route_Information_parser.dart'; +import 'navigator_v2/router_delegate.dart'; + +void main() { + runApp(NavigatorVeggiesApp()); +} + +class NavigatorVeggiesApp extends StatefulWidget { + @override + State createState() => _NavigatorVeggiesAppState(); +} + +class _NavigatorVeggiesAppState extends State { + VeggieRouterDelegate _routerDelegate = VeggieRouterDelegate(); + VeggieRouteInformationParser _routeInformationParser = VeggieRouteInformationParser(); + + @override + Widget build(BuildContext context) { + return MaterialApp.router( + title: 'Veggies App', + routerDelegate: _routerDelegate, + routeInformationParser: _routeInformationParser, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/model.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/model.dart new file mode 100644 index 00000000..3034870a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/model.dart @@ -0,0 +1,18 @@ +class VeggieRoutePath { + final int id; + final bool isUnknown; + + VeggieRoutePath.home() + : id = null, + isUnknown = false; + + VeggieRoutePath.details(this.id) : isUnknown = false; + + VeggieRoutePath.unknown() + : id = null, + isUnknown = true; + + bool get isHomePage => id == null; + + bool get isDetailsPage => id != null; +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/page.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/page.dart new file mode 100644 index 00000000..79db07c3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/page.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import '../data/veggie.dart'; +import '../screen/details.dart'; + +class VeggieDetailsPage extends Page { + final Veggie veggie; + + VeggieDetailsPage({ + this.veggie, + }) : super(key: ValueKey(veggie)); + + Route createRoute(BuildContext context) { + return MaterialPageRoute( + settings: this, + builder: (BuildContext context) { + return VeggieDetailsScreen(veggie: veggie); + }, + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/route_Information_parser.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/route_Information_parser.dart new file mode 100644 index 00000000..29734448 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/route_Information_parser.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'model.dart'; + +class VeggieRouteInformationParser extends RouteInformationParser { + @override + Future parseRouteInformation( + RouteInformation routeInformation) async { + print("parseRouteInformation"); + final uri = Uri.parse(routeInformation.location); + // Handle '/' + if (uri.pathSegments.length == 0) { + return VeggieRoutePath.home(); + } + + // Handle '/book/:id' + if (uri.pathSegments.length == 2) { + if (uri.pathSegments[0] != 'veggie') return VeggieRoutePath.unknown(); + var remaining = uri.pathSegments[1]; + var id = int.tryParse(remaining); + if (id == null) return VeggieRoutePath.unknown(); + return VeggieRoutePath.details(id); + } + + // Handle unknown routes + return VeggieRoutePath.unknown(); + } + + @override + RouteInformation restoreRouteInformation(VeggieRoutePath path) { + print("restoreRouteInformation"); + if (path.isUnknown) { + return RouteInformation(location: '/404'); + } + if (path.isHomePage) { + return RouteInformation(location: '/'); + } + if (path.isDetailsPage) { + return RouteInformation(location: '/veggie/${path.id}'); + } + return null; + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/router_delegate.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/router_delegate.dart new file mode 100644 index 00000000..95b3067d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/navigator_v2/router_delegate.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import '../data/local_veggie_provider.dart'; +import '../data/veggie.dart'; +import '../navigator_v2/model.dart'; +import '../navigator_v2/page.dart'; +import '../screen/list.dart'; +import '../screen/unknown.dart'; + +class VeggieRouterDelegate extends RouterDelegate + with ChangeNotifier, PopNavigatorRouterDelegateMixin { + final GlobalKey navigatorKey; + + Veggie _selectedVeggie; + bool show404 = true; + + List veggies = LocalVeggieProvider.veggies; + + VeggieRouterDelegate() : navigatorKey = GlobalKey(); + + VeggieRoutePath get currentConfiguration { + print("currentConfiguration"); + if (show404) { + return VeggieRoutePath.unknown(); + } + return _selectedVeggie == null + ? VeggieRoutePath.home() + : VeggieRoutePath.details(veggies.indexOf(_selectedVeggie)); + } + + @override + Widget build(BuildContext context) { + List pages = [ + MaterialPage( + key: ValueKey('VeggiesListPage'), + child: + VeggiesListScreen(veggies: veggies, onTapped: _handleVeggieTapped), + ), + if (show404) + MaterialPage(key: ValueKey('UnknownPage'), child: UnknownScreen()) + else if (_selectedVeggie != null) + VeggieDetailsPage(veggie: _selectedVeggie) + ]; + + return Navigator( + key: navigatorKey, + pages: pages, + onPopPage: (route, result) { + if (!route.didPop(result)) { + return false; + } + + // Update the list of pages by setting _selectedVeggie to null + _selectedVeggie = null; + show404 = false; + notifyListeners(); + + return true; + }, + ); + } + + @override + Future setNewRoutePath(VeggieRoutePath path) async { + print("setNewRoutePath"); + if (path.isUnknown) { + _selectedVeggie = null; + show404 = true; + return; + } + + if (path.isDetailsPage) { + if (path.id < 0 || path.id > veggies.length - 1) { + show404 = true; + return; + } + + _selectedVeggie = veggies[path.id]; + } else { + _selectedVeggie = null; + } + + show404 = false; + } + + void _handleVeggieTapped(Veggie veggie) { + print("_handleVeggieTapped"); + _selectedVeggie = veggie; + // notifyListeners(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/pages_example.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/pages_example.dart new file mode 100755 index 00000000..e0e9a945 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/pages_example.dart @@ -0,0 +1,153 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +final _navigatorKey = GlobalKey(); + +// 该文件可独立运行 +// 右击点击 create 'pages_example.dart' -> OK +void main() => runApp(MyApp()); + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + static int _counter = 15; + + // Initial Route: /category/5/item/15 + final pages = [ + MyPage( + key: Key('/'), + name: '/', + builder: (context) => HomeScreen(), + ), + MyPage( + key: Key('/category/5'), + name: '/category/5', + builder: (context) => CategoryScreen(id: 5), + ), + MyPage( + key: Key('/item/15'), + name: '/item/15', + builder: (context) => ItemScreen(id: 15), + ), + ]; + + void addPage(MyPage page) { + setState(() => pages.add(page)); + } + + bool _onPopPage(Route route, dynamic result) { + setState(() => pages.remove(route.settings)); + return route.didPop(result); + } + + @override + Widget build(BuildContext context) { + print('build: $pages'); + return MaterialApp( + theme: ThemeData.dark(), + home: Scaffold( + body: WillPopScope( + onWillPop: () async => !await _navigatorKey.currentState.maybePop(), + child: Navigator( + key: _navigatorKey, + onPopPage: _onPopPage, + pages: List.of(pages), + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + setState(() { + final int id = ++_counter; + pages.add( + MyPage( + key: Key('/item/$id'), + name: '/item/$id', + builder: (context) => ItemScreen(id: id), + ), + ); + }); + }, + child: Icon(Icons.add), + ), + ), + ); + } +} + +class MyPage extends Page { + const MyPage({ + @required LocalKey key, + @required String name, + @required this.builder, + }) : super(key: key, name: name); + + final WidgetBuilder builder; + + @override + Route createRoute(BuildContext context) { + return MaterialPageRoute( + settings: this, + builder: builder, + ); + } + + @override + String toString() => '$name'; +} + +class HomeScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Material( + color: Colors.red, + child: Center( + child: Text( + 'Home', + style: Theme.of(context).textTheme.headline2, + ), + ), + ); + } +} + +class CategoryScreen extends StatelessWidget { + const CategoryScreen({Key key, this.id}) : super(key: key); + + final int id; + + @override + Widget build(BuildContext context) { + return Material( + color: Colors.green, + child: Center( + child: Text( + 'Category $id', + style: Theme.of(context).textTheme.headline2, + ), + ), + ); + } +} + +class ItemScreen extends StatelessWidget { + const ItemScreen({Key key, this.id}) : super(key: key); + + final int id; + + @override + Widget build(BuildContext context) { + return Material( + color: Colors.blue, + child: Center( + child: Text( + 'Item $id\n${ModalRoute.of(context).settings}', + style: Theme.of(context).textTheme.headline4, + textAlign: TextAlign.center, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/router_example.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/router_example.dart new file mode 100755 index 00000000..5d046cde --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/router_example.dart @@ -0,0 +1,240 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + + +// 该文件可独立运行 +// 右击点击 create 'router_example.dart' -> OK +void main() => runApp(MyApp()); + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + final delegate = MyRouteDelegate( + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) { + return MyHomePage(title: 'Route: ${settings.name}'); + }, + ); + }, + ); + + @override + Widget build(BuildContext context) { + return MaterialApp.router( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + routeInformationParser: MyRouteParser(), + routerDelegate: delegate, + ); + } +} + +class MyRouteParser extends RouteInformationParser { + @override + Future parseRouteInformation(RouteInformation routeInformation) { + return SynchronousFuture(routeInformation.location); + } + + @override + RouteInformation restoreRouteInformation(String configuration) { + return RouteInformation(location: configuration); + } +} + +class MyRouteDelegate extends RouterDelegate + with PopNavigatorRouterDelegateMixin, ChangeNotifier { + final _stack = []; + + static MyRouteDelegate of(BuildContext context) { + final delegate = Router.of(context).routerDelegate; + assert(delegate is MyRouteDelegate, 'Delegate type must match'); + return delegate as MyRouteDelegate; + } + + MyRouteDelegate({ + @required this.onGenerateRoute, + }); + + final RouteFactory onGenerateRoute; + + @override + GlobalKey navigatorKey = GlobalKey(); + + @override + String get currentConfiguration => _stack.isNotEmpty ? _stack.last : null; + + List get stack => List.unmodifiable(_stack); + + void push(String newRoute) { + _stack.add(newRoute); + notifyListeners(); + } + + void remove(String routeName) { + _stack.remove(routeName); + notifyListeners(); + } + + @override + Future setInitialRoutePath(String configuration) { + return setNewRoutePath(configuration); + } + + @override + Future setNewRoutePath(String configuration) { + _stack + ..clear() + ..add(configuration); + return SynchronousFuture(null); + } + + bool _onPopPage(Route route, dynamic result) { + if (_stack.isNotEmpty) { + if (_stack.last == route.settings.name) { + _stack.remove(route.settings.name); + notifyListeners(); + } + } + return route.didPop(result); + } + + @override + Widget build(BuildContext context) { + print('${describeIdentity(this)}.stack: $_stack'); + return Navigator( + key: navigatorKey, + onPopPage: _onPopPage, + pages: [ + for (final name in _stack) + MyPage( + key: ValueKey(name), + name: name, + ), + ], + ); + } +} + +class MyPage extends Page { + const MyPage({ + LocalKey key, + String name, + }) : super( + key: key, + name: name, + ); + + Route createRoute(BuildContext context) { + return MaterialPageRoute( + settings: this, + builder: (BuildContext context) { + return MyHomePage(title: 'Route: ${name}'); + }, + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + static int _counter = 0; + + void _showDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: Text('Is this being displayed?'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text('NO'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text('YES'), + ), + ], + ); + }, + ); + } + + void _removeLast() { + final delegate = MyRouteDelegate.of(context); + final stack = delegate.stack; + if (stack.length > 2) { + delegate.remove(stack[stack.length - 2]); + } + } + + void _incrementCounter() { + setState(() { + _counter++; + }); + MyRouteDelegate.of(context).push('Route$_counter'); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'You have pushed the button this many times:', + ), + Text( + '$_counter', + style: Theme.of(context).textTheme.headline4, + ), + ], + ), + ), + floatingActionButton: Row( + mainAxisSize: MainAxisSize.min, + children: [ + FloatingActionButton( + heroTag: 'dialog', + onPressed: _showDialog, + tooltip: 'Show dialog', + child: Icon(Icons.message), + ), + SizedBox(width: 12.0), + FloatingActionButton( + heroTag: 'remove', + onPressed: _removeLast, + tooltip: 'Remove last', + child: Icon(Icons.delete), + ), + SizedBox(width: 12.0), + FloatingActionButton( + heroTag: 'add', + onPressed: _incrementCounter, + tooltip: 'Increment', + child: Icon(Icons.add), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/details.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/details.dart new file mode 100755 index 00000000..25783ac6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/details.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import '../data/veggie.dart'; + +class VeggieDetailsScreen extends StatelessWidget { + final Veggie veggie; + + VeggieDetailsScreen({ + @required this.veggie, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text(veggie.name), backgroundColor: veggie.accentColor,), + body: Container( + color: veggie.accentColor, + child: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (veggie != null) ...[ + Text(veggie.name, style: Theme.of(context).textTheme.headline6), + Text(veggie.categoryName, style: Theme.of(context).textTheme.subtitle1), + ], + ], + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/favorites.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/favorites.dart new file mode 100755 index 00000000..f0139941 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/favorites.dart @@ -0,0 +1,16 @@ + +import 'package:flutter/material.dart'; + +class FavoritesScreen extends StatefulWidget { + @override + _FavoritesScreenState createState() => _FavoritesScreenState(); +} + +class _FavoritesScreenState extends State { + @override + Widget build(BuildContext context) { + return Center( + child: Text('收藏'), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/list.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/list.dart new file mode 100644 index 00000000..e2daee94 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/list.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import '../data/veggie.dart'; + +class VeggiesListScreen extends StatelessWidget { + final List veggies; + final ValueChanged onTapped; + + VeggiesListScreen({ + @required this.veggies, + @required this.onTapped, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('水果列表'),), + body: ListView( + children: [ + for (var item in veggies) + ListTile( + title: Text('${item.name}'), + subtitle: Text(item.categoryName), + onTap: () => onTapped(item), + ) + ], + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/search.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/search.dart new file mode 100755 index 00000000..24ca219f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/search.dart @@ -0,0 +1,16 @@ + +import 'package:flutter/material.dart'; + +class SearchScreen extends StatefulWidget { + @override + _SearchScreenState createState() => _SearchScreenState(); +} + +class _SearchScreenState extends State { + @override + Widget build(BuildContext context) { + return Center( + child: Text('搜索'), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/settings.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/settings.dart new file mode 100755 index 00000000..e8cabcbe --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/settings.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class SettingsScreen extends StatefulWidget { + @override + _SettingsScreenState createState() => _SettingsScreenState(); +} + +class _SettingsScreenState extends State { + @override + Widget build(BuildContext context) { + return Center( + child: Text('设置'), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/unknown.dart b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/unknown.dart new file mode 100644 index 00000000..fa516452 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/navigator_v2/screen/unknown.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; + +class UnknownScreen extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: Text('404!'), + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/profileapp/main.dart b/FlutterHelper/flutter_helper/lib/templates/profileapp/main.dart new file mode 100644 index 00000000..504b723a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/profileapp/main.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/templates/profileapp/page_book.dart'; +import 'package:flutter_helper/templates/profileapp/page_drink.dart'; +import 'package:flutter_helper/templates/profileapp/page_travel.dart'; + +import 'page_profile.dart'; +import 'utils.dart'; + +void main() => runApp(new ProfileApp()); + +class ProfileApp extends StatefulWidget { + @override + _ProfileAppState createState() => _ProfileAppState(); +} + +class _ProfileAppState extends State { + var _curIndex = 3; + + @override + Widget build(BuildContext context) { + return new MaterialApp( + title: 'Profile Challenge', + home: Scaffold( + body: _buildBody(), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _curIndex, + onTap: (index) { + if (_curIndex != index) { + setState(() { + _curIndex = index; + }); + } + }, + fixedColor: PColors.primaryColor, + iconSize: 25.0, + type: BottomNavigationBarType.fixed, + items: [ + _navigationItems(LAIcons.home), + _navigationItems(LAIcons.bookmark), + _navigationItems(LAIcons.thumbsUp), + _navigationItems(LAIcons.user), + ], + ), + ), + ); + } + + _buildBody() { + switch(_curIndex) { + case 0: return BookPage(); + case 1: return DrinkPage(); + case 2: return TravelPage(); + case 3: return ProfilePage(); + } + } + + _navigationItems(IconData id) => + BottomNavigationBarItem(icon: Icon(id), title: Text('')); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/profileapp/page_book.dart b/FlutterHelper/flutter_helper/lib/templates/profileapp/page_book.dart new file mode 100644 index 00000000..0e979f3d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/profileapp/page_book.dart @@ -0,0 +1,10 @@ + +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +class BookPage extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return Center(child: Text('BookPage')); + } + +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/profileapp/page_drink.dart b/FlutterHelper/flutter_helper/lib/templates/profileapp/page_drink.dart new file mode 100644 index 00000000..4652462f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/profileapp/page_drink.dart @@ -0,0 +1,10 @@ + +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +class DrinkPage extends StatelessWidget{ + @override + Widget build(BuildContext context) { + return Center(child: Text('DrinkPage')); + } + +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/profileapp/page_profile.dart b/FlutterHelper/flutter_helper/lib/templates/profileapp/page_profile.dart new file mode 100644 index 00000000..5c118ee0 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/profileapp/page_profile.dart @@ -0,0 +1,386 @@ +import 'package:flutter_helper/boss/utils.dart'; +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; +import 'package:flutter_helper/templates/profileapp/utils.dart'; +import 'dart:math'; + +//https://github.com/tomialagbe/flutter_ui_challenges#readme +class ProfilePage extends StatefulWidget { + @override + _ProfilePageState createState() => _ProfilePageState(); +} + +class _ProfilePageState extends State { + final Profile profile = getProfile(); + + @override + Widget build(BuildContext context) { + return ListView( + children: [ + _profileHeader(), + _quickActions(), + _buildItem("Memories", Icons.camera), + _buildItem("Favourites", Icons.favorite), + _buildItem("Presents", Icons.card_giftcard), + _buildItem("Friends", Icons.people), + _buildItem("Achievement", Icons.home), + ], + ); + } + + _profileHeader() { + final topPadding = MediaQuery.of(context).padding.top; + final headerGradient = new RadialGradient( + center: Alignment.topLeft, + radius: 0.4, + colors: [ + const Color(0xFF8860EB), + const Color(0xFF8881EB), + ], + stops: [ + 0.4, + 1.0, + ], + tileMode: TileMode.repeated, + ); + final headerHeight = 290.0; + + return Container( + height: headerHeight, + decoration: new BoxDecoration( + color: PColors.primaryColor, + boxShadow: [ + new BoxShadow(spreadRadius: 2.0, + blurRadius: 4.0, + offset: new Offset(0.0, 1.0), + color: Colors.black38), + ], + ), + child: new Stack( + fit: StackFit.expand, + children: [ + // linear gradient + new Container( + height: headerHeight, + decoration: new BoxDecoration( + gradient: new LinearGradient( + colors: [ //7928D1 + const Color(0xFF7928D1), const Color(0xFF9A4DFF)], + stops: [0.3, 0.5], + begin: Alignment.topRight, end: Alignment.bottomLeft + ), + ), + ), + // radial gradient + new CustomPaint( + painter: new HeaderGradientPainter(), + ), + new Padding( + padding: new EdgeInsets.only( + top: topPadding, left: 15.0, right: 15.0, bottom: 20.0), + child: new Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildBellIcon(), + new Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: _buildTitle(), + ), + new Padding( + padding: const EdgeInsets.only(bottom: 20.0), + child: _buildAvatar(), + ), + _buildFollowerStats() + ], + ), + ), + ], + ), + ); + } + /// Build the bell icon at the top right corner of the header + Widget _buildBellIcon() { + return new Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new IconButton( + icon: new Icon( + LAIcons.bell, color: Colors.white, size: 30.0,), + onPressed: () {}), + ], + ); + } + Widget _buildTitle() { + return new Text("Profile", + style: new TextStyle( + fontFamily: ProfileFontNames.TimeBurner, + fontWeight: FontWeight.w700, + color: Colors.white, + fontSize: 40.0, + letterSpacing: 1.0)); + } + + /// The avatar consists of the profile image, the users name and location + Widget _buildAvatar() { + final mainTextStyle = new TextStyle(fontFamily: ProfileFontNames.TimeBurner, + color: Colors.white, + fontWeight: FontWeight.w700, + fontSize: 20.0); + final subTextStyle = new TextStyle( + fontFamily: ProfileFontNames.TimeBurner, + fontSize: 16.0, + color: Colors.white70, + fontWeight: FontWeight.w700); + + return new Row( + children: [ + new Container( + width: 70.0, height: 60.0, + decoration: new BoxDecoration( + image: new DecorationImage( + image: new AssetImage("assets/images/emma-watson.jpg"), + fit: BoxFit.cover), + borderRadius: new BorderRadius.all(new Radius.circular(20.0)), + boxShadow: [ + new BoxShadow( + color: Colors.black26, blurRadius: 5.0, spreadRadius: 1.0), + ], + ), + ), + new Padding(padding: const EdgeInsets.only(right: 20.0)), + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text(profile.fullName, style: mainTextStyle), + new Text(profile.location, style: subTextStyle), + ], + ), + ], + ); + } + + Widget _buildFollowerStats() { + return new Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildFollowerStat("Followers", profile.numberOfFollowersString), + _buildVerticalDivider(), + _buildFollowerStat("Following", profile.numberFollowingString), + _buildVerticalDivider(), + _buildFollowerStat("Total Likes", profile.totalLikesString), + ], + ); + } + + Widget _buildFollowerStat(String title, String value) { + final titleStyle = new TextStyle( + fontSize: 16.0, + fontFamily: ProfileFontNames.TimeBurner, + color: Colors.white); + final valueStyle = new TextStyle( + fontFamily: ProfileFontNames.TimeBurner, + fontSize: 18.0, + fontWeight: FontWeight.w700, + color: Colors.white); + return new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Text(title, style: titleStyle), + new Text(value, style: valueStyle), + ], + ); + } + + Widget _buildVerticalDivider() { + return new Container( + height: 30.0, + width: 1.0, + color: Colors.white30, + margin: const EdgeInsets.only(left: 10.0, right: 10.0), + ); + } + + // var microphone = AssetImage("assets/images/microphone.png"); + // var wallet = AssetImage("assets/images/wallet.png"); + // var joystick = AssetImage("assets/images/joystick.png"); + + _buildAction(String title, Color c, Gradient gra, ImageProvider img) { + final textStyle = TextStyle( + color: Colors.white, + fontWeight: FontWeight.w700, + fontSize: 18.0, + fontFamily: ProfileFontNames.TimeBurner); + return GestureDetector( + onTap: () { + showToast(title); + }, + child: Container( + margin: EdgeInsets.only(right: 5.0, left: 5.0), + width: 150.0, + decoration: BoxDecoration( + color: c, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(10.0), + gradient: gra, + boxShadow: [ + BoxShadow( + blurRadius: 2.0, + spreadRadius: 1.0, + offset: Offset(0.0, 1.0), + ) + ], + ), + child: Stack( + children: [ + Opacity( + opacity: 0.2, + child: Align( + alignment: Alignment.centerRight, + child: Transform.rotate( + angle: -pi / 4.8, + alignment: Alignment.centerRight, + child: ClipPath( + clipper: _BackgroundImageClipper(), + child: Container( + padding: EdgeInsets.only( + bottom: 20.0, + left: 60.0, + ), + child: Image( + width: 90.0, + height: 90.0, + image: img, + ), + ), + ), + ), + ), + ), + Container( + alignment: Alignment.topLeft, + padding: EdgeInsets.only(left: 10.0, top: 10.0), + child: Text(title, style: textStyle), + ), + ], + ), + ), + ); + } + + _quickActions() { + final blueGradient = LinearGradient( + colors: [Color(0xFF0075D1), Color(0xFF00A2E3)], + stops: [0.4, 0.6], + begin: Alignment.topRight, + end: Alignment.bottomLeft); + final purpleGraient = LinearGradient( + colors: [Color(0xFF882DEB), Color(0xFF9A4DFF)], + stops: [0.5, 0.7], + begin: Alignment.topLeft, + end: Alignment.bottomRight); + final redGradient = LinearGradient( + colors: [Color(0xFFBA110E), Color(0xFFCF3110)], + stops: [0.6, 0.8], + begin: Alignment.bottomRight, + end: Alignment.topLeft); + + return Container( + constraints: BoxConstraints(maxHeight: 120.0), + margin: EdgeInsets.only(top: 20.0), + child: ListView( + padding: + EdgeInsets.only(left: 10.0, bottom: 20.0, right: 10.0, top: 10.0), + shrinkWrap: true, + scrollDirection: Axis.horizontal, + children: [ + _buildAction( + "Live\nBroadcast", + Colors.blue, + blueGradient, + new AssetImage("assets/images/microphone.png"), + ), + _buildAction( + "My\nWallet", + Colors.purple, + purpleGraient, + new AssetImage("assets/images/wallet.png"), + ), + _buildAction( + "Game\nCenter", + Colors.red, + redGradient, + new AssetImage("assets/images/joystick.png"), + ), + ], + ), + ); + } + + _buildItem(String title, IconData iconData) { + final textStyle = TextStyle( + color: Colors.black54, + fontSize: 18.0, + fontWeight: FontWeight.w600, + ); + return InkWell( + onTap: () { + showToast(title); + }, + child: Padding( + padding: EdgeInsets.only(left: 16.0, right: 16.0), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + color: Colors.purple, + borderRadius: BorderRadius.circular(5.0), + ), + width: 35.0, + height: 35.0, + child: Icon(iconData, color: Colors.white, size: 24.0), + ), + Padding( + padding: EdgeInsets.only(left: 10.0, right: 10.0), + child: Text(title, style: textStyle), + ), + Expanded(child: Container()), + IconButton( + onPressed: () {}, + icon: Icon(Icons.chevron_right, color: Colors.black26), + ), + ], + ), + ), + ); + } +} + +class _BackgroundImageClipper extends CustomClipper { + @override + Path getClip(Size size) { + final path = Path(); + path.moveTo(0.0, 0.0); + path.lineTo(size.width, size.height); + path.lineTo(size.width, 0.0); + path.close(); + return path; + } + + @override + bool shouldReclip(covariant CustomClipper oldClipper) => false; +} + + +class HeaderGradientPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + // TODO: paint background radial gradient + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => false; + +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/templates/profileapp/page_travel.dart b/FlutterHelper/flutter_helper/lib/templates/profileapp/page_travel.dart new file mode 100644 index 00000000..9afc4fe5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/profileapp/page_travel.dart @@ -0,0 +1,8 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +class TravelPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Center(child: Text('TravelPage')); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/profileapp/utils.dart b/FlutterHelper/flutter_helper/lib/templates/profileapp/utils.dart new file mode 100644 index 00000000..b0909c2f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/profileapp/utils.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; + +class Profile { + String firstName; + String lastName; + String location; + int numberOfFollowers; + int numberFollowing; + int totalLikes; + + String get fullName => "$firstName $lastName"; + + String get numberOfFollowersString => _abbreviatedCount(numberOfFollowers); + + String get numberFollowingString => _abbreviatedCount(numberFollowing); + + String get totalLikesString => _abbreviatedCount(totalLikes); + + String _abbreviatedCount(int num) { + if (num < 1000) return "$num"; + if (num >= 1000 && num < 1000000) { + String s = (num / 1000).toStringAsFixed(1); + if (s.endsWith(".0")) { + int idx = s.indexOf(".0"); + s = s.substring(0, idx); + } + return "${s}K"; + } else if (num >= 1000000 && num < 1000000000) { + String s = (num / 1000000).toStringAsFixed(1); + if (s.endsWith(".0")) { + int idx = s.indexOf(".0"); + s = s.substring(0, idx); + } + return "${s}M"; + } + return ""; + } +} + +Profile getProfile() { + return new Profile() + ..firstName = "Emma" + ..lastName = "Watson" + ..location = "New York" + ..numberOfFollowers = 5700000 + ..numberFollowing = 924 + ..totalLikes = 1700; +} + +class ProfileFontNames { + static final String TimeBurner = "Timeburner"; +} + + +class PColors { + static final Color primaryColor = new Color(0xFF9A10FF); +} + +class TIcons { + static const fontFamily = "Themify"; + + static final IconData bell = new IconData(0xe6b8, fontFamily: fontFamily); + static final IconData home = new IconData(0xe69b, fontFamily: fontFamily); + static final IconData user = new IconData(0xe602, fontFamily: fontFamily); + static final IconData thumbUp = new IconData(0xe670, fontFamily: fontFamily); + static final IconData tag = new IconData(0xe608, fontFamily: fontFamily); +} + +class LAIcons { + static const fontFamily = "LineAwesome"; + + static final IconData bell = new IconData(0xf141, fontFamily: fontFamily); + static final IconData home = new IconData(0xf237, fontFamily: fontFamily); + static final IconData user = new IconData(0xf364, fontFamily: fontFamily); + static final IconData thumbsUp = new IconData(0xf33f, fontFamily: fontFamily); + static final IconData bookmark = new IconData(0xf14f, fontFamily: fontFamily); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/todo/CustomCheckboxTile.dart b/FlutterHelper/flutter_helper/lib/templates/todo/CustomCheckboxTile.dart new file mode 100644 index 00000000..e813ce1d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/todo/CustomCheckboxTile.dart @@ -0,0 +1,285 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; + +class CustomListTile extends StatelessWidget { + const CustomListTile({ + Key key, + this.leading, + this.title, + this.subtitle, + this.trailing, + this.isThreeLine: false, + this.dense, + this.enabled: true, + this.onTap, + this.onLongPress, + this.selected: false, + }) : assert(isThreeLine != null), + assert(enabled != null), + assert(selected != null), + assert(!isThreeLine || subtitle != null), + super(key: key); + + final Widget leading; + + final Widget title; + + final Widget subtitle; + + final Widget trailing; + + final bool isThreeLine; + + final bool dense; + + final bool enabled; + + final GestureTapCallback onTap; + + final GestureLongPressCallback onLongPress; + + final bool selected; + + static Iterable divideTiles({BuildContext context, @required Iterable tiles, Color color}) sync* { + assert(tiles != null); + assert(color != null || context != null); + + final Iterator iterator = tiles.iterator; + final bool isNotEmpty = iterator.moveNext(); + + final Decoration decoration = BoxDecoration( + border: Border( + bottom: Divider.createBorderSide(context, color: color), + ), + ); + + Widget tile = iterator.current; + while (iterator.moveNext()) { + yield DecoratedBox( + position: DecorationPosition.foreground, + decoration: decoration, + child: tile, + ); + tile = iterator.current; + } + if (isNotEmpty) yield tile; + } + + Color _iconColor(ThemeData theme, ListTileTheme tileTheme) { + if (!enabled) return theme.disabledColor; + + if (selected && tileTheme?.selectedColor != null) return tileTheme.selectedColor; + + if (!selected && tileTheme?.iconColor != null) return tileTheme.iconColor; + + switch (theme.brightness) { + case Brightness.light: + return selected ? theme.primaryColor : Colors.black45; + case Brightness.dark: + return selected ? theme.accentColor : null; // null - use current icon theme color + } + assert(theme.brightness != null); + return null; + } + + Color _textColor(ThemeData theme, ListTileTheme tileTheme, Color defaultColor) { + if (!enabled) return theme.disabledColor; + + if (selected && tileTheme?.selectedColor != null) return tileTheme.selectedColor; + + if (!selected && tileTheme?.textColor != null) return tileTheme.textColor; + + if (selected) { + switch (theme.brightness) { + case Brightness.light: + return theme.primaryColor; + case Brightness.dark: + return theme.accentColor; + } + } + return defaultColor; + } + + bool _denseLayout(ListTileTheme tileTheme) { + return dense != null ? dense : (tileTheme?.dense ?? false); + } + + TextStyle _titleTextStyle(ThemeData theme, ListTileTheme tileTheme) { + TextStyle style; + if (tileTheme != null) { + switch (tileTheme.style) { + case ListTileStyle.drawer: + style = theme.textTheme.body2; + break; + case ListTileStyle.list: + style = theme.textTheme.subhead; + break; + } + } else { + style = theme.textTheme.subhead; + } + final Color color = _textColor(theme, tileTheme, style.color); + return style.copyWith(fontSize: 14.0, color: color); + } + + TextStyle _subtitleTextStyle(ThemeData theme, ListTileTheme tileTheme) { + final TextStyle style = theme.textTheme.body1; + final Color color = _textColor(theme, tileTheme, theme.textTheme.caption.color); + return style.copyWith(color: color, fontSize: 12.0); + } + + @override + Widget build(BuildContext context) { + assert(debugCheckHasMaterial(context)); + final ThemeData theme = Theme.of(context); + final ListTileTheme tileTheme = ListTileTheme.of(context); + + final bool isTwoLine = !isThreeLine && subtitle != null; + final bool isOneLine = !isThreeLine && !isTwoLine; + double tileHeight; + if (isOneLine) + tileHeight = 50.0; + else if (isTwoLine) + tileHeight = _denseLayout(tileTheme) ? 60.0 : 72.0; + else + tileHeight = _denseLayout(tileTheme) ? 76.0 : 88.0; + + // Overall, the list tile is a Row() with these children. + final List children = []; + + IconThemeData iconThemeData; + if (leading != null || trailing != null) iconThemeData = IconThemeData(color: _iconColor(theme, tileTheme)); + + if (leading != null) { + children.add(IconTheme.merge( + data: iconThemeData, + child: Container(margin: EdgeInsetsDirectional.only(end: 16.0), width: 30.0, alignment: AlignmentDirectional.centerStart, child: leading), + )); + } + + final Widget primaryLine = AnimatedDefaultTextStyle(style: _titleTextStyle(theme, tileTheme), duration: kThemeChangeDuration, child: title ?? Container()); + Widget center = primaryLine; + if (subtitle != null && (isTwoLine || isThreeLine)) { + center = Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + primaryLine, + AnimatedDefaultTextStyle( + style: _subtitleTextStyle(theme, tileTheme), + duration: kThemeChangeDuration, + child: subtitle, + ), + ], + ); + } + children.add(Expanded( + child: center, + )); + + if (trailing != null) { + children.add(IconTheme.merge( + data: iconThemeData, + child: Container( + margin: EdgeInsetsDirectional.only(start: 16.0), + alignment: AlignmentDirectional.centerEnd, + child: trailing, + ), + )); + } + + return InkWell( + highlightColor: Colors.grey.withAlpha(10), + splashColor: Colors.transparent, + onTap: enabled ? onTap : null, + onLongPress: enabled ? onLongPress : null, + child: Semantics( + selected: selected, + enabled: enabled, + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: tileHeight), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 0.0), + child: UnconstrainedBox( + constrainedAxis: Axis.horizontal, + child: SafeArea( + top: false, + bottom: false, + child: Row(children: children), + ), + ), + )), + ), + ); + } +} + +class CustomCheckboxListTile extends StatelessWidget { + const CustomCheckboxListTile({ + Key key, + @required this.value, + @required this.onChanged, + this.activeColor, + this.title, + this.subtitle, + this.isThreeLine: false, + this.dense, + this.secondary, + this.selected: false, + }) : assert(value != null), + assert(isThreeLine != null), + assert(!isThreeLine || subtitle != null), + assert(selected != null), + super(key: key); + + final bool value; + + final ValueChanged onChanged; + + final Color activeColor; + + final Widget title; + + final Widget subtitle; + + final Widget secondary; + + final bool isThreeLine; + + final bool dense; + + final bool selected; + + @override + Widget build(BuildContext context) { + final Widget leading = Container( + width: 18.0, + child: Checkbox( + value: value, + onChanged: onChanged, + activeColor: activeColor, + ), + ); + Widget trailing = secondary; + return MergeSemantics( + child: ListTileTheme.merge( + selectedColor: activeColor ?? Theme.of(context).accentColor, + child: CustomListTile( + leading: leading, + title: title, + subtitle: subtitle, + trailing: trailing, + isThreeLine: isThreeLine, + dense: dense, + enabled: onChanged != null, + onTap: onChanged != null + ? () { + onChanged(!value); + } + : null, + selected: selected, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/todo/CustomIcons.dart b/FlutterHelper/flutter_helper/lib/templates/todo/CustomIcons.dart new file mode 100644 index 00000000..afdc733b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/todo/CustomIcons.dart @@ -0,0 +1,6 @@ +import 'package:flutter/material.dart'; + +class CustomIcons { + static const IconData menu = IconData(0xe901, fontFamily: "CustomFont"); + static const IconData search = IconData(0xe900, fontFamily: "CustomFont"); +} diff --git a/FlutterHelper/flutter_helper/lib/templates/todo/DummyData.dart b/FlutterHelper/flutter_helper/lib/templates/todo/DummyData.dart new file mode 100644 index 00000000..61aa631b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/todo/DummyData.dart @@ -0,0 +1,25 @@ +import './objects/ColorChoice.dart'; +import './objects/TodoObject.dart'; +import 'package:flutter/material.dart'; + +List todos = [ + TodoObject.import("SOME_RANDOM_UUID", "Custom", 1, ColorChoices.choices[0], Icons.alarm, { + DateTime(2018, 5, 3): [ + TaskObject("Meet Clients", DateTime(2018, 5, 3)), + TaskObject("Design Sprint", DateTime(2018, 5, 3)), + TaskObject("Icon Set Design for Mobile", DateTime(2018, 5, 3)), + TaskObject("HTML/CSS Study", DateTime(2018, 5, 3)), + ], + DateTime(2019, 5, 4): [ + TaskObject("Meet Clients", DateTime(2019, 5, 4)), + TaskObject("Design Sprint", DateTime(2019, 5, 4)), + TaskObject("Icon Set Design for Mobile", DateTime(2019, 5, 4)), + TaskObject("HTML/CSS Study", DateTime(2019, 5, 4)), + ] + }), + TodoObject("Personal", Icons.person), + TodoObject("Work", Icons.work), + TodoObject("Home", Icons.home), + TodoObject("Shopping", Icons.shopping_basket), + TodoObject("School", Icons.school), +]; diff --git a/FlutterHelper/flutter_helper/lib/templates/todo/main.dart b/FlutterHelper/flutter_helper/lib/templates/todo/main.dart new file mode 100644 index 00000000..33a2877b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/todo/main.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import './pages/Home.dart'; + +void main() => runApp(TodoApp()); + +class TodoApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter TODO', + home: HomePage(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/todo/objects/ColorChoice.dart b/FlutterHelper/flutter_helper/lib/templates/todo/objects/ColorChoice.dart new file mode 100644 index 00000000..b92ff80d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/todo/objects/ColorChoice.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; + +class ColorChoice { + ColorChoice({@required this.primary, @required this.gradient}); + + final Color primary; + final List gradient; +} + +class ColorChoices { + static List choices = [ + ColorChoice( + primary: Color(0xFFF77B67), + gradient: [ + Color.fromRGBO(245, 68, 113, 1.0), + Color.fromRGBO(245, 161, 81, 1.0), + ], + ), + ColorChoice( + primary: Color(0xFF5A89E6), + gradient: [ + Color.fromRGBO(77, 85, 225, 1.0), + Color.fromRGBO(93, 167, 231, 1.0), + ], + ), + ColorChoice( + primary: Color(0xFF4EC5AC), + gradient: [ + Color.fromRGBO(61, 188, 156, 1.0), + Color.fromRGBO(61, 212, 132, 1.0), + ], + ), + ]; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/todo/objects/TodoObject.dart b/FlutterHelper/flutter_helper/lib/templates/todo/objects/TodoObject.dart new file mode 100644 index 00000000..9a5ba19a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/todo/objects/TodoObject.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:uuid/uuid.dart'; +import 'dart:math'; +import '../objects/ColorChoice.dart'; + +enum TodoCardSettings { edit_color, delete } + +class TodoObject { + TodoObject(String title, IconData icon) { + this.title = title; + this.icon = icon; + ColorChoice choice = ColorChoices.choices[Random().nextInt(ColorChoices.choices.length)]; + this.color = choice.primary; + this.gradient = LinearGradient(colors: choice.gradient, begin: Alignment.bottomCenter, end: Alignment.topCenter); + tasks = Map>(); + this.uuid = Uuid().v1(); + } + + TodoObject.import(String uuidS, String title, int sortID, ColorChoice color, IconData icon, Map> tasks) { + this.sortID = sortID; + this.title = title; + this.color = color.primary; + this.gradient = LinearGradient(colors: color.gradient, begin: Alignment.bottomCenter, end: Alignment.topCenter); + this.icon = icon; + this.tasks = tasks; + this.uuid = uuidS; + } + + String uuid; + int sortID; + String title; + Color color; + LinearGradient gradient; + IconData icon; + Map> tasks; + + int taskAmount() { + int amount = 0; + tasks.values.forEach((list) { + amount += list.length; + }); + return amount; + } + + //List tasks; + + double percentComplete() { + if (tasks.isEmpty) { + return 1.0; + } + int completed = 0; + int amount = 0; + tasks.values.forEach((list) { + amount += list.length; + list.forEach((task) { + if (task.isCompleted()) { + completed++; + } + }); + }); + return completed / amount; + } +} + +class TaskObject { + DateTime date; + String task; + bool _completed; + + TaskObject(String task, DateTime date) { + this.task = task; + this.date = date; + this._completed = false; + } + + TaskObject.import(String task, DateTime date, bool completed) { + this.task = task; + this.date = date; + this._completed = completed; + } + + void setComplete(bool value) { + _completed = value; + } + + isCompleted() => _completed; +} diff --git a/FlutterHelper/flutter_helper/lib/templates/todo/pages/Details.dart b/FlutterHelper/flutter_helper/lib/templates/todo/pages/Details.dart new file mode 100644 index 00000000..91fd2cec --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/todo/pages/Details.dart @@ -0,0 +1,276 @@ +import 'package:flutter/material.dart'; +import '../objects/TodoObject.dart'; +import 'package:intl/intl.dart'; +import '../CustomCheckboxTile.dart'; + +class DetailPage extends StatefulWidget { + DetailPage({@required this.todoObject, Key key}) : super(key: key); + + final TodoObject todoObject; + + @override + _DetailPageState createState() => _DetailPageState(); +} + +class _DetailPageState extends State with TickerProviderStateMixin { + double percentComplete; + AnimationController animationBar; + double barPercent = 0.0; + Tween animT; + AnimationController scaleAnimation; + + @override + void initState() { + scaleAnimation = AnimationController(vsync: this, duration: Duration(milliseconds: 1000), lowerBound: 0.0, upperBound: 1.0); + + percentComplete = widget.todoObject.percentComplete(); + barPercent = percentComplete; + animationBar = AnimationController(vsync: this, duration: Duration(milliseconds: 100)) + ..addListener(() { + setState(() { + barPercent = animT.transform(animationBar.value); + }); + }); + animT = Tween(begin: percentComplete, end: percentComplete); + scaleAnimation.forward(); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + animationBar.dispose(); + scaleAnimation.dispose(); + } + + void updateBarPercent() async { + double newPercentComplete = widget.todoObject.percentComplete(); + if (animationBar.status == AnimationStatus.forward || animationBar.status == AnimationStatus.completed) { + animT.begin = newPercentComplete; + await animationBar.reverse(); + } else { + animT.end = newPercentComplete; + await animationBar.forward(); + } + percentComplete = newPercentComplete; + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Hero( + tag: widget.todoObject.uuid + "_background", + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(0.0), + ), + ), + ), + Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + backgroundColor: Colors.transparent, + elevation: 0.0, + leading: Hero( + tag: widget.todoObject.uuid + "_backIcon", + child: Material( + color: Colors.transparent, + type: MaterialType.transparency, + child: IconButton( + icon: Icon(Icons.arrow_back), + color: Colors.grey, + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + ), + actions: [ + Hero( + tag: widget.todoObject.uuid + "_more_vert", + child: Material( + color: Colors.transparent, + type: MaterialType.transparency, + child: PopupMenuButton( + icon: Icon( + Icons.more_vert, + color: Colors.grey, + ), + itemBuilder: (context) => >[ + PopupMenuItem( + child: Text("Edit Color"), + value: TodoCardSettings.edit_color, + ), + PopupMenuItem( + child: Text("Delete"), + value: TodoCardSettings.delete, + ), + ], + onSelected: (setting) { + switch (setting) { + case TodoCardSettings.edit_color: + print("edit color clicked"); + break; + case TodoCardSettings.delete: + print("delete clicked"); + break; + } + }, + ), + ), + ) + ], + ), + body: Padding( + padding: EdgeInsets.only(left: 40.0, right: 40.0, top: 35.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 30.0), + child: Align( + alignment: Alignment.bottomLeft, + child: Hero( + tag: widget.todoObject.uuid + "_icon", + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.grey.withAlpha(70), style: BorderStyle.solid, width: 1.0), + ), + child: Padding( + padding: EdgeInsets.all(8.0), + child: Icon( + widget.todoObject.icon, + color: widget.todoObject.color, + ), + ), + ), + ), + ), + ), + Padding( + padding: EdgeInsets.only(bottom: 12.0), + child: Align( + alignment: Alignment.bottomLeft, + child: Hero( + tag: widget.todoObject.uuid + "_number_of_tasks", + child: Material( + color: Colors.transparent, + child: Text( + widget.todoObject.taskAmount().toString() + " Tasks", + style: TextStyle(), + softWrap: false, + ), + ), + ), + ), + ), + Padding( + padding: EdgeInsets.only(bottom: 20.0), + child: Align( + alignment: Alignment.bottomLeft, + child: Hero( + tag: widget.todoObject.uuid + "_title", + child: Material( + color: Colors.transparent, + child: Text( + widget.todoObject.title, + style: TextStyle(fontSize: 30.0), + softWrap: false, + ), + ), + ), + ), + ), + Padding( + padding: EdgeInsets.only(bottom: 30.0), + child: Align( + alignment: Alignment.bottomLeft, + child: Hero( + tag: widget.todoObject.uuid + "_progress_bar", + child: Material( + color: Colors.transparent, + child: Row( + children: [ + Expanded( + child: LinearProgressIndicator( + value: barPercent, + backgroundColor: Colors.grey.withAlpha(50), + valueColor: AlwaysStoppedAnimation(widget.todoObject.color), + ), + ), + Padding( + padding: EdgeInsets.only(left: 5.0), + child: Text((barPercent * 100).round().toString() + "%"), + ) + ], + ), + ), + ), + ), + ), + Expanded( + child: Hero( + tag: widget.todoObject.uuid + "_just_a_test", + child: Material( + type: MaterialType.transparency, + child: FadeTransition( + opacity: scaleAnimation, + child: ScaleTransition( + scale: scaleAnimation, + child: ListView.builder( + padding: EdgeInsets.all(0.0), + itemBuilder: (BuildContext context, int index) { + DateTime currentDate = widget.todoObject.tasks.keys.toList()[index]; + DateTime _now = DateTime.now(); + DateTime today = DateTime(_now.year, _now.month, _now.day); + String dateString; + if (currentDate.isBefore(today.subtract(Duration(days: 7)))) { + dateString = DateFormat.yMMMMEEEEd().format(currentDate); + } else if (currentDate.isBefore(today)) { + dateString = "Previous - " + DateFormat.E().format(currentDate); + } else if (currentDate.isAtSameMomentAs(today)) { + dateString = "Today"; + } else if (currentDate.isAtSameMomentAs(today.add(Duration(days: 1)))) { + dateString = "Tomorrow"; + } else { + dateString = DateFormat.E().format(currentDate); + } + List tasks = [Text(dateString)]; + widget.todoObject.tasks[currentDate].forEach((task) { + tasks.add(CustomCheckboxListTile( + activeColor: widget.todoObject.color, + value: task.isCompleted(), + onChanged: (value) { + setState(() { + task.setComplete(value); + updateBarPercent(); + }); + }, + title: Text(task.task), + secondary: Icon(Icons.alarm), + )); + }); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: tasks, + ); + }, + itemCount: widget.todoObject.tasks.length, + ), + ), + ), + ), + ), + ), + ], + ), + ), + ) + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/templates/todo/pages/Home.dart b/FlutterHelper/flutter_helper/lib/templates/todo/pages/Home.dart new file mode 100644 index 00000000..fb2063bf --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/templates/todo/pages/Home.dart @@ -0,0 +1,373 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import '../DummyData.dart'; +import '../CustomIcons.dart'; +import '../objects/TodoObject.dart'; +import '../pages/Details.dart'; + +class HomePage extends StatefulWidget { + HomePage({Key key}) : super(key: key); + + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends State with TickerProviderStateMixin { + ScrollController scrollController; + Color backgroundColor; + LinearGradient backgroundGradient; + Tween colorTween; + int currentPage = 0; + Color constBackColor; + + @override + void initState() { + super.initState(); + colorTween = ColorTween(begin: todos[0].color, end: todos[0].color); + backgroundColor = todos[0].color; + backgroundGradient = todos[0].gradient; + scrollController = ScrollController(); + scrollController.addListener(() { + ScrollPosition position = scrollController.position; +// ScrollDirection direction = position.userScrollDirection; + int page = position.pixels ~/ (position.maxScrollExtent / (todos.length.toDouble() - 1)); + double pageDo = (position.pixels / (position.maxScrollExtent / (todos.length.toDouble() - 1))); + double percent = pageDo - page; + if (todos.length - 1 < page + 1) { + return; + } + colorTween.begin = todos[page].color; + colorTween.end = todos[page + 1].color; + setState(() { + backgroundColor = colorTween.transform(percent); + backgroundGradient = todos[page].gradient.lerpTo(todos[page + 1].gradient, percent); + }); + }); + } + + @override + void dispose() { + super.dispose(); + scrollController.dispose(); + } + + @override + Widget build(BuildContext context) { + final double _width = MediaQuery.of(context).size.width; + + return Container( + decoration: BoxDecoration(gradient: backgroundGradient), + child: Scaffold( + backgroundColor: Colors.transparent, + appBar: AppBar( + backgroundColor: Colors.transparent, + elevation: 0.0, + title: Text("TODO"), + centerTitle: true, + leading: IconButton( + icon: Icon(CustomIcons.menu), + onPressed: () {}, + ), + actions: [ + IconButton( + icon: Icon( + CustomIcons.search, + size: 26.0, + ), + onPressed: () {}, + ) + ], + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Spacer(), + Padding( + padding: EdgeInsets.only(left: 50.0), + child: Container( + decoration: BoxDecoration( + boxShadow: [BoxShadow(color: Colors.black38, offset: Offset(5.0, 5.0), blurRadius: 15.0)], + shape: BoxShape.circle, + ), + child: CircleAvatar( + backgroundColor: Colors.grey, + ), + ), + ), + Spacer( + flex: 2, + ), + Padding( + padding: EdgeInsets.only(left: 50.0), + child: Text( + "Hello, John.", + style: TextStyle(color: Colors.white, fontSize: 30.0), + ), + ), + Spacer(), + Padding( + padding: EdgeInsets.only(left: 50.0), + child: Text( + "This is a daily quote.", + style: TextStyle(color: Colors.white70), + ), + ), + Padding( + padding: EdgeInsets.only(left: 50.0), + child: Text( + "You have 10 tasks to do today.", + style: TextStyle(color: Colors.white70), + ), + ), + Spacer( + flex: 2, + ), + Padding( + padding: EdgeInsets.only( + left: 50.0, + ), + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: "TODAY : ", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + ), + ), + TextSpan( + text: DateFormat.yMMMMd().format(DateTime.now()), + style: TextStyle( + color: Colors.white, + ), + ), + ], + ), + ), + ), + Spacer(), + Expanded( + flex: 20, + child: ListView.builder( + itemBuilder: (context, index) { + TodoObject todoObject = todos[index]; + double percentComplete = todoObject.percentComplete(); + + return Padding( + padding: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 30.0), + child: InkWell( + onTap: () { + Navigator.of(context).push( + PageRouteBuilder( + pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) => DetailPage(todoObject: todoObject), + transitionDuration: Duration(milliseconds: 1000), + ), + ); + }, + child: Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(10.0), boxShadow: [BoxShadow(color: Colors.black.withAlpha(70), offset: Offset(3.0, 10.0), blurRadius: 15.0)]), + height: 250.0, + child: Stack( + children: [ + Hero( + tag: todoObject.uuid + "_background", + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.0), + ), + ), + ), + Padding( + padding: EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + flex: 10, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + children: [ + Hero( + tag: todoObject.uuid + "_backIcon", + child: Material( + type: MaterialType.transparency, + child: Container( + height: 0, + width: 0, + child: IconButton( + icon: Icon(Icons.arrow_back), + onPressed: null, + ), + ), + ), + ), + Hero( + tag: todoObject.uuid + "_icon", + child: Container( + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + border: Border.all(color: Colors.grey.withAlpha(70), style: BorderStyle.solid, width: 1.0), + ), + child: Padding( + padding: EdgeInsets.all(8.0), + child: Icon(todoObject.icon, color: todoObject.color), + ), + ), + ), + ], + ), + Spacer(), + Hero( + tag: todoObject.uuid + "_more_vert", + child: Material( + color: Colors.transparent, + type: MaterialType.transparency, + child: PopupMenuButton( + icon: Icon( + Icons.more_vert, + color: Colors.grey, + ), + itemBuilder: (context) => >[ + PopupMenuItem( + child: Text("Edit Color"), + value: TodoCardSettings.edit_color, + ), + PopupMenuItem( + child: Text("Delete"), + value: TodoCardSettings.delete, + ), + ], + onSelected: (setting) { + switch (setting) { + case TodoCardSettings.edit_color: + print("edit color clicked"); + break; + case TodoCardSettings.delete: + print("delete clicked"); + setState(() { + todos.remove(todoObject); + }); + break; + } + }, + ), + ), + ), + ], + ), + ), + Hero( + tag: todoObject.uuid + "_number_of_tasks", + child: Material( + color: Colors.transparent, + child: Text( + todoObject.taskAmount().toString() + " Tasks", + style: TextStyle(), + softWrap: false, + )), + ), + Spacer(), + Hero( + tag: todoObject.uuid + "_title", + child: Material( + color: Colors.transparent, + child: Text( + todoObject.title, + style: TextStyle(fontSize: 30.0), + softWrap: false, + ), + ), + ), + Spacer(), + Hero( + tag: todoObject.uuid + "_progress_bar", + child: Material( + color: Colors.transparent, + child: Row( + children: [ + Expanded( + child: LinearProgressIndicator( + value: percentComplete, + backgroundColor: Colors.grey.withAlpha(50), + valueColor: AlwaysStoppedAnimation(todoObject.color), + ), + ), + Padding( + padding: EdgeInsets.only(left: 5.0), + child: Text((percentComplete * 100).round().toString() + "%"), + ) + ], + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + }, + padding: EdgeInsets.only(left: 40.0, right: 40.0), + scrollDirection: Axis.horizontal, + physics: _CustomScrollPhysics(), + controller: scrollController, + itemExtent: _width - 80, + itemCount: todos.length, + ), + ), + Spacer( + flex: 2, + ), + ], + ), + ), + ); + } +} + +class _CustomScrollPhysics extends ScrollPhysics { + _CustomScrollPhysics({ + ScrollPhysics parent, + }) : super(parent: parent); + + @override + _CustomScrollPhysics applyTo(ScrollPhysics ancestor) { + return _CustomScrollPhysics(parent: buildParent(ancestor)); + } + + double _getPage(ScrollPosition position) { + return position.pixels / (position.maxScrollExtent / (todos.length.toDouble() - 1)); + // return position.pixels / position.viewportDimension; + } + + double _getPixels(ScrollPosition position, double page) { + // return page * position.viewportDimension; + return page * (position.maxScrollExtent / (todos.length.toDouble() - 1)); + } + + double _getTargetPixels(ScrollPosition position, Tolerance tolerance, double velocity) { + double page = _getPage(position); + if (velocity < -tolerance.velocity) + page -= 0.5; + else if (velocity > tolerance.velocity) page += 0.5; + return _getPixels(position, page.roundToDouble()); + } + + @override + Simulation createBallisticSimulation(ScrollMetrics position, double velocity) { + if ((velocity <= 0.0 && position.pixels <= position.minScrollExtent) || (velocity >= 0.0 && position.pixels >= position.maxScrollExtent)) return super.createBallisticSimulation(position, velocity); + final Tolerance tolerance = this.tolerance; + final double target = _getTargetPixels(position, tolerance, velocity); + if (target != position.pixels) return ScrollSpringSimulation(spring, position.pixels, target, velocity, tolerance: tolerance); + return null; + } +} diff --git a/FlutterHelper/flutter_helper/lib/test.dart b/FlutterHelper/flutter_helper/lib/test.dart new file mode 100644 index 00000000..0975fe2a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/test.dart @@ -0,0 +1,6 @@ + + +void main() { + List veggies = ["1", "2", "3", "4"]; + print('${veggies.indexOf("2")}'); +} diff --git a/FlutterHelper/flutter_helper/lib/test/ConstructorDemo.dart b/FlutterHelper/flutter_helper/lib/test/ConstructorDemo.dart new file mode 100644 index 00000000..83ca8da4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/test/ConstructorDemo.dart @@ -0,0 +1,173 @@ +import 'package:flutter/cupertino.dart'; + +class Person { + String name; + num age; + + Person({this.name, this.age}); + + Person.fromDictionary(Map dic) { + this.name = dic['name']; + this.age = dic['age']; + } +} + +class Person2 { + String firstName; + + // 无参数的,非命名的构造函数 + Person2() { + print('in Person2'); + } +} + +class Son2 extends Person2 { + // 因为父类有无参数的,非命名的构造函数, 所以可以不用手动调用父类的构造函数 + Son2.fromDictionary(Map data) { + print('in son2'); + } +} + +// 如果父类不现实提供无名无参的构造函数,在子类中必须手动调用父类的一个构造函数。 +// 这种情况下,调用父类的构造函数的代码放在子类构造函数名后,子类构造函数体前,中间使用:分割 +class Son3 extends Son2 { + // 父类没有无参数的,非命名的 构造函数,所以必须手动调用一个父类的构造函数 + Son3.fromDictionary(Map data) : super.fromDictionary(data) { + print('in Son3'); + } +} + +// 父类中的命名构造函数不能被子类继承。如果想要子类也拥有一个父类一样名字的构造函数, +// 必须在子类中实现这个构造函数 + +//如果想要让类产生一个永远不会改变的对象,可以让这些对象成为编译时常量。为此,需要定义一个 const 构造函数并确保所有的实例变量都是 final 的 +class ImmutablePoint { + final num x; + final num y; + + const ImmutablePoint(this.x, this.y); + + static final ImmutablePoint origin = const ImmutablePoint(0, 0); +} + +class Point { + num x; + num y; + + // 主构造函数 + Point(this.x, this.y); + + // 重定向构造函数, 指向主构造函数, 函数体为空 + // 貌似swift中遍历构造函数,但略有不同 + Point.alongXAxis(num x) : this(x, 0); +} + +class Vehicle { + Vehicle() { + print("super constructor"); + } + + Vehicle.get() { + print("super Run"); + } + + Vehicle.create() { + print("super create"); + } +} + +class Audi extends Vehicle { + Audi() { + print("Audi constructor"); + } + + Audi.get() : super.get() { + print("Audi run"); + } + + Audi.create() { + print("Audi create"); + } +} + +class Point3 { + num x, y; + + Point3(this.x, this.y); + + Point3.origin() { + this.x = 10; + this.y = 10; + } + + // 构造参数为实例变量直接赋值 + Point3.rect(this.x, this.y); + + Point3.fromJson(Map json) + : x = json['x'], + y = json['y'] { + print("In Point.fromJson(): ($x, $y)"); + } + + void pointPrint() { + print("x = $x, y = $y"); + } +} + +class Rect { + num x, y, wid, hei; + + Rect(this.x, this.y, this.wid, this.hei); + + Rect.withSize(num width, num height) : this(0, 0, width, height); +} + +// 常量构造函数(单利) +class ImmutablePoint2 { + static final ImmutablePoint2 origin = const ImmutablePoint2(0, 0); + final num x, y; + + const ImmutablePoint2(this.x, this.y); +} + +// 工厂构造函数(池子) +class Logger { + final String name; + bool mute = false; + + // _cache is library-private, thanks to + // the _ in front of its name. + static final Map _cache = {}; + + factory Logger(String name){ + if(_cache.containsKey(name)) { + return _cache[name]; + } else { + final logger = Logger._internal(name); + _cache[name] = logger; + return logger; + } + } + + Logger._internal(this.name); + + void log(String msg) { + if(!mute) print(msg); + } + + + +} + +int main() { + Audi audi0 = Audi(); + Audi audi1 = Audi.create(); + Audi audi2 = Audi.get(); + + Point3 p3 = Point3.origin(); + p3.pointPrint(); + + // 调用 + var logger = Logger('UI'); + logger.log("Button clicked"); +} diff --git a/FlutterHelper/flutter_helper/lib/trip/home/home_dao.dart b/FlutterHelper/flutter_helper/lib/trip/home/home_dao.dart new file mode 100644 index 00000000..4160b1c9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/home/home_dao.dart @@ -0,0 +1,22 @@ +import 'dart:convert'; + +import 'package:flutter_helper/trip/home/home_model.dart'; +import 'package:http/http.dart' as http; + +class HomeDao { + + static final String HOME_URL = 'http://www.devio.org/io/flutter_app/json/home_page.json'; + + static Future fetch() async { + + final response = await http.get(Uri.parse(HOME_URL)); + if(response.statusCode == 200) { + Utf8Decoder utf8decoder = Utf8Decoder(); + var result = json.decode(utf8decoder.convert(response.bodyBytes)); + return HomeModel.fromJson(result); + } else { + throw Exception('Failed to load home_page.json'); + } + } + +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/trip/home/home_dart.dart b/FlutterHelper/flutter_helper/lib/trip/home/home_dart.dart new file mode 100644 index 00000000..11e14a61 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/home/home_dart.dart @@ -0,0 +1,194 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/home/home_dao.dart'; +import 'package:flutter_helper/trip/home/home_model.dart'; +import 'package:flutter_helper/trip/home/nav_grid.dart'; +import 'package:flutter_helper/trip/home/nav_local.dart'; +import 'package:flutter_helper/trip/utils.dart'; +import 'package:flutter_helper/trip/widget/LoadingContainer.dart'; +import 'package:flutter_helper/trip/widget/search_bar.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; +import 'package:flutter_swiper/flutter_swiper.dart'; + +import 'nav_sale.dart'; +import 'nav_sub.dart'; + +const APPBAR_SCROLL_OFFSET = 100; +const SEARCH_BAR_DEFAULT_TEXT = '网红打卡地 景点 酒店 美食'; + +class HomePage extends StatefulWidget { + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends State { + double _appBarAlpha = 0; + List _localNavList = []; + List _bannerList = []; + List _subNavList = []; + GridNavModel _gridNavModel; + SalesBoxModel _salesBoxModel; + bool _loading = true; + + @override + void initState() { + super.initState(); + _handleRefresh(); + } + + _onScroll(offset) { + double alpha = offset / APPBAR_SCROLL_OFFSET; + if (alpha < 0) { + alpha = 0; + } else if (alpha > 1) { + alpha = 1; + } + setState(() { + _appBarAlpha = alpha; + }); + print(_appBarAlpha); + } + + Future _handleRefresh() async { + try { + HomeModel model = await HomeDao.fetch(); + setState(() { + _localNavList = model.localNavList; + _subNavList = model.subNavList; + _gridNavModel = model.gridNav; + _salesBoxModel = model.salesBox; + _bannerList = model.bannerList; + _loading = false; + }); + } catch (e) { + print(e); + setState(() { + _loading = false; + }); + } + return null; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color(0xfff2f2f2), + body: LoadingContainer( + isLoading: _loading, + child: Stack( + children: [ + MediaQuery.removePadding( + removeTop: true, + context: context, + child: RefreshIndicator( + onRefresh: _handleRefresh, + child: NotificationListener( + onNotification: (notif) { + if (notif is ScrollUpdateNotification && notif.depth == 0) { + _onScroll(notif.metrics.pixels); + } + return true; + }, + child: _listView, + ), + ), + ), + _appBar, + ], + ), + ), + ); + } + + Widget get _appBar { + return Column( + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + // AppBar 渐变遮罩背景 + colors: [Color(0x66000000), Colors.transparent], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Container( + padding: EdgeInsets.fromLTRB(0, 20, 0, 0), + height: 80.0, + decoration: BoxDecoration( + color: + Color.fromARGB((_appBarAlpha * 255).toInt(), 255, 255, 255), + ), + child: SearchBar( + searchBarType: _appBarAlpha > 0.2 + ? SearchBarType.homeLight + : SearchBarType.home, + // inputBoxClick: _jumpToSearch, + // speakClick: _jumpToSpeak, + defaultText: SEARCH_BAR_DEFAULT_TEXT, + leftButtonClick: () {}, + ), + ), + ), + Container( + height: _appBarAlpha > 0.2 ? 0.5 : 0, + decoration: BoxDecoration( + color: Colors.red, + boxShadow: [ + BoxShadow(color: Colors.black12, blurRadius: 0.5), + ], + ), + ), + ], + ); + } + + Widget get _banner { + return Container( + height: 180, + child: Swiper( + itemCount: _bannerList.length, + autoplay: true, + itemBuilder: (context, index) { + return GestureDetector( + onTap: () { + CommonModel model = _bannerList[index]; + NavigatorUtil.push( + context, + WebView( + url: model.url, + title: model.title, + hideAppBar: model.hideAppBar, + )); + }, + child: Image.network(_bannerList[index].icon, fit: BoxFit.fill), + ); + }, + pagination: SwiperPagination(), + ), + ); + } + + Widget get _listView { + return ListView( + children: [ + _banner, + Padding( + padding: EdgeInsets.fromLTRB(7, 4, 7, 4), + child: LocalNav(localNavList: _localNavList), + ), + Padding( + padding: EdgeInsets.fromLTRB(7, 4, 7, 4), + child: GridNav(gridNavModel: _gridNavModel), + ), + Padding( + padding: EdgeInsets.fromLTRB(7, 4, 7, 4), + child: SubNav(subNavList: _subNavList), + ), + Padding( + padding: EdgeInsets.fromLTRB(7, 4, 7, 4), + child: SalesNav(salesBoxModel: _salesBoxModel), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/home/home_model.dart b/FlutterHelper/flutter_helper/lib/trip/home/home_model.dart new file mode 100644 index 00000000..71f483cd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/home/home_model.dart @@ -0,0 +1,160 @@ +class HomeModel { + final ConfigModel config; + final List bannerList; + final List localNavList; + final List subNavList; + final GridNavModel gridNav; + final SalesBoxModel salesBox; + + HomeModel( + {this.config, + this.bannerList, + this.localNavList, + this.subNavList, + this.gridNav, + this.salesBox}); + + factory HomeModel.fromJson(Map json) { + var localNavListJson = json['localNavList'] as List; + List localNavList = + localNavListJson.map((i) => CommonModel.fromJson(i)).toList(); + + var bannerListJson = json['bannerList'] as List; + List bannerList = + bannerListJson.map((i) => CommonModel.fromJson(i)).toList(); + + var subNavListJson = json['subNavList'] as List; + List subNavList = + subNavListJson.map((i) => CommonModel.fromJson(i)).toList(); + + return HomeModel( + localNavList: localNavList, + bannerList: bannerList, + subNavList: subNavList, + config: ConfigModel.fromJson(json['config']), + gridNav: GridNavModel.fromJson(json['gridNav']), + salesBox: SalesBoxModel.fromJson(json['salesBox']), + ); + } +} + +class ConfigModel { + final String searchUrl; + + ConfigModel({this.searchUrl}); + + factory ConfigModel.fromJson(Map json) { + return ConfigModel(searchUrl: json['searchUrl']); + } + + Map toJson() { + return {searchUrl: searchUrl}; + } +} + +class CommonModel { + final String icon; + final String title; + final String url; + final String statusBarColor; + final bool hideAppBar; + + CommonModel( + {this.icon, this.title, this.url, this.statusBarColor, this.hideAppBar}); + + factory CommonModel.fromJson(Map json) { + return CommonModel( + icon: json['icon'], + title: json['title'], + url: json['url'], + statusBarColor: json['statusBarColor'], + hideAppBar: json['hideAppBar']); + } +} + +///首页网格卡片模型 +class GridNavModel { + final GridNavItem hotel; + final GridNavItem flight; + final GridNavItem travel; + + GridNavModel({this.hotel, this.flight, this.travel}); + + factory GridNavModel.fromJson(Map json) { + return json != null + ? GridNavModel( + hotel: GridNavItem.fromJson(json['hotel']), + flight: GridNavItem.fromJson(json['flight']), + travel: GridNavItem.fromJson(json['travel']), + ) + : null; + } +} + +class GridNavItem { + final String startColor; + final String endColor; + final CommonModel mainItem; + final CommonModel item1; + final CommonModel item2; + final CommonModel item3; + final CommonModel item4; + + GridNavItem( + {this.startColor, + this.endColor, + this.mainItem, + this.item1, + this.item2, + this.item3, + this.item4}); + + factory GridNavItem.fromJson(Map json) { + return GridNavItem( + startColor: json['startColor'], + endColor: json['endColor'], + mainItem: CommonModel.fromJson(json['mainItem']), + item1: CommonModel.fromJson(json['item1']), + item2: CommonModel.fromJson(json['item2']), + item3: CommonModel.fromJson(json['item3']), + item4: CommonModel.fromJson(json['item4']), + ); + } +} + + +///活动入口模型 +class SalesBoxModel { + final String icon; + final String moreUrl; + final CommonModel bigCard1; + final CommonModel bigCard2; + final CommonModel smallCard1; + final CommonModel smallCard2; + final CommonModel smallCard3; + final CommonModel smallCard4; + + SalesBoxModel( + {this.icon, + this.moreUrl, + this.bigCard1, + this.bigCard2, + this.smallCard1, + this.smallCard2, + this.smallCard3, + this.smallCard4}); + + factory SalesBoxModel.fromJson(Map json) { + return SalesBoxModel( + icon: json['icon'], + moreUrl: json['moreUrl'], + bigCard1: CommonModel.fromJson(json['bigCard1']), + bigCard2: CommonModel.fromJson(json['bigCard2']), + smallCard1: CommonModel.fromJson(json['smallCard1']), + smallCard2: CommonModel.fromJson(json['smallCard2']), + smallCard3: CommonModel.fromJson(json['smallCard3']), + smallCard4: CommonModel.fromJson(json['smallCard4']), + ); + } +} + diff --git a/FlutterHelper/flutter_helper/lib/trip/home/nav_grid.dart b/FlutterHelper/flutter_helper/lib/trip/home/nav_grid.dart new file mode 100644 index 00000000..6004c49e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/home/nav_grid.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/home/home_model.dart'; +import 'package:flutter_helper/trip/utils.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; + +class GridNav extends StatelessWidget { + final GridNavModel gridNavModel; + + const GridNav({Key key, @required this.gridNavModel}) : super(key: key); + + @override + Widget build(BuildContext context) { + return PhysicalModel( + color: Colors.transparent, + borderRadius: BorderRadius.circular(6), + clipBehavior: Clip.antiAlias, + child: Column( + children: _gridNavItems(context), + ), + ); + } + + _gridNavItems(BuildContext context) { + List items = []; + if (gridNavModel == null) return items; + if (gridNavModel.hotel != null) { + items.add(_gridNavItem(context, gridNavModel.hotel, true)); + } + if (gridNavModel.flight != null) { + items.add(_gridNavItem(context, gridNavModel.flight, false)); + } + if (gridNavModel.travel != null) { + items.add(_gridNavItem(context, gridNavModel.travel, false)); + } + + return items; + } + + Widget _gridNavItem( + BuildContext context, GridNavItem gridNavItem, bool first) { + List items = []; + items.add(_mainItem(context, gridNavItem.mainItem)); + items.add(_doubleItem(context, gridNavItem.item1, gridNavItem.item2)); + items.add(_doubleItem(context, gridNavItem.item3, gridNavItem.item4)); + List expandItems = []; + items.forEach((item) { + expandItems.add(Expanded(child: item, flex: 1)); + }); + Color startColor = Color(int.parse('0xff' + gridNavItem.startColor)); + Color endColor = Color(int.parse('0xff' + gridNavItem.endColor)); + return Container( + height: 88, + margin: first ? null : EdgeInsets.only(top: 3), + decoration: BoxDecoration( + // 线性渐变 + gradient: LinearGradient(colors: [startColor, endColor]), + ), + child: Row(children: expandItems), + ); + } + + Widget _mainItem(BuildContext context, CommonModel model) { + return _wrapGesture( + context, + Stack( + alignment: AlignmentDirectional.topCenter, + children: [ + Image.network( + model.icon, + fit: BoxFit.contain, + height: 88, + width: 121, + alignment: AlignmentDirectional.bottomEnd, + ), + Container( + margin: EdgeInsets.only(top: 11), + child: Text( + model.title, + style: TextStyle(fontSize: 14, color: Colors.white), + ), + ), + ], + ), + model); + } + + Widget _doubleItem( + BuildContext context, CommonModel topItem, CommonModel bottomItem) { + return Column( + children: [ + Expanded(child: _item(context, topItem, true)), + Expanded(child: _item(context, bottomItem, false)), + ], + ); + } + + _item(BuildContext context, CommonModel item, bool first) { + BorderSide borderSide = BorderSide(width: 0.8, color: Colors.white); + return FractionallySizedBox( + widthFactor: 1, //撑满父布局的宽度 + child: Container( + decoration: BoxDecoration( + border: Border( + left: borderSide, bottom: first ? borderSide : BorderSide.none), + ), + child: _wrapGesture( + context, + Center( + child: Text( + item.title, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 14, color: Colors.white), + ), + ), + item), + ), + ); + } + + _wrapGesture(BuildContext context, Widget widget, CommonModel model) { + return GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: model.url, + statusBarColor: model.statusBarColor, + title: model.title, + hideAppBar: model.hideAppBar, + )); + }, + child: widget, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/home/nav_local.dart b/FlutterHelper/flutter_helper/lib/trip/home/nav_local.dart new file mode 100644 index 00000000..6f7cf193 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/home/nav_local.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/home/home_model.dart'; +import 'package:flutter_helper/trip/utils.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; + +class LocalNav extends StatelessWidget { + final List localNavList; + + const LocalNav({Key key, this.localNavList}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: 64, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6)), + ), + child: Padding( + padding: EdgeInsets.all(7), + child: _items(context), + ), + ); + } + + _items(BuildContext context) { + if (localNavList == null) return null; + List items = []; + localNavList.forEach((model) { + items.add(_item(context, model)); + }); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: items, + ); + } + + Widget _item(BuildContext context, CommonModel model) { + return GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: model.url, + statusBarColor: model.statusBarColor, + hideAppBar: model.hideAppBar, + )); + }, + child: Column( + children: [ + Image.network(model.icon, width: 32, height: 32), + Text(model.title, style: TextStyle(fontSize: 12)), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/home/nav_sale.dart b/FlutterHelper/flutter_helper/lib/trip/home/nav_sale.dart new file mode 100644 index 00000000..e7548a52 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/home/nav_sale.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/home/home_model.dart'; +import 'package:flutter_helper/trip/utils.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; + +class SalesNav extends StatelessWidget { + final SalesBoxModel salesBoxModel; + + const SalesNav({Key key, this.salesBoxModel}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration(color: Colors.white), + child: _items(context), + ); + } + + _items(BuildContext context) { + if (salesBoxModel == null) return null; + List items = []; + items.add(_doubleItem( + context, + salesBoxModel.bigCard1, + salesBoxModel.bigCard2, + true, + false, + )); + items.add(_doubleItem( + context, + salesBoxModel.smallCard1, + salesBoxModel.smallCard2, + false, + false, + )); + items.add(_doubleItem( + context, + salesBoxModel.smallCard3, + salesBoxModel.smallCard4, + false, + true, + )); + + return Column( + children: [ + Container( + height: 44, + margin: EdgeInsets.only(left: 10), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 1, + color: Color(0xfff2f2f2), + ), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Image.network(salesBoxModel.icon, width: 15, fit: BoxFit.fill), + Container( + padding: EdgeInsets.only(right: 7), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + gradient: LinearGradient( + colors: [Color(0xffff4e63), Color(0xffff6cc9)], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + ), + child: GestureDetector( + onTap: () { + NavigatorUtil.push(context, + WebView(url: salesBoxModel.moreUrl, title: "更多活动")); + }, + child: Text( + '获取更多福利>', + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: items.sublist(0, 1)), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: items.sublist(1, 2)), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: items.sublist(2, 3)), + ], + ); + } + Widget _doubleItem(BuildContext context, CommonModel leftCard, + CommonModel rightCard, bool big, bool last) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _item(context, leftCard, big, true, last), + _item(context, rightCard, big, false, last) + ], + ); + } + + Widget _item( + BuildContext context, CommonModel model, bool big, bool left, bool last) { + BorderSide borderSide = BorderSide(width: 0.8, color: Color(0xfff2f2f2)); + return GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: model.url, + statusBarColor: model.statusBarColor, + hideAppBar: model.hideAppBar, + )); + }, + child: Container( + decoration: BoxDecoration( + border: Border( + right: left ? borderSide : BorderSide.none, + bottom: last ? BorderSide.none : borderSide)), + child: Image.network( + model.icon, + fit: BoxFit.fill, + width: MediaQuery.of(context).size.width / 2 - 10, + height: big ? 129 : 80, + ), + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/home/nav_sub.dart b/FlutterHelper/flutter_helper/lib/trip/home/nav_sub.dart new file mode 100644 index 00000000..8091efea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/home/nav_sub.dart @@ -0,0 +1,79 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/home/home_model.dart'; +import 'package:flutter_helper/trip/utils.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; + +class SubNav extends StatelessWidget { + final List subNavList; + + const SubNav({Key key, this.subNavList}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(6), + ), + child: Padding( + padding: EdgeInsets.all(7), + child: _items(context), + ), + ); + } + + _items(BuildContext context) { + if (subNavList == null) return null; + List items = []; + subNavList.forEach((element) { + items.add(_item(context, element)); + }); + // 计算出第一行显示的数量 + int separate = (subNavList.length / 2 + 0.5).toInt(); + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: items.sublist(0, separate), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: items.sublist(separate, subNavList.length), + ), + ), + ], + ); + } + + Widget _item(BuildContext context, CommonModel element) { + return Expanded( + flex: 1, + child: GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: element.url, + statusBarColor: element.statusBarColor, + hideAppBar: element.hideAppBar, + ), + ); + }, + child: Column( + children: [ + Image.network(element.icon, width: 18, height: 18), + Padding( + padding: EdgeInsets.only(top: 3), + child: Text( + element.title, + style: TextStyle(fontSize: 12), + ), + ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/mine/mine_page.dart b/FlutterHelper/flutter_helper/lib/trip/mine/mine_page.dart new file mode 100644 index 00000000..ba6d3002 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/mine/mine_page.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; + +class MinePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: WebView( + url: 'https://m.ctrip.com/webapp/myctrip/', + hideAppBar: true, + backForbid: true, + statusBarColor: '4c5bca', + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/navigator/tab_navigator.dart b/FlutterHelper/flutter_helper/lib/trip/navigator/tab_navigator.dart new file mode 100644 index 00000000..f394b8d1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/navigator/tab_navigator.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/home/home_dart.dart'; +import 'package:flutter_helper/trip/mine/mine_page.dart'; +import 'package:flutter_helper/trip/search/search_page.dart'; +import 'package:flutter_helper/trip/trvavel/travel_page.dart'; + +class TabNavigator extends StatefulWidget { + @override + _TabNavigatorState createState() => _TabNavigatorState(); +} + +class _TabNavigatorState extends State { + final _defaultColor = Colors.grey; + final _activeColor = Colors.blue; + int _currentIndex = 0; + final PageController _controller = PageController(initialPage: 0); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: PageView( + controller: _controller, + children: [ + HomePage(), + SearchPage( + hideLeft: true, + ), + TravelPage(), + MinePage(), + ], + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, + onTap: (index) { + _controller.jumpToPage(index); + setState(() { + _currentIndex = index; + }); + }, + type: BottomNavigationBarType.fixed, + items: [ + _bottomItem('首页', Icons.home, 0), + _bottomItem('搜索', Icons.search, 1), + _bottomItem('旅拍', Icons.camera_alt, 2), + _bottomItem('我的', Icons.account_circle, 3) + ], + ), + ); + } + + _bottomItem(String title, IconData icon, int index) { + return BottomNavigationBarItem( + icon: Icon(icon, color: _defaultColor), + activeIcon: Icon(icon, color: _activeColor), + title: Text(title, + style: TextStyle( + color: _currentIndex != index ? _defaultColor : _activeColor, + )), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/search/search_dao.dart b/FlutterHelper/flutter_helper/lib/trip/search/search_dao.dart new file mode 100644 index 00000000..24396032 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/search/search_dao.dart @@ -0,0 +1,19 @@ +import 'dart:convert'; + +import 'package:flutter_helper/trip/search/search_model.dart'; +import 'package:http/http.dart' as http; + +class SearchDao { + static Future fetch(String url, String text) async { + final response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + Utf8Decoder utf8decoder = Utf8Decoder(); + var result = json.decode(utf8decoder.convert(response.bodyBytes)); + SearchModel model = SearchModel.fromJson(result); + model.keyword = text; + return model; + } else { + throw Exception('Failed to load search_page'); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/search/search_model.dart b/FlutterHelper/flutter_helper/lib/trip/search/search_model.dart new file mode 100644 index 00000000..844bedc6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/search/search_model.dart @@ -0,0 +1,44 @@ +class SearchModel { + String keyword; + final List data; + + SearchModel({this.data}); + + factory SearchModel.fromJson(Map json) { + var dataJson = json['data'] as List; + List data = + dataJson.map((i) => SearchItem.fromJson(i)).toList(); + return SearchModel(data: data); + } +} + +class SearchItem { + final String word; //xx酒店 + final String type; //hotel + final String price; //实时计价 + final String star; //豪华型 + final String zonename; //虹桥 + final String districtname; //上海 + final String url; + + SearchItem( + {this.word, + this.type, + this.price, + this.star, + this.zonename, + this.districtname, + this.url}); + + factory SearchItem.fromJson(Map json) { + return SearchItem( + word: json['word'], + type: json['type'], + price: json['price'], + star: json['star'], + zonename: json['zonename'], + districtname: json['districtname'], + url: json['url'], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/search/search_page.dart b/FlutterHelper/flutter_helper/lib/trip/search/search_page.dart new file mode 100644 index 00000000..c4b21418 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/search/search_page.dart @@ -0,0 +1,237 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/search/search_dao.dart'; +import 'package:flutter_helper/trip/search/search_model.dart'; +import 'package:flutter_helper/trip/utils.dart'; +import 'package:flutter_helper/trip/widget/search_bar.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; + +const TYPES = [ + 'channelgroup', + 'gs', + 'plane', + 'train', + 'cruise', + 'district', + 'food', + 'hotel', + 'huodong', + 'shop', + 'sight', + 'ticket', + 'travelgroup' +]; +const URL = + 'https://m.ctrip.com/restapi/h5api/searchapp/search?source=mobileweb&action=autocomplete&contentType=json&keyword='; + +class SearchPage extends StatefulWidget { + final bool hideLeft; + final String searchUrl; + final String keyword; + final String hint; + + const SearchPage( + {Key key, this.hideLeft, this.searchUrl = URL, this.keyword, this.hint}) + : super(key: key); + + @override + _SearchPageState createState() => _SearchPageState(); +} + +class _SearchPageState extends State { + SearchModel searchModel; + String keyword; + + @override + void initState() { + if (widget.keyword != null) { + _onTextChange(widget.keyword); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + _appBar(), + MediaQuery.removePadding( + removeTop: true, + context: context, + child: Expanded( + flex: 1, + child: ListView.builder( + itemCount: searchModel?.data?.length??0, + itemBuilder: (context, position) { + return _item(position); + }, + ), + ), + ), + ], + ), + ); + } + + void _onTextChange(String text) { + this.keyword = text; + if (text.length == 0) { + setState(() { + searchModel = null; + }); + } else { + String url = widget.searchUrl + text; + SearchDao.fetch(url, text).then((value) { + // 只有当前输入的内容和服务端返回的一致时才渲染 + if (value.keyword == keyword) { + setState(() { + searchModel = value; + }); + } + }).catchError((e) { + print(e); + }); + } + } + + _appBar() => Column( + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [Color(0x66000000), Colors.transparent], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Container( + padding: EdgeInsets.only(top: 20), + height: 80, + decoration: BoxDecoration(color: Colors.white), + child: SearchBar( + hideLeft: widget.hideLeft, + defaultText: widget.keyword, + hint: widget.hint, + speakClick: _jumpToSpeak, + leftButtonClick: () { + Navigator.pop(context); + }, + onChanged: _onTextChange, + ), + ), + ), + ], + ); + + void _jumpToSpeak() { + //NavigatorUtil.push(context, SpeakPage()); + } + + _item(int position) { + if (searchModel == null || searchModel.data == null) return null; + SearchItem item = searchModel.data[position]; + return GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: item.url, + title: '详情', + )); + }, + child: Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 0.3, color: Colors.grey))), + child: Row( + children: [ + Container( + margin: EdgeInsets.all(1), + child: Image( + height: 26, + width: 26, + image: AssetImage(_typeImage(item.type))), + ), + Column( + children: [ + Container( + width: 300, + child: _title(item), + ), + Container( + width: 300, + margin: EdgeInsets.only(top: 5), + child: _subTitle(item)) + ], + ) + ], + ), + ), + ); + } + + _typeImage(String type) { + if (type == null) return 'images/type_travelgroup.png'; + String path = 'travelgroup'; + for (final val in TYPES) { + if (type.contains(val)) { + path = val; + break; + } + } + return 'images/type_$path.png'; + } + + _title(SearchItem item) { + if (item == null) { + return null; + } + List spans = []; + spans.addAll(_keywordTextSpans(item.word, searchModel.keyword)); + spans.add(TextSpan( + text: ' ' + (item.districtname ?? '') + ' ' + (item.zonename ?? ''), + style: TextStyle(fontSize: 16, color: Colors.grey))); + return RichText(text: TextSpan(children: spans)); + } + + _subTitle(SearchItem item) { + return RichText( + text: TextSpan(children: [ + TextSpan( + text: item.price ?? '', + style: TextStyle(fontSize: 16, color: Colors.orange), + ), + TextSpan( + text: ' ' + (item.star ?? ''), + style: TextStyle(fontSize: 12, color: Colors.grey), + ) + ]), + ); + } + + _keywordTextSpans(String word, String keyword) { + List spans = []; + if (word == null || word.length == 0) return spans; + //搜索关键字高亮忽略大小写 + String wordL = word.toLowerCase(), keywordL = keyword.toLowerCase(); + List arr = wordL.split(keywordL); + TextStyle normalStyle = TextStyle(fontSize: 16, color: Colors.black87); + TextStyle keywordStyle = TextStyle(fontSize: 16, color: Colors.orange); + //'wordwoc'.split('w') -> [, ord, oc] @https://www.tutorialspoint.com/tpcg.php?p=wcpcUA + int preIndex = 0; + for (int i = 0; i < arr.length; i++) { + if (i != 0) { + //搜索关键字高亮忽略大小写 + preIndex = wordL.indexOf(keywordL, preIndex); + spans.add(TextSpan( + text: word.substring(preIndex, preIndex + keyword.length), + style: keywordStyle)); + } + String val = arr[i]; + if (val != null && val.length > 0) { + spans.add(TextSpan(text: val, style: normalStyle)); + } + } + return spans; + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/trip_app.dart b/FlutterHelper/flutter_helper/lib/trip/trip_app.dart new file mode 100644 index 00000000..06e44905 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/trip_app.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +import 'navigator/tab_navigator.dart'; + +class TripApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter之旅', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: TabNavigator(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_dao.dart b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_dao.dart new file mode 100644 index 00000000..eeeff539 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_dao.dart @@ -0,0 +1,44 @@ +import 'dart:convert'; + +import 'package:flutter_helper/trip/trvavel/travel_model.dart'; +import 'package:http/http.dart' as http; + +///旅拍页接口 + +var Params = { + "districtId": -1, + "groupChannelCode": "RX-OMF", + "type": null, + "lat": -180, + "lon": -180, + "locatedDistrictId": 0, + "pagePara": { + "pageIndex": 1, + "pageSize": 10, + "sortType": 9, + "sortDirection": 0 + }, + "imageCutType": 1, + "head": {'cid': "09031014111431397988"}, + "contentType": "json" +}; + +class TravelDao { + static Future fetch(String url, Map params, + String groupChannelCode, int pageIndex, int pageSize) async { + // 拼接参数 + Map paramsMap = params['pagePara']; + paramsMap['pageIndex'] = pageIndex; + paramsMap['pageSize'] = pageSize; + params['groupChannelCode'] = groupChannelCode; + // 请求网络 + final response = await http.post(Uri.parse(url), body: jsonEncode(params)); + if(response.statusCode == 200) { + Utf8Decoder utf8decoder = Utf8Decoder(); // 中文乱码 + var result = json.decode(utf8decoder.convert(response.bodyBytes)); + return TravelItemModel.fromJson(result); + } else { + throw Exception("Failed to load travel!!"); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_model.dart b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_model.dart new file mode 100644 index 00000000..1aca9ccc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_model.dart @@ -0,0 +1,425 @@ +///旅拍页模型 +class TravelItemModel { + int totalCount; + List resultList; + + TravelItemModel({this.totalCount, this.resultList}); + + TravelItemModel.fromJson(Map json) { + totalCount = json['totalCount']; + if (json['resultList'] != null) { + resultList = new List(); + json['resultList'].forEach((v) { + resultList.add(new TravelItem.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['totalCount'] = this.totalCount; + if (this.resultList != null) { + data['resultList'] = this.resultList.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class TravelItem { + int type; + Article article; + + TravelItem({this.type, this.article}); + + TravelItem.fromJson(Map json) { + type = json['type']; + article = + json['article'] != null ? new Article.fromJson(json['article']) : null; + } + + Map toJson() { + final Map data = new Map(); + data['type'] = this.type; + if (this.article != null) { + data['article'] = this.article.toJson(); + } + return data; + } +} + +class Article { + int articleId; + String articleType; + int productType; + int sourceType; + String articleTitle; + Author author; + List images; + bool hasVideo; + int readCount; + int likeCount; + int commentCount; + List urls; + List tags; + List topics; + List pois; + String publishTime; + String publishTimeDisplay; + String shootTime; + String shootTimeDisplay; + int level; + String distanceText; + bool isLike; + int imageCounts; + bool isCollected; + int collectCount; + int articleStatus; + String poiName; + + Article( + {this.articleId, + this.articleType, + this.productType, + this.sourceType, + this.articleTitle, + this.author, + this.images, + this.hasVideo, + this.readCount, + this.likeCount, + this.commentCount, + this.urls, + this.tags, + this.topics, + this.pois, + this.publishTime, + this.publishTimeDisplay, + this.shootTime, + this.shootTimeDisplay, + this.level, + this.distanceText, + this.isLike, + this.imageCounts, + this.isCollected, + this.collectCount, + this.articleStatus, + this.poiName}); + + Article.fromJson(Map json) { + articleId = json['articleId']; + articleType = json['articleType']; + productType = json['productType']; + sourceType = json['sourceType']; + articleTitle = json['articleTitle']; + author = + json['author'] != null ? new Author.fromJson(json['author']) : null; + if (json['images'] != null) { + images = new List(); + json['images'].forEach((v) { + images.add(new Images.fromJson(v)); + }); + } + hasVideo = json['hasVideo']; + readCount = json['readCount']; + likeCount = json['likeCount']; + commentCount = json['commentCount']; + if (json['urls'] != null) { + urls = new List(); + json['urls'].forEach((v) { + urls.add(new Urls.fromJson(v)); + }); + } + if (json['topics'] != null) { + topics = new List(); + json['topics'].forEach((v) { + topics.add(new Topics.fromJson(v)); + }); + } + if (json['pois'] != null) { + pois = new List(); + json['pois'].forEach((v) { + pois.add(new Pois.fromJson(v)); + }); + } + publishTime = json['publishTime']; + publishTimeDisplay = json['publishTimeDisplay']; + shootTime = json['shootTime']; + shootTimeDisplay = json['shootTimeDisplay']; + level = json['level']; + distanceText = json['distanceText']; + isLike = json['isLike']; + imageCounts = json['imageCounts']; + isCollected = json['isCollected']; + collectCount = json['collectCount']; + articleStatus = json['articleStatus']; + poiName = json['poiName']; + } + + Map toJson() { + final Map data = new Map(); + data['articleId'] = this.articleId; + data['articleType'] = this.articleType; + data['productType'] = this.productType; + data['sourceType'] = this.sourceType; + data['articleTitle'] = this.articleTitle; + if (this.author != null) { + data['author'] = this.author.toJson(); + } + if (this.images != null) { + data['images'] = this.images.map((v) => v.toJson()).toList(); + } + data['hasVideo'] = this.hasVideo; + data['readCount'] = this.readCount; + data['likeCount'] = this.likeCount; + data['commentCount'] = this.commentCount; + if (this.urls != null) { + data['urls'] = this.urls.map((v) => v.toJson()).toList(); + } + if (this.topics != null) { + data['topics'] = this.topics.map((v) => v.toJson()).toList(); + } + if (this.pois != null) { + data['pois'] = this.pois.map((v) => v.toJson()).toList(); + } + data['publishTime'] = this.publishTime; + data['publishTimeDisplay'] = this.publishTimeDisplay; + data['shootTime'] = this.shootTime; + data['shootTimeDisplay'] = this.shootTimeDisplay; + data['level'] = this.level; + data['distanceText'] = this.distanceText; + data['isLike'] = this.isLike; + data['imageCounts'] = this.imageCounts; + data['isCollected'] = this.isCollected; + data['collectCount'] = this.collectCount; + data['articleStatus'] = this.articleStatus; + data['poiName'] = this.poiName; + return data; + } +} + +class Author { + int authorId; + String nickName; + String clientAuth; + String jumpUrl; + CoverImage coverImage; + int identityType; + String tag; + + Author( + {this.authorId, + this.nickName, + this.clientAuth, + this.jumpUrl, + this.coverImage, + this.identityType, + this.tag}); + + Author.fromJson(Map json) { + authorId = json['authorId']; + nickName = json['nickName']; + clientAuth = json['clientAuth']; + jumpUrl = json['jumpUrl']; + coverImage = json['coverImage'] != null + ? new CoverImage.fromJson(json['coverImage']) + : null; + identityType = json['identityType']; + tag = json['tag']; + } + + Map toJson() { + final Map data = new Map(); + data['authorId'] = this.authorId; + data['nickName'] = this.nickName; + data['clientAuth'] = this.clientAuth; + data['jumpUrl'] = this.jumpUrl; + if (this.coverImage != null) { + data['coverImage'] = this.coverImage.toJson(); + } + data['identityType'] = this.identityType; + data['tag'] = this.tag; + return data; + } +} + +class CoverImage { + String dynamicUrl; + String originalUrl; + + CoverImage({this.dynamicUrl, this.originalUrl}); + + CoverImage.fromJson(Map json) { + dynamicUrl = json['dynamicUrl']; + originalUrl = json['originalUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['dynamicUrl'] = this.dynamicUrl; + data['originalUrl'] = this.originalUrl; + return data; + } +} + +class Images { + int imageId; + String dynamicUrl; + String originalUrl; + double width; + double height; + int mediaType; + bool isWaterMarked; + + Images( + {this.imageId, + this.dynamicUrl, + this.originalUrl, + this.width, + this.height, + this.mediaType, + this.isWaterMarked}); + + Images.fromJson(Map json) { + imageId = json['imageId']; + dynamicUrl = json['dynamicUrl']; + originalUrl = json['originalUrl']; + width = json['width']; + height = json['height']; + mediaType = json['mediaType']; + isWaterMarked = json['isWaterMarked']; + } + + Map toJson() { + final Map data = new Map(); + data['imageId'] = this.imageId; + data['dynamicUrl'] = this.dynamicUrl; + data['originalUrl'] = this.originalUrl; + data['width'] = this.width; + data['height'] = this.height; + data['mediaType'] = this.mediaType; + data['isWaterMarked'] = this.isWaterMarked; + return data; + } +} + +class Urls { + String version; + String appUrl; + String h5Url; + String wxUrl; + + Urls({this.version, this.appUrl, this.h5Url, this.wxUrl}); + + Urls.fromJson(Map json) { + version = json['version']; + appUrl = json['appUrl']; + h5Url = json['h5Url']; + wxUrl = json['wxUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['version'] = this.version; + data['appUrl'] = this.appUrl; + data['h5Url'] = this.h5Url; + data['wxUrl'] = this.wxUrl; + return data; + } +} + +class Topics { + int topicId; + String topicName; + int level; + + Topics({this.topicId, this.topicName, this.level}); + + Topics.fromJson(Map json) { + topicId = json['topicId']; + topicName = json['topicName']; + level = json['level']; + } + + Map toJson() { + final Map data = new Map(); + data['topicId'] = this.topicId; + data['topicName'] = this.topicName; + data['level'] = this.level; + return data; + } +} + +class Pois { + int poiType; + int poiId; + String poiName; + int businessId; + int districtId; + PoiExt poiExt; + int source; + int isMain; + bool isInChina; + String countryName; + + Pois( + {this.poiType, + this.poiId, + this.poiName, + this.businessId, + this.districtId, + this.poiExt, + this.source, + this.isMain, + this.isInChina, + this.countryName}); + + Pois.fromJson(Map json) { + poiType = json['poiType']; + poiId = json['poiId']; + poiName = json['poiName']; + businessId = json['businessId']; + districtId = json['districtId']; + poiExt = + json['poiExt'] != null ? new PoiExt.fromJson(json['poiExt']) : null; + source = json['source']; + isMain = json['isMain']; + isInChina = json['isInChina']; + countryName = json['countryName']; + } + + Map toJson() { + final Map data = new Map(); + data['poiType'] = this.poiType; + data['poiId'] = this.poiId; + data['poiName'] = this.poiName; + data['businessId'] = this.businessId; + data['districtId'] = this.districtId; + if (this.poiExt != null) { + data['poiExt'] = this.poiExt.toJson(); + } + data['source'] = this.source; + data['isMain'] = this.isMain; + data['isInChina'] = this.isInChina; + data['countryName'] = this.countryName; + return data; + } +} + +class PoiExt { + String h5Url; + String appUrl; + + PoiExt({this.h5Url, this.appUrl}); + + PoiExt.fromJson(Map json) { + h5Url = json['h5Url']; + appUrl = json['appUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['h5Url'] = this.h5Url; + data['appUrl'] = this.appUrl; + return data; + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_page.dart b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_page.dart new file mode 100644 index 00000000..310d3138 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_page.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/trvavel/travel_tab_dao.dart'; +import 'package:flutter_helper/trip/trvavel/travel_tab_model.dart'; +import 'package:flutter_helper/trip/trvavel/travel_tab_page.dart'; +import 'package:flutter_helper/utils/util_log.dart'; +import 'package:underline_indicator/underline_indicator.dart'; + +class TravelPage extends StatefulWidget { + @override + _TravelPageState createState() => _TravelPageState(); +} + +class _TravelPageState extends State with TickerProviderStateMixin { + TabController _controller; + List _tabs = []; + TravelTabModel _travelTabModel; + + @override + void initState() { + LogUtil.e("initState"); + _controller = TabController(length: 0, vsync: this); + // 获取数据 + TravelTabDao.fetch().then((model) { + _controller = TabController(length: model.tabs.length, vsync: this); + setState(() { + _tabs = model.tabs; + _travelTabModel = model; + }); + LogUtil.e("获取到数据 ${_tabs}"); + LogUtil.e("获取到数据 ${_travelTabModel}"); + }).catchError((e) { + print(e); + }); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + Container( + color: Colors.white, + padding: EdgeInsets.only(top: 30), + child: TabBar( + controller: _controller, + isScrollable: true, + labelColor: Colors.black, + labelPadding: EdgeInsets.fromLTRB(20, 0, 10, 5), + indicator: UnderlineIndicator( + strokeCap: StrokeCap.round, + borderSide: BorderSide( + color: Color(0xff2fcfbb), + width: 3, + ), + insets: EdgeInsets.only(bottom: 10), + ), + tabs: _tabs.map((e) => Tab(text: e.labelName)).toList(), + ), + ), + Flexible( + child: TabBarView( + controller: _controller, + children: _tabs.map((tab) => TravelTabPage( + travelUrl: _travelTabModel.url, + params: _travelTabModel.params, + groupChannelCode: tab.groupChannelCode, + )).toList(), + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_dao.dart b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_dao.dart new file mode 100644 index 00000000..629e7131 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_dao.dart @@ -0,0 +1,21 @@ +import 'dart:convert'; + +import 'package:flutter_helper/trip/trvavel/travel_tab_model.dart'; +import 'package:http/http.dart' as http; + +/// 旅拍类别接口 +class TravelTabDao { + static const _url = + 'http://www.devio.org/io/flutter_app/json/travel_page.json'; + + static Future fetch() async { + final response = await http.get(Uri.parse(_url)); + if (response.statusCode == 200) { + Utf8Decoder utf8decoder = Utf8Decoder(); + var result = json.decode(utf8decoder.convert(response.bodyBytes)); + return TravelTabModel.fromJson(result); + } else { + throw Exception('Failed to load travel_page.json'); + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_model.dart b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_model.dart new file mode 100644 index 00000000..b6dbc8e4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_model.dart @@ -0,0 +1,46 @@ +class TravelTabModel { + Map params; + String url; + List tabs; + + TravelTabModel({this.url, this.tabs}); + + TravelTabModel.fromJson(Map json) { + url = json['url']; + params = json['params']; + List __tabs = json['tabs']; + tabs = []; + __tabs?.forEach((v) { + tabs.add(TravelTab.fromJson(v)); + }); + } + + Map toJson() { + final Map data = new Map(); + data['url'] = this.url; + if (this.tabs != null) { + data['tabs'] = this.tabs.map((e) => e.toJson()).toList(); + } + return data; + } +} + +class TravelTab { + String labelName; + String groupChannelCode; + + + TravelTab({this.labelName, this.groupChannelCode}); + + TravelTab.fromJson(Map json) { + labelName = json['labelName']; + groupChannelCode = json['groupChannelCode']; + } + + Map toJson() { + final Map data = new Map(); + data['labelName'] = labelName; + data['groupChannelCode'] = groupChannelCode; + return data; + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_page.dart b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_page.dart new file mode 100644 index 00000000..71bb35c7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/trvavel/travel_tab_page.dart @@ -0,0 +1,266 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/trip/trvavel/travel_dao.dart'; +import 'package:flutter_helper/trip/trvavel/travel_model.dart'; +import 'package:flutter_helper/trip/utils.dart'; +import 'package:flutter_helper/trip/widget/LoadingContainer.dart'; +import 'package:flutter_helper/trip/widget/webview.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +const _TRAVEL_URL = + 'https://m.ctrip.com/restapi/soa2/16189/json/searchTripShootListForHomePageV2?_fxpcqlniredt=09031014111431397988&__gw_appid=99999999&__gw_ver=1.0&__gw_from=10650013707&__gw_platform=H5'; +const PAGE_SIZE = 10; + +class TravelTabPage extends StatefulWidget { + final String travelUrl; + final Map params; + final String groupChannelCode; + + const TravelTabPage( + {Key key, this.travelUrl, this.params, this.groupChannelCode}) + : super(key: key); + + @override + State createState() => _TravelTabPageState(); +} + +class _TravelTabPageState extends State + with AutomaticKeepAliveClientMixin { + List travelItems; + int pageIndex = 1; + bool _loading = true; + ScrollController _scrollController = ScrollController(); + + @override + void initState() { + _loadData(); + _scrollController.addListener(() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + _loadData(loadMore: true); + } + }); + super.initState(); + } + + Future _handleRefresh() async { + _loadData(); + return null; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Scaffold( + body: LoadingContainer( + isLoading: _loading, + child: RefreshIndicator( + onRefresh: _handleRefresh, + child: MediaQuery.removePadding( + context: context, + child: StaggeredGridView.countBuilder( + controller: _scrollController, + crossAxisCount: 4, + itemCount: travelItems?.length ?? 0, + itemBuilder: (context, index) => _TravelItem( + index: index, + item: travelItems[index], + ), + staggeredTileBuilder: (index) => StaggeredTile.fit(2), + ), + ), + ), + ), + ), + ), + ); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + void _loadData({bool loadMore = false}) { + if (loadMore) + pageIndex++; + else + pageIndex = 1; + + TravelDao.fetch(widget.travelUrl ?? _TRAVEL_URL, widget.params, + widget.groupChannelCode, pageIndex, PAGE_SIZE) + .then((model) { + _loading = false; + setState(() { + List items = _filterItems(model.resultList); + if (travelItems != null) { + travelItems.clear(); + travelItems.addAll(items); + } else { + travelItems = items; + } + }); + }).catchError((e) { + _loading = false; + print(e); + }); + } + + List _filterItems(List resultList) { + if (resultList == null) return []; + List filterItem = []; + resultList.forEach((item) { + if (item.article != null) filterItem.add(item); + }); + return filterItem; + } + + @override + bool get wantKeepAlive => true; +} + +class _TravelItem extends StatelessWidget { + final TravelItem item; + final int index; + + const _TravelItem({Key key, this.item, this.index}) : super(key: key); + + @override + Widget build(BuildContext context) => GestureDetector( + onTap: () { + if (item.article.urls != null && item.article.urls.length > 0) { + NavigatorUtil.push( + context, + WebView( + url: item.article.urls[0].h5Url, + title: '详情', + ), + ); + } + }, + child: Card( + child: PhysicalModel( + color: Colors.transparent, + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.circular(5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _itemImage(), + Container( + padding: EdgeInsets.all(4), + child: Text( + item.article.articleTitle, + maxLines: 2, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 14, color: Colors.black87), + ), + ), + _indexText(), + ], + ), + ), + ), + ); + + _itemImage() => Stack( + children: [ + Image.network(item.article.images[0]?.dynamicUrl), + Positioned( + bottom: 8, + left: 8, + child: Container( + padding: EdgeInsets.fromLTRB(5, 1, 5, 1), + decoration: BoxDecoration( + color: Colors.black54, + borderRadius: BorderRadius.circular(10), + ), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 3), + child: Icon( + Icons.location_on, + color: Colors.white, + size: 12, + ), + ), + LimitedBox( + maxWidth: 130, + child: Text( + _poiName(), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + ], + ), + ), + ), + ], + ); + + String _poiName() { + return item.article.pois == null || item.article.pois.length == 0 + ? '未知' + : item.article.pois[0]?.poiName ?? '未知'; + } + + _indexText() => Container( + padding: EdgeInsets.fromLTRB(6, 0, 6, 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + PhysicalModel( + color: Colors.transparent, + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.circular(12), + child: Image.network( + item.article.author?.coverImage?.dynamicUrl, + width: 24, + height: 24, + ), + ), + Container( + padding: EdgeInsets.all(5), + width: 90, + child: Text( + item.article.author?.nickName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 12), + ), + ), + ], + ), + Row( + children: [ + Icon( + Icons.thumb_up, + size: 14, + color: Colors.grey, + ), + LimitedBox( + maxWidth: 30, + child: Padding( + padding: EdgeInsets.only(left: 3), + child: Text( + // '11111111111', + item.article.likeCount.toString(), + style: TextStyle(fontSize: 10), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], + ), + ], + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/trip/utils.dart b/FlutterHelper/flutter_helper/lib/trip/utils.dart new file mode 100644 index 00000000..d7200bba --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/utils.dart @@ -0,0 +1,9 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class NavigatorUtil{ + /// 跳转到指定页面 + static push(BuildContext context, Widget page) { + Navigator.push(context, MaterialPageRoute(builder: (context)=>page)); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/trip/widget/LoadingContainer.dart b/FlutterHelper/flutter_helper/lib/trip/widget/LoadingContainer.dart new file mode 100644 index 00000000..d7a751ca --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/widget/LoadingContainer.dart @@ -0,0 +1,33 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 加载进度条 +class LoadingContainer extends StatelessWidget { + final Widget child; + final bool isLoading; + final bool cover; + + const LoadingContainer({ + Key key, + @required this.isLoading, + this.cover = false, + @required this.child, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return !cover + ? !isLoading + ? child + : _loadingView + : Stack( + children: [child, isLoading ? _loadingView : Container()], + ); + } + + Widget get _loadingView { + return Center( + child: CircularProgressIndicator(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/widget/search_bar.dart b/FlutterHelper/flutter_helper/lib/trip/widget/search_bar.dart new file mode 100644 index 00000000..c5a83fe6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/widget/search_bar.dart @@ -0,0 +1,220 @@ +import 'package:flutter/material.dart'; + +enum SearchBarType { home, normal, homeLight } + +class SearchBar extends StatefulWidget { + final bool enabled; + final bool hideLeft; + final SearchBarType searchBarType; + final String hint; + final String defaultText; + final void Function() leftButtonClick; + final void Function() rightButtonClick; + final void Function() speakClick; + final void Function() inputBoxClick; + final ValueChanged onChanged; + + const SearchBar( + {Key key, + this.enabled = true, + this.hideLeft, + this.searchBarType = SearchBarType.normal, + this.hint, + this.defaultText, + this.leftButtonClick, + this.rightButtonClick, + this.speakClick, + this.inputBoxClick, + this.onChanged}) + : super(key: key); + + @override + _SearchBarState createState() => _SearchBarState(); +} + +class _SearchBarState extends State { + bool showClear = false; + final TextEditingController _controller = TextEditingController(); + + @override + void initState() { + if (widget.defaultText != null) { + setState(() { + _controller.text = widget.defaultText; + }); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return widget.searchBarType == SearchBarType.normal + ? _genNormalSearch() + : _genHomeSearch(); + } + + _genNormalSearch() => Container( + child: Row( + children: [ + _wrapTap( + Container( + padding: EdgeInsets.fromLTRB(6, 5, 10, 5), + child: widget?.hideLeft ?? false + ? null + : Icon( + Icons.arrow_back_ios, + color: Colors.grey, + size: 26, + ), + ), + widget.leftButtonClick), + Expanded(child: _inputBox(), flex: 1), + _wrapTap( + Container( + padding: EdgeInsets.fromLTRB(10, 5, 10, 5), + child: Text( + '搜索', + style: TextStyle(color: Colors.blue, fontSize: 17), + ), + ), + widget.rightButtonClick), + ], + ), + ); + + _genHomeSearch() => Container( + child: Row( + children: [ + _wrapTap( + Container( + padding: EdgeInsets.fromLTRB(6, 5, 5, 5), + child: Row( + children: [ + Text( + '上海', + style: TextStyle(color: _homeFontColor(), fontSize: 14), + ), + Icon( + Icons.expand_more, + color: _homeFontColor(), + size: 22, + ), + ], + ), + ), + widget.leftButtonClick), + Expanded(child: _inputBox(), flex: 1), + _wrapTap( + Container( + padding: EdgeInsets.fromLTRB(10, 0, 10, 5), + child: Icon( + Icons.comment, + color: _homeFontColor(), + size: 26, + ), + ), + widget.rightButtonClick), + ], + ), + ); + + _inputBox() { + Color inputBoxColor = widget.searchBarType == SearchBarType.home + ? Colors.white + : Color(int.parse('0xffEDEDED')); + return Container( + height: 30, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + decoration: BoxDecoration( + color: inputBoxColor, + borderRadius: BorderRadius.circular( + widget.searchBarType == SearchBarType.normal ? 5 : 15, + ), + ), + child: Row( + children: [ + Icon( + Icons.search, + size: 20, + color: widget.searchBarType == SearchBarType.normal + ? Color(0xffA9A9A9) + : Colors.blue, + ), + Expanded( + flex: 1, + child: widget.searchBarType == SearchBarType.normal + ? TextField( + controller: _controller, + onChanged: _onChanged, + autofocus: true, + style: TextStyle( + fontSize: 18.0, + color: Colors.black, + fontWeight: FontWeight.w300, + ), + decoration: InputDecoration( + contentPadding: EdgeInsets.fromLTRB(5, 0, 5, 0), + border: InputBorder.none, + hintText: widget.hint ?? '', + hintStyle: TextStyle(fontSize: 15), + ), + ) + : _wrapTap( + Container( + child: Text( + widget.defaultText, + style: TextStyle( + fontSize: 13, + color: Colors.grey, + ), + ), + ), + widget.inputBoxClick, + ), + ), + !showClear + ? _wrapTap( + Icon( + Icons.mic, + size: 22, + color: widget.searchBarType == SearchBarType.normal + ? Colors.blue + : Colors.grey, + ), + widget.speakClick, + ) + : _wrapTap( + Icon( + Icons.clear, + size: 22, + color: Colors.grey, + ), + () { + setState(() { + _controller.clear(); + }); + _onChanged(''); + }, + ), + ], + ), + ); + } + + _wrapTap(Widget child, void Function() callback) { + return GestureDetector(onTap: callback, child: child); + } + + _onChanged(String text) { + setState(() { + showClear = text.length > 0; + }); + if (widget.onChanged != null) widget.onChanged(text); + } + + _homeFontColor() { + return widget.searchBarType == SearchBarType.homeLight + ? Colors.black54 + : Colors.white; + } +} diff --git a/FlutterHelper/flutter_helper/lib/trip/widget/webview.dart b/FlutterHelper/flutter_helper/lib/trip/widget/webview.dart new file mode 100644 index 00000000..46d256e9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/trip/widget/webview.dart @@ -0,0 +1,161 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; + +class WebView extends StatefulWidget { + String url; + final String statusBarColor; + final String title; + final bool hideAppBar; + final bool backForbid; + + WebView({ + this.url, + this.statusBarColor, + this.title, + this.hideAppBar, + this.backForbid = false, + }) { + if (url != null && url.contains('ctrip.com')) { + // fix 携程H5 Http://无法打开的问题 + url = url.replaceAll("http://", 'https://'); + } + } + + @override + _WebViewState createState() => _WebViewState(); +} + +class _WebViewState extends State { + final CATCH_URLS = [ + 'm.ctrip.com/', + 'm.ctrip.com/html5/', + 'm.ctrip.com/html5' + ]; + + final webviewReference = FlutterWebviewPlugin(); + StreamSubscription _onUrlChanged; + StreamSubscription _onStateChanged; + StreamSubscription _onHttpError; + bool exiting = false; + + @override + void initState() { + webviewReference.close(); + _onUrlChanged = webviewReference.onUrlChanged.listen((event) {}); + _onStateChanged = webviewReference.onStateChanged.listen((state) { + switch (state.type) { + case WebViewState.startLoad: + if (_isToMain(state.url) && !exiting) { + if (widget.backForbid) { + webviewReference.launch(widget.url); + } else { + Navigator.pop(context); + exiting = true; + } + } + break; + default: + break; + } + }); + _onHttpError = webviewReference.onHttpError.listen((event) { + print('$event'); + }); + super.initState(); + } + + _isToMain(String url) { + bool contain = false; + for (final value in CATCH_URLS) { + if (url?.endsWith(value) ?? false) { + contain = true; + break; + } + } + return contain; + } + + @override + void dispose() { + _onStateChanged.cancel(); + _onUrlChanged.cancel(); + _onHttpError.cancel(); + webviewReference.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + String statusBarColorStr = widget.statusBarColor ?? 'ffffff'; + Color backButtonColor; + if (statusBarColorStr == 'ffffff') { + backButtonColor = Colors.black; + } else { + backButtonColor = Colors.white; + } + + return Scaffold( + body: Column( + children: [ + _appBar( + Color(int.parse('0xff' + statusBarColorStr)), + backButtonColor, + ), + Expanded( + child: WebviewScaffold( + userAgent: 'null', ////防止携程H5页面重定向到打开携程APP ctrip://wireless/xxx的网址 + url: widget.url, + withZoom: true, + withLocalStorage: true, + hidden: true, + initialChild: Container( + color: Colors.white, + child: Center( + child: Text('Waiting...'), + ), + ), + ), + ) + ], + ), + ); + } + + _appBar(Color backgroundColor, Color backButtonColor) { + if (widget.hideAppBar ?? false) { + return Container(color: backgroundColor, height: 30); + } + return Container( + color: backgroundColor, + padding: EdgeInsets.fromLTRB(0, 40, 0, 10), + child: FractionallySizedBox( + widthFactor: 1, // 填充整个宽度 + child: Stack( + children: [ + GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + margin: EdgeInsets.only(left: 10), + child: Icon(Icons.close, color: backButtonColor, size: 26), + ), + ), + Positioned( + left: 0, + right: 0, + child: Center( + child: Text( + widget.title ?? '', + style: TextStyle(color: backButtonColor, fontSize: 20), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/demo_page.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/demo_page.dart new file mode 100644 index 00000000..b20a5210 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/demo_page.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class DemoPage extends StatelessWidget { + const DemoPage({ + Key key, + @required this.child, + }) : super(key: key); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Offline Demo'), + ), + body: child, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/flutter_offline.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/flutter_offline.dart new file mode 100644 index 00000000..ba26015a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/flutter_offline.dart @@ -0,0 +1,4 @@ +library flutter_offline; + +export 'package:connectivity/connectivity.dart' show ConnectivityResult; +export 'src/main.dart'; diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/src/main.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/src/main.dart new file mode 100644 index 00000000..f574121e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/src/main.dart @@ -0,0 +1,111 @@ +import 'dart:async'; + +import 'package:connectivity/connectivity.dart'; +import 'package:flutter/widgets.dart'; +import 'utils.dart'; +import 'package:wifi_info_flutter/wifi_info_flutter.dart'; + +const kOfflineDebounceDuration = Duration(seconds: 3); +typedef ValueWidgetBuilder = Widget Function(BuildContext context, T value, Widget child); + +class OfflineBuilder extends StatefulWidget { + factory OfflineBuilder({ + Key key, + @required ValueWidgetBuilder connectivityBuilder, + Duration debounceDuration = kOfflineDebounceDuration, + WidgetBuilder builder, + Widget child, + WidgetBuilder errorBuilder, + }) { + return OfflineBuilder.initialize( + key: key, + connectivityBuilder: connectivityBuilder, + connectivityService: Connectivity(), + wifiInfo: WifiInfo(), + debounceDuration: debounceDuration, + builder: builder, + errorBuilder: errorBuilder, + child: child, + ); + } + + @visibleForTesting + OfflineBuilder.initialize({ + Key key, + @required this.connectivityBuilder, + @required this.connectivityService, + @required this.wifiInfo, + this.debounceDuration = kOfflineDebounceDuration, + this.builder, + this.child, + this.errorBuilder, + }) : assert(!(builder is WidgetBuilder && child is Widget) && !(builder == null && child == null), + 'You should specify either a builder or a child'), + super(key: key); + + /// Override connectivity service used for testing + final Connectivity connectivityService; + + final WifiInfo wifiInfo; + + /// Debounce duration from epileptic network situations + final Duration debounceDuration; + + /// Used for building the Offline and/or Online UI + final ValueWidgetBuilder connectivityBuilder; + + /// Used for building the child widget + final WidgetBuilder builder; + + /// The widget below this widget in the tree. + final Widget child; + + /// Used for building the error widget incase of any platform errors + final WidgetBuilder errorBuilder; + + @override + OfflineBuilderState createState() => OfflineBuilderState(); +} + +class OfflineBuilderState extends State { + Stream _connectivityStream; + + @override + void initState() { + super.initState(); + + _connectivityStream = Stream.fromFuture(widget.connectivityService.checkConnectivity()) + .asyncExpand((data) => widget.connectivityService.onConnectivityChanged.transform(startsWith(data))) + .transform(debounce(widget.debounceDuration)); + } + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: _connectivityStream, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (!snapshot.hasData && !snapshot.hasError) { + return const SizedBox(); + } + + if (snapshot.hasError) { + if (widget.errorBuilder != null) { + return widget.errorBuilder(context); + } + throw OfflineBuilderError(snapshot.error); + } + + return widget.connectivityBuilder(context, snapshot.data, widget.child ?? widget.builder(context)); + }, + ); + } +} + +class OfflineBuilderError extends Error { + OfflineBuilderError(this.error); + + final Object error; + + @override + String toString() => error.toString(); +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/src/utils.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/src/utils.dart new file mode 100644 index 00000000..a66d7ae3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/lib/src/utils.dart @@ -0,0 +1,57 @@ +import 'dart:async'; + +import 'package:connectivity/connectivity.dart'; + +StreamTransformer debounce( + Duration debounceDuration, +) { + var _seenFirstData = false; + Timer _debounceTimer; + + return StreamTransformer.fromHandlers( + handleData: (ConnectivityResult data, EventSink sink) { + if (_seenFirstData) { + _debounceTimer?.cancel(); + _debounceTimer = Timer(debounceDuration, () => sink.add(data)); + } else { + sink.add(data); + _seenFirstData = true; + } + }, + handleDone: (EventSink sink) { + _debounceTimer?.cancel(); + sink.close(); + }, + ); +} + +StreamTransformer startsWith( + ConnectivityResult data, +) { + return StreamTransformer( + ( + Stream input, + bool cancelOnError, + ) { + StreamController controller; + StreamSubscription subscription; + + controller = StreamController( + sync: true, + onListen: () => controller?.add(data), + onPause: ([Future resumeSignal]) => subscription.pause(resumeSignal), + onResume: () => subscription.resume(), + onCancel: () => subscription.cancel(), + ); + + subscription = input.listen( + controller.add, + onError: controller.addError, + onDone: controller.close, + cancelOnError: cancelOnError, + ); + + return controller.stream.listen(null); + }, + ); +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/main.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/main.dart new file mode 100644 index 00000000..a048d229 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/main.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; + +import './demo_page.dart'; +import './widgets/demo_1.dart'; +import './widgets/demo_2.dart'; +import './widgets/demo_3.dart'; + +void main() => runApp(FlutterOfflineApp()); + +class FlutterOfflineApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Offline Demo', + theme: ThemeData.dark(), + home: Builder( + builder: (BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () { + navigate(context, Demo1()); + }, + child: Text('Demo 1'), + ), + ElevatedButton( + onPressed: () { + navigate(context, Demo2()); + }, + child: Text('Demo 2'), + ), + ElevatedButton( + onPressed: () { + navigate(context, Demo3()); + }, + child: Text('Demo 3'), + ), + ], + ); + }, + ), + ); + } + + void navigate(BuildContext context, Widget widget) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) => DemoPage(child: widget), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_1.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_1.dart new file mode 100644 index 00000000..83df6b86 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_1.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_offline/flutter_offline.dart'; + +class Demo1 extends StatelessWidget { + @override + Widget build(BuildContext context) { + return OfflineBuilder( + connectivityBuilder: ( + BuildContext context, + ConnectivityResult connectivity, + Widget child, + ) { + final connected = connectivity != ConnectivityResult.none; + return Stack( + fit: StackFit.expand, + children: [ + child, + Positioned( + height: 32.0, + left: 0.0, + right: 0.0, + child: AnimatedContainer( + duration: const Duration(milliseconds: 350), + color: connected ? Color(0xFF00EE44) : Color(0xFFEE4400), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 350), + child: connected + ? Text('ONLINE') + : Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('OFFLINE'), + SizedBox(width: 8.0), + SizedBox( + width: 12.0, + height: 12.0, + child: CircularProgressIndicator( + strokeWidth: 2.0, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ], + ), + ), + ), + ), + ], + ); + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'There are no bottons to push :)', + ), + Text( + 'Just turn off your internet.', + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_2.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_2.dart new file mode 100644 index 00000000..1a043d43 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_2.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_offline/flutter_offline.dart'; + +class Demo2 extends StatelessWidget { + @override + Widget build(BuildContext context) { + return OfflineBuilder( + connectivityBuilder: ( + BuildContext context, + ConnectivityResult connectivity, + Widget child, + ) { + if (connectivity == ConnectivityResult.none) { + return Container( + color: Colors.white, + child: Center( + child: Text( + 'Oops, \n\nNow we are Offline!', + style: TextStyle(color: Colors.black), + ), + ), + ); + } else { + return child; + } + }, + builder: (BuildContext context) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'There are no bottons to push :)', + ), + Text( + 'Just turn off your internet.', + ), + ], + ), + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_3.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_3.dart new file mode 100644 index 00000000..3f910b8a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_offline/widgets/demo_3.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_offline/flutter_offline.dart'; + + +class Demo3 extends StatelessWidget { + @override + Widget build(BuildContext context) { + return OfflineBuilder( + debounceDuration: Duration.zero, + connectivityBuilder: ( + BuildContext context, + ConnectivityResult connectivity, + Widget child, + ) { + if (connectivity == ConnectivityResult.none) { + return Container( + color: Colors.white70, + child: Center( + child: Text( + 'Oops, \n\nWe experienced a Delayed Offline!', + style: TextStyle(color: Colors.black), + ), + ), + ); + } + return child; + }, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'There are no bottons to push :)', + ), + Text( + 'Just turn off your internet.', + ), + Text( + 'This one has a bit of a delay.', + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/detailscreen.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/detailscreen.dart new file mode 100644 index 00000000..fcdd1394 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/detailscreen.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; + +import 'lib/showcaseview.dart'; + +class Detail extends StatefulWidget { + @override + _DetailState createState() => _DetailState(); +} + +class _DetailState extends State { + final GlobalKey _one = GlobalKey(); + BuildContext myContext; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback( + (_) => Future.delayed(Duration(milliseconds: 200), () { + ShowCaseWidget.of(myContext).startShowCase([_one]); + })); + } + + @override + Widget build(BuildContext context) { + return ShowCaseWidget( + builder: Builder( + builder: (context) { + myContext = context; + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.transparent, + elevation: 0, + leading: IconButton( + icon: Icon( + Icons.arrow_back, + color: Colors.black, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: ListView( + children: [ + Showcase( + key: _one, + title: 'Title', + description: 'Desc', + child: InkWell( + onTap: () {}, + child: Text( + 'Flutter Notification', + style: TextStyle( + fontSize: 25, fontWeight: FontWeight.w600), + ), + ), + ), + SizedBox( + height: 16, + ), + Text( + 'Hi, you have new Notification from flutter group, open slack and check it out', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500), + ), + SizedBox( + height: 16, + ), + RichText( + text: TextSpan( + style: TextStyle( + fontWeight: FontWeight.w400, color: Colors.black), + children: [ + TextSpan(text: 'Hi team,\n\n'), + TextSpan( + text: + 'As some of you know, we’re moving to Slack for our internal team communications. Slack is a messaging app where we can talk, share files, and work together. It also connects with tools we already use, like [add your examples here], plus 900+ other apps.\n\n'), + TextSpan( + text: 'Why are we moving to Slack?\n\n', + style: TextStyle( + fontWeight: FontWeight.w600, + color: Colors.black)), + TextSpan( + text: + 'We want to use the best communication tools to make our lives easier and be more productive. Having everything in one place will help us work together better and faster, rather than jumping around between emails, IMs, texts and a bunch of other programs. Everything you share in Slack is automatically indexed and archived, creating a searchable archive of all our work.'), + ], + ), + ), + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/showcaseview.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/showcaseview.dart new file mode 100644 index 00000000..dab0a06a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/showcaseview.dart @@ -0,0 +1,31 @@ +/* + * Copyright © 2020, Simform Solutions + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +library showcaseview; + +export 'src/showcase.dart'; +export 'src/showcase_widget.dart'; diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/custom_paint.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/custom_paint.dart new file mode 100644 index 00000000..cd9fda6b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/custom_paint.dart @@ -0,0 +1,58 @@ +/* + * Copyright © 2020, Simform Solutions + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import 'package:flutter/material.dart'; + +class ShapePainter extends CustomPainter { + Rect rect; + final ShapeBorder shapeBorder; + final Color color; + final double opacity; + + ShapePainter({ + @required this.rect, + this.color, + this.shapeBorder, + this.opacity, + }); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint(); + paint.color = color.withOpacity(opacity); + final outer = + RRect.fromLTRBR(0, 0, size.width, size.height, Radius.circular(0)); + + final radius = shapeBorder == CircleBorder() ? 50.0 : 3.0; + + final inner = RRect.fromRectAndRadius(rect, Radius.circular(radius)); + canvas.drawDRRect(outer, inner, paint); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => false; +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/get_position.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/get_position.dart new file mode 100644 index 00000000..239393e6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/get_position.dart @@ -0,0 +1,103 @@ +/* + * Copyright © 2020, Simform Solutions + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import 'package:flutter/material.dart'; + +class GetPosition { + final GlobalKey key; + final EdgeInsets padding; + final double screenWidth; + final double screenHeight; + + GetPosition( + {this.key, + this.padding = EdgeInsets.zero, + this.screenWidth, + this.screenHeight}); + + Rect getRect() { + final box = key.currentContext.findRenderObject() as RenderBox; + + final topLeft = box.size.topLeft(box.localToGlobal(const Offset(0.0, 0.0))); + final bottomRight = + box.size.bottomRight(box.localToGlobal(const Offset(0.0, 0.0))); + + final rect = Rect.fromLTRB( + topLeft.dx - padding.left < 0 ? 0 : topLeft.dx - padding.left, + topLeft.dy - padding.top < 0 ? 0 : topLeft.dy - padding.top, + bottomRight.dx + padding.right > screenWidth + ? screenWidth + : bottomRight.dx + padding.right, + bottomRight.dy + padding.bottom > screenHeight + ? screenHeight + : bottomRight.dy + padding.bottom, + ); + return rect; + } + + ///Get the bottom position of the widget + double getBottom() { + final box = key.currentContext.findRenderObject() as RenderBox; + final bottomRight = + box.size.bottomRight(box.localToGlobal(const Offset(0.0, 0.0))); + return bottomRight.dy + padding.bottom; + } + + ///Get the top position of the widget + double getTop() { + final box = key.currentContext.findRenderObject() as RenderBox; + final topLeft = box.size.topLeft(box.localToGlobal(const Offset(0.0, 0.0))); + return topLeft.dy - padding.top; + } + + ///Get the left position of the widget + double getLeft() { + final box = key.currentContext.findRenderObject() as RenderBox; + final topLeft = box.size.topLeft(box.localToGlobal(const Offset(0.0, 0.0))); + return topLeft.dx - padding.left; + } + + ///Get the right position of the widget + double getRight() { + final box = key.currentContext.findRenderObject() as RenderBox; + final bottomRight = + box.size.bottomRight(box.localToGlobal(const Offset(0.0, 0.0))); + return bottomRight.dx + padding.right; + } + + double getHeight() { + return getBottom() - getTop(); + } + + double getWidth() { + return getRight() - getLeft(); + } + + double getCenter() { + return (getLeft() + getRight()) / 2; + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/layout_overlays.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/layout_overlays.dart new file mode 100644 index 00000000..a84b5219 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/layout_overlays.dart @@ -0,0 +1,198 @@ +/* + * Copyright © 2020, Simform Solutions + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import 'package:flutter/material.dart'; +import 'showcase_widget.dart'; + +/// Displays an overlay Widget anchored directly above the center of this +/// [AnchoredOverlay]. +/// +/// The overlay Widget is created by invoking the provided [overlayBuilder]. +/// +/// The [anchor] position is provided to the [overlayBuilder], but the builder +/// does not have to respect it. In other words, the [overlayBuilder] can +/// interpret the meaning of "anchor" however it wants - the overlay will not +/// be forced to be centered about the [anchor]. +/// +/// The overlay built by this [AnchoredOverlay] can be conditionally shown +/// and hidden by settings the [showOverlay] property to true or false. +/// +/// The [overlayBuilder] is invoked every time this Widget is rebuilt. +/// +class AnchoredOverlay extends StatelessWidget { + final bool showOverlay; + final Widget Function(BuildContext, Rect anchorBounds, Offset anchor) + overlayBuilder; + final Widget child; + + AnchoredOverlay({ + Key key, + this.showOverlay = false, + this.overlayBuilder, + this.child, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return OverlayBuilder( + showOverlay: showOverlay, + overlayBuilder: (overlayContext) { + // To calculate the "anchor" point we grab the render box of + // our parent Container and then we find the center of that box. + final box = context.findRenderObject() as RenderBox; + final topLeft = + box.size.topLeft(box.localToGlobal(const Offset(0.0, 0.0))); + final bottomRight = + box.size.bottomRight(box.localToGlobal(const Offset(0.0, 0.0))); + final anchorBounds = Rect.fromLTRB( + topLeft.dx, + topLeft.dy, + bottomRight.dx, + bottomRight.dy, + ); + final anchorCenter = box.size.center(topLeft); + return overlayBuilder(overlayContext, anchorBounds, anchorCenter); + }, + child: child, + ); + }, + ); + } +} + +/// Displays an overlay Widget as constructed by the given [overlayBuilder]. +/// +/// The overlay built by the [overlayBuilder] can be conditionally shown and +/// hidden by settings the [showOverlay] property to true or false. +/// +/// The [overlayBuilder] is invoked every time this Widget is rebuilt. +/// +/// Implementation note: the reason we rebuild the overlay every time our state +/// changes is because there doesn't seem to be any better way to invalidate the +/// overlay itself than to invalidate this Widget. Remember, overlay Widgets +/// exist in [OverlayEntry]s which are inaccessible to outside Widgets. But if +/// a better approach is found then feel free to use it. +class OverlayBuilder extends StatefulWidget { + final bool showOverlay; + final Widget Function(BuildContext) overlayBuilder; + final Widget child; + + OverlayBuilder({ + Key key, + this.showOverlay = false, + this.overlayBuilder, + this.child, + }) : super(key: key); + + @override + _OverlayBuilderState createState() => _OverlayBuilderState(); +} + +class _OverlayBuilderState extends State { + OverlayEntry _overlayEntry; + + @override + void initState() { + super.initState(); + + if (widget.showOverlay) { + WidgetsBinding.instance.addPostFrameCallback((_) => showOverlay()); + } + } + + @override + void didUpdateWidget(OverlayBuilder oldWidget) { + super.didUpdateWidget(oldWidget); + WidgetsBinding.instance + .addPostFrameCallback((_) => syncWidgetAndOverlay()); + } + + @override + void reassemble() { + super.reassemble(); + WidgetsBinding.instance + .addPostFrameCallback((_) => syncWidgetAndOverlay()); + } + + @override + void dispose() { + if (isShowingOverlay()) { + hideOverlay(); + } + + super.dispose(); + } + + bool isShowingOverlay() => _overlayEntry != null; + + void showOverlay() { + if (_overlayEntry == null) { + // Create the overlay. + _overlayEntry = OverlayEntry( + builder: widget.overlayBuilder, + ); + addToOverlay(_overlayEntry); + } else { + // Rebuild overlay. + buildOverlay(); + } + } + + void addToOverlay(OverlayEntry overlayEntry) async { + Overlay.of(ShowCaseWidget.of(context)?.context ?? context) + .insert(overlayEntry); + } + + void hideOverlay() { + if (_overlayEntry != null) { + _overlayEntry.remove(); + _overlayEntry = null; + } + } + + void syncWidgetAndOverlay() { + if (isShowingOverlay() && !widget.showOverlay) { + hideOverlay(); + } else if (!isShowingOverlay() && widget.showOverlay) { + showOverlay(); + } + } + + void buildOverlay() async { + WidgetsBinding.instance + .addPostFrameCallback((_) => _overlayEntry?.markNeedsBuild()); + } + + @override + Widget build(BuildContext context) { + buildOverlay(); + + return widget.child; + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/measure_size.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/measure_size.dart new file mode 100644 index 00000000..4ea42453 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/measure_size.dart @@ -0,0 +1,69 @@ +/* + * Copyright © 2020, Simform Solutions + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +typedef OnWidgetSizeChange = void Function(Size size); + +class MeasureSize extends StatefulWidget { + final Widget child; + final OnWidgetSizeChange onSizeChange; + + MeasureSize({ + @required this.onSizeChange, + @required this.child, + }); + + @override + _MeasureSizeState createState() => _MeasureSizeState(); +} + +class _MeasureSizeState extends State { + @override + Widget build(BuildContext context) { + SchedulerBinding.instance.addPostFrameCallback(postFrameCallback); + return Container( + key: widgetKey, + child: widget.child, + ); + } + + GlobalKey widgetKey = GlobalKey(); + Size oldSize; + + void postFrameCallback(Duration timestamp) { + var context = widgetKey.currentContext; + if (context == null) return; + + var newSize = context.size; + if (oldSize == newSize) return; + + oldSize = newSize; + widget.onSizeChange(newSize); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/showcase.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/showcase.dart new file mode 100644 index 00000000..93d0b56f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/showcase.dart @@ -0,0 +1,346 @@ +/* + * Copyright © 2020, Simform Solutions + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +import 'custom_paint.dart'; +import 'get_position.dart'; +import 'layout_overlays.dart'; +import 'showcase_widget.dart'; +import 'tooltip_widget.dart'; + +class Showcase extends StatefulWidget { + @override + final GlobalKey key; + + final Widget child; + final String title; + final String description; + final ShapeBorder shapeBorder; + final TextStyle titleTextStyle; + final TextStyle descTextStyle; + final EdgeInsets contentPadding; + final Color overlayColor; + final double overlayOpacity; + final Widget container; + final Color showcaseBackgroundColor; + final Color textColor; + final bool showArrow; + final double height; + final double width; + final Duration animationDuration; + final VoidCallback onToolTipClick; + final VoidCallback onTargetClick; + final bool disposeOnTap; + final bool disableAnimation; + final EdgeInsets overlayPadding; + + const Showcase( + {@required this.key, + @required this.child, + this.title, + @required this.description, + this.shapeBorder, + this.overlayColor = Colors.black, + this.overlayOpacity = 0.75, + this.titleTextStyle, + this.descTextStyle, + this.showcaseBackgroundColor = Colors.white, + this.textColor = Colors.black, + this.showArrow = true, + this.onTargetClick, + this.disposeOnTap, + this.animationDuration = const Duration(milliseconds: 2000), + this.disableAnimation = false, + this.contentPadding = + const EdgeInsets.symmetric(vertical: 8, horizontal: 8), + this.onToolTipClick, + this.overlayPadding = EdgeInsets.zero}) + : height = null, + width = null, + container = null, + assert(overlayOpacity >= 0.0 && overlayOpacity <= 1.0, + "overlay opacity should be >= 0.0 and <= 1.0."), + assert( + onTargetClick == null + ? true + : (disposeOnTap == null ? false : true), + "disposeOnTap is required if you're using onTargetClick"), + assert( + disposeOnTap == null + ? true + : (onTargetClick == null ? false : true), + "onTargetClick is required if you're using disposeOnTap"); + + const Showcase.withWidget({ + this.key, + @required this.child, + @required this.container, + @required this.height, + @required this.width, + this.title, + this.description, + this.shapeBorder, + this.overlayColor = Colors.black, + this.overlayOpacity = 0.75, + this.titleTextStyle, + this.descTextStyle, + this.showcaseBackgroundColor = Colors.white, + this.textColor = Colors.black, + this.onTargetClick, + this.disposeOnTap, + this.animationDuration = const Duration(milliseconds: 2000), + this.disableAnimation = false, + this.contentPadding = const EdgeInsets.symmetric(vertical: 8), + this.overlayPadding = EdgeInsets.zero, + }) : showArrow = false, + onToolTipClick = null, + assert(overlayOpacity >= 0.0 && overlayOpacity <= 1.0, + "overlay opacity should be >= 0.0 and <= 1.0."); + + @override + _ShowcaseState createState() => _ShowcaseState(); +} + +class _ShowcaseState extends State with TickerProviderStateMixin { + bool _showShowCase = false; + Animation _slideAnimation; + AnimationController _slideAnimationController; + Timer timer; + GetPosition position; + + @override + void initState() { + super.initState(); + + _slideAnimationController = AnimationController( + duration: widget.animationDuration, + vsync: this, + )..addStatusListener((status) { + if (status == AnimationStatus.completed) { + _slideAnimationController.reverse(); + } + if (_slideAnimationController.isDismissed) { + if (!widget.disableAnimation) { + _slideAnimationController.forward(); + } + } + }); + + _slideAnimation = CurvedAnimation( + parent: _slideAnimationController, + curve: Curves.easeInOut, + ); + } + + @override + void dispose() { + _slideAnimationController.dispose(); + super.dispose(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + position ??= GetPosition( + key: widget.key, + padding: widget.overlayPadding, + screenWidth: MediaQuery.of(context).size.width, + screenHeight: MediaQuery.of(context).size.height, + ); + showOverlay(); + } + + /// + /// show overlay if there is any target widget + /// + void showOverlay() { + final activeStep = ShowCaseWidget.activeTargetWidget(context); + setState(() { + _showShowCase = activeStep == widget.key; + }); + + if (activeStep == widget.key) { + _slideAnimationController.forward(); + if (ShowCaseWidget.of(context).autoPlay) { + timer = Timer( + Duration( + seconds: ShowCaseWidget.of(context).autoPlayDelay.inSeconds), + _nextIfAny); + } + } + } + + @override + Widget build(BuildContext context) { + return AnchoredOverlay( + overlayBuilder: (context, rectBound, offset) { + final size = MediaQuery.of(context).size; + position = GetPosition( + key: widget.key, + padding: widget.overlayPadding, + screenWidth: size.width, + screenHeight: size.height, + ); + return buildOverlayOnTarget(offset, rectBound.size, rectBound, size); + }, + showOverlay: true, + child: widget.child, + ); + } + + void _nextIfAny() { + if (timer != null && timer.isActive) { + if (ShowCaseWidget.of(context).autoPlayLockEnable) { + return; + } + timer.cancel(); + } else if (timer != null && !timer.isActive) { + timer = null; + } + ShowCaseWidget.of(context).completed(widget.key); + if (!widget.disableAnimation) { + _slideAnimationController.forward(); + } + } + + void _getOnTargetTap() { + if (widget.disposeOnTap == true) { + ShowCaseWidget.of(context).dismiss(); + widget.onTargetClick(); + } else { + (widget.onTargetClick ?? _nextIfAny).call(); + } + } + + void _getOnTooltipTap() { + if (widget.disposeOnTap == true) { + ShowCaseWidget.of(context).dismiss(); + } + widget.onToolTipClick?.call(); + } + + Widget buildOverlayOnTarget( + Offset offset, + Size size, + Rect rectBound, + Size screenSize, + ) => + Visibility( + visible: _showShowCase, + maintainAnimation: true, + maintainState: true, + child: Stack( + children: [ + GestureDetector( + onTap: _nextIfAny, + child: Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + child: CustomPaint( + painter: ShapePainter( + opacity: widget.overlayOpacity, + rect: position.getRect(), + shapeBorder: widget.shapeBorder, + color: widget.overlayColor), + ), + ), + ), + _TargetWidget( + offset: offset, + size: size, + onTap: _getOnTargetTap, + shapeBorder: widget.shapeBorder, + ), + ToolTipWidget( + position: position, + offset: offset, + screenSize: screenSize, + title: widget.title, + description: widget.description, + animationOffset: _slideAnimation, + titleTextStyle: widget.titleTextStyle, + descTextStyle: widget.descTextStyle, + container: widget.container, + tooltipColor: widget.showcaseBackgroundColor, + textColor: widget.textColor, + showArrow: widget.showArrow, + contentHeight: widget.height, + contentWidth: widget.width, + onTooltipTap: _getOnTooltipTap, + contentPadding: widget.contentPadding, + ), + ], + ), + ); +} + +class _TargetWidget extends StatelessWidget { + final Offset offset; + final Size size; + final Animation widthAnimation; + final VoidCallback onTap; + final ShapeBorder shapeBorder; + + _TargetWidget({ + Key key, + @required this.offset, + this.size, + this.widthAnimation, + this.onTap, + this.shapeBorder, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Positioned( + top: offset.dy, + left: offset.dx, + child: FractionalTranslation( + translation: const Offset(-0.5, -0.5), + child: GestureDetector( + onTap: onTap, + child: Container( + height: size.height + 16, + width: size.width + 16, + decoration: ShapeDecoration( + shape: shapeBorder ?? + RoundedRectangleBorder( + borderRadius: const BorderRadius.all( + Radius.circular(8), + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/showcase_widget.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/showcase_widget.dart new file mode 100644 index 00000000..af4139d3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/showcase_widget.dart @@ -0,0 +1,147 @@ +/* + * Copyright © 2020, Simform Solutions + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import 'package:flutter/material.dart'; + +class ShowCaseWidget extends StatefulWidget { + final Builder builder; + final VoidCallback onFinish; + final Function(int, GlobalKey) onStart; + final Function(int, GlobalKey) onComplete; + final bool autoPlay; + final Duration autoPlayDelay; + final bool autoPlayLockEnable; + + const ShowCaseWidget({ + @required this.builder, + this.onFinish, + this.onStart, + this.onComplete, + this.autoPlay = false, + this.autoPlayDelay = const Duration(milliseconds: 2000), + this.autoPlayLockEnable = false, + }); + + static GlobalKey activeTargetWidget(BuildContext context) { + return context + .dependOnInheritedWidgetOfExactType<_InheritedShowCaseView>() + .activeWidgetIds; + } + + static ShowCaseWidgetState of(BuildContext context) { + final state = context.findAncestorStateOfType(); + if (state != null) { + return context.findAncestorStateOfType(); + } else { + throw Exception('Please provide ShowCaseView context'); + } + } + + @override + ShowCaseWidgetState createState() => ShowCaseWidgetState(); +} + +class ShowCaseWidgetState extends State { + List ids; + int activeWidgetId; + bool autoPlay; + Duration autoPlayDelay; + bool autoPlayLockEnable; + + @override + void initState() { + super.initState(); + autoPlayDelay = widget.autoPlayDelay; + autoPlay = widget.autoPlay; + autoPlayLockEnable = widget.autoPlayLockEnable; + } + + void startShowCase(List widgetIds) { + setState(() { + ids = widgetIds; + activeWidgetId = 0; + _onStart(); + }); + } + + void completed(GlobalKey id) { + if (ids != null && ids[activeWidgetId] == id) { + setState(() { + _onComplete(); + activeWidgetId = activeWidgetId + 1; + _onStart(); + + if (activeWidgetId >= ids.length) { + _cleanupAfterSteps(); + if (widget.onFinish != null) { + widget.onFinish(); + } + } + }); + } + } + + void dismiss() { + setState(_cleanupAfterSteps); + } + + void _onStart() { + if (activeWidgetId < ids.length) { + widget.onStart?.call(activeWidgetId, ids[activeWidgetId]); + } + } + + void _onComplete() { + widget.onComplete?.call(activeWidgetId, ids[activeWidgetId]); + } + + void _cleanupAfterSteps() { + ids = null; + activeWidgetId = null; + } + + @override + Widget build(BuildContext context) { + return _InheritedShowCaseView( + child: widget.builder, + activeWidgetIds: ids?.elementAt(activeWidgetId), + ); + } +} + +class _InheritedShowCaseView extends InheritedWidget { + final GlobalKey activeWidgetIds; + + _InheritedShowCaseView({ + @required this.activeWidgetIds, + @required Widget child, + }) : super(child: child); + + @override + bool updateShouldNotify(_InheritedShowCaseView oldWidget) => + oldWidget.activeWidgetIds != activeWidgetIds; +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/tooltip_widget.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/tooltip_widget.dart new file mode 100644 index 00000000..484df5cd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/lib/src/tooltip_widget.dart @@ -0,0 +1,357 @@ +/* + * Copyright © 2020, Simform Solutions + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import 'dart:math'; + +import 'package:flutter/material.dart'; + +import 'get_position.dart'; +import 'measure_size.dart'; + +class ToolTipWidget extends StatefulWidget { + final GetPosition position; + final Offset offset; + final Size screenSize; + final String title; + final String description; + final Animation animationOffset; + final TextStyle titleTextStyle; + final TextStyle descTextStyle; + final Widget container; + final Color tooltipColor; + final Color textColor; + final bool showArrow; + final double contentHeight; + final double contentWidth; + static bool isArrowUp; + final VoidCallback onTooltipTap; + final EdgeInsets contentPadding; + + ToolTipWidget( + {this.position, + this.offset, + this.screenSize, + this.title, + this.description, + this.animationOffset, + this.titleTextStyle, + this.descTextStyle, + this.container, + this.tooltipColor, + this.textColor, + this.showArrow, + this.contentHeight, + this.contentWidth, + this.onTooltipTap, + this.contentPadding = const EdgeInsets.symmetric(vertical: 8)}); + + @override + _ToolTipWidgetState createState() => _ToolTipWidgetState(); +} + +class _ToolTipWidgetState extends State { + Offset position; + + bool isCloseToTopOrBottom(Offset position) { + var height = 120.0; + height = widget.contentHeight ?? height; + return (widget.screenSize.height - position.dy) <= height; + } + + String findPositionForContent(Offset position) { + if (isCloseToTopOrBottom(position)) { + return 'ABOVE'; + } else { + return 'BELOW'; + } + } + + double _getTooltipWidth() { + final titleStyle = widget.titleTextStyle ?? + Theme.of(context) + .textTheme + .headline6 + .merge(TextStyle(color: widget.textColor)); + final descriptionStyle = widget.descTextStyle ?? + Theme.of(context) + .textTheme + .subtitle2 + .merge(TextStyle(color: widget.textColor)); + final titleLength = widget.title == null + ? 0 + : _textSize(widget.title, titleStyle).width + + widget.contentPadding.right + + widget.contentPadding.left; + final descriptionLength = + _textSize(widget.description, descriptionStyle).width + + widget.contentPadding.right + + widget.contentPadding.left; + var maxTextWidth = max(titleLength, descriptionLength); + if (maxTextWidth > widget.screenSize.width - 20) { + return widget.screenSize.width - 20; + } else { + return maxTextWidth + 15; + } + } + + bool _isLeft() { + final screenWidth = widget.screenSize.width / 3; + return !(screenWidth <= widget.position.getCenter()); + } + + bool _isRight() { + final screenWidth = widget.screenSize.width / 3; + return ((screenWidth * 2) <= widget.position.getCenter()); + } + + double _getLeft() { + if (_isLeft()) { + var leftPadding = + widget.position.getCenter() - (_getTooltipWidth() * 0.1); + if (leftPadding + _getTooltipWidth() > widget.screenSize.width) { + leftPadding = (widget.screenSize.width - 20) - _getTooltipWidth(); + } + if (leftPadding < 20) { + leftPadding = 14; + } + return leftPadding; + } else if (!(_isRight())) { + return widget.position.getCenter() - (_getTooltipWidth() * 0.5); + } else { + return null; + } + } + + double _getRight() { + if (_isRight()) { + var rightPadding = + widget.position.getCenter() + (_getTooltipWidth() / 2); + if (rightPadding + _getTooltipWidth() > widget.screenSize.width) { + rightPadding = 14; + } + return rightPadding; + } else if (!(_isLeft())) { + return widget.position.getCenter() - (_getTooltipWidth() * 0.5); + } else { + return null; + } + } + + double _getSpace() { + var space = widget.position.getCenter() - (widget.contentWidth / 2); + if (space + widget.contentWidth > widget.screenSize.width) { + space = widget.screenSize.width - widget.contentWidth - 8; + } else if (space < (widget.contentWidth / 2)) { + space = 16; + } + return space; + } + + @override + void initState() { + super.initState(); + position = widget.offset; + } + + @override + Widget build(BuildContext context) { + final contentOrientation = findPositionForContent(position); + final contentOffsetMultiplier = contentOrientation == "BELOW" ? 1.0 : -1.0; + ToolTipWidget.isArrowUp = contentOffsetMultiplier == 1.0; + + final contentY = ToolTipWidget.isArrowUp + ? widget.position.getBottom() + (contentOffsetMultiplier * 3) + : widget.position.getTop() + (contentOffsetMultiplier * 3); + + final num contentFractionalOffset = + contentOffsetMultiplier.clamp(-1.0, 0.0); + + var paddingTop = ToolTipWidget.isArrowUp ? 22.0 : 0.0; + var paddingBottom = ToolTipWidget.isArrowUp ? 0.0 : 27.0; + + if (!widget.showArrow) { + paddingTop = 10; + paddingBottom = 10; + } + + if (widget.container == null) { + return Stack( + children: [ + widget.showArrow ? _getArrow(contentOffsetMultiplier) : Container(), + Positioned( + top: contentY, + left: _getLeft(), + right: _getRight(), + child: FractionalTranslation( + translation: Offset(0.0, contentFractionalOffset as double), + child: SlideTransition( + position: Tween( + begin: Offset(0.0, contentFractionalOffset / 10), + end: Offset(0.0, 0.100), + ).animate(widget.animationOffset), + child: Material( + color: Colors.transparent, + child: Container( + padding: + EdgeInsets.only(top: paddingTop, bottom: paddingBottom), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: GestureDetector( + onTap: widget.onTooltipTap, + child: Container( + width: _getTooltipWidth(), + padding: widget.contentPadding, + color: widget.tooltipColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + child: Column( + crossAxisAlignment: widget.title != null + ? CrossAxisAlignment.start + : CrossAxisAlignment.center, + children: [ + widget.title != null + ? Text( + widget.title, + style: widget.titleTextStyle ?? + Theme.of(context) + .textTheme + .headline6 + .merge(TextStyle( + color: + widget.textColor)), + ) + : Container(), + Text( + widget.description, + style: widget.descTextStyle ?? + Theme.of(context) + .textTheme + .subtitle2 + .merge(TextStyle( + color: widget.textColor)), + ), + ], + ), + ) + ], + ), + ), + ), + ), + ), + ), + ), + ), + ) + ], + ); + } else { + return Stack( + children: [ + Positioned( + left: _getSpace(), + top: contentY - 10, + child: FractionalTranslation( + translation: Offset(0.0, contentFractionalOffset as double), + child: SlideTransition( + position: Tween( + begin: Offset(0.0, contentFractionalOffset / 10), + end: !widget.showArrow && !ToolTipWidget.isArrowUp + ? Offset(0.0, 0.0) + : Offset(0.0, 0.100), + ).animate(widget.animationOffset), + child: Material( + color: Colors.transparent, + child: GestureDetector( + onTap: widget.onTooltipTap, + child: Container( + padding: EdgeInsets.only( + top: paddingTop, + ), + color: Colors.transparent, + child: Center( + child: MeasureSize( + onSizeChange: (size) { + setState(() { + var tempPos = position; + tempPos = Offset( + position.dx, position.dy + size.height); + position = tempPos; + }); + }, + child: widget.container), + ), + ), + ), + ), + ), + ), + ), + ], + ); + } + } + + Widget _getArrow(double contentOffsetMultiplier) { + final contentFractionalOffset = contentOffsetMultiplier.clamp(-1.0, 0.0); + return Positioned( + top: ToolTipWidget.isArrowUp + ? widget.position.getBottom() + : widget.position.getTop() - 1, + left: widget.position.getCenter() - 24, + child: FractionalTranslation( + translation: Offset(0.0, contentFractionalOffset), + child: SlideTransition( + position: Tween( + begin: Offset(0.0, contentFractionalOffset / 5), + end: Offset(0.0, 0.150), + ).animate(widget.animationOffset), + child: Icon( + ToolTipWidget.isArrowUp + ? Icons.arrow_drop_up + : Icons.arrow_drop_down, + color: widget.tooltipColor, + size: 50, + ), + ), + ), + ); + } + + Size _textSize(String text, TextStyle style) { + final textPainter = (TextPainter( + text: TextSpan(text: text, style: style), + maxLines: 1, + textScaleFactor: MediaQuery.of(context).textScaleFactor, + textDirection: TextDirection.ltr) + ..layout()) + .size; + return textPainter; + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/main.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/main.dart new file mode 100644 index 00000000..6f44d7c9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/flutter_showcaseview/main.dart @@ -0,0 +1,546 @@ +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'detailscreen.dart'; +import 'lib/showcaseview.dart'; + +void main() => runApp(ShowCaseApp()); + +class ShowCaseApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter ShowCase', + theme: ThemeData( + primaryColor: Color(0xffEE5366), + ), + debugShowCheckedModeBanner: false, + home: Scaffold( + body: ShowCaseWidget( + onStart: (index, key) { + log('onStart: $index, $key'); + }, + onComplete: (index, key) { + log('onComplete: $index, $key'); + if (index == 4) + SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light + .copyWith( + statusBarIconBrightness: Brightness.dark, + statusBarColor: Colors.white)); + }, + builder: Builder(builder: (context) => MailPage()), + autoPlay: false, + autoPlayDelay: Duration(seconds: 3), + autoPlayLockEnable: false, + ), + ), + ); + } +} + +class MailPage extends StatefulWidget { + @override + _MailPageState createState() => _MailPageState(); +} + +class _MailPageState extends State { + GlobalKey _one = GlobalKey(); + GlobalKey _two = GlobalKey(); + GlobalKey _three = GlobalKey(); + GlobalKey _four = GlobalKey(); + GlobalKey _five = GlobalKey(); + List mails = []; + + @override + void initState() { + super.initState(); + //Start showcase view after current widget frames are drawn. + WidgetsBinding.instance.addPostFrameCallback((_) => + ShowCaseWidget.of(context) + .startShowCase([_one, _two, _three, _four, _five])); + mails = [ + Mail( + sender: 'Medium', + sub: 'Showcase View', + msg: 'Check new showcase View', + date: '25 May', + isUnread: false, + ), + Mail( + sender: 'Quora', + sub: 'New Question for you', + msg: 'Hi, There is new question for you', + date: '22 May', + isUnread: false, + ), + Mail( + sender: 'Google', + sub: 'Flutter 1.5', + msg: 'We have launched Flutter 1.5', + date: '20 May', + isUnread: true, + ), + Mail( + sender: 'Github', + sub: 'Showcase View', + msg: 'New star on your showcase view.', + date: '21 May ', + isUnread: false, + ), + Mail( + sender: 'Simform', + sub: 'Credit card Plugin', + msg: 'Check out our credit card plugin', + date: '19 May', + isUnread: true, + ), + Mail( + sender: 'Flutter', + sub: 'Flutter is Future', + msg: 'Flutter laucnhed for Web', + date: '18 Jun', + isUnread: true, + ), + Mail( + sender: 'Medium', + sub: 'Showcase View', + msg: 'Check new showcase View', + date: '21 May ', + isUnread: false, + ), + Mail( + sender: 'Simform', + sub: 'Credit card Plugin', + msg: 'Check out our credit card plugin', + date: '19 May', + isUnread: true, + ), + Mail( + sender: 'Flutter', + sub: 'Flutter is Future', + msg: 'Flutter laucnhed for Web', + date: '18 Jun', + isUnread: true, + ), + ]; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + bottom: false, + child: Column( + children: [ + SizedBox( + height: 20, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Container( + padding: const EdgeInsets.only(left: 10, right: 8), + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Color(0xffF9F9F9), + border: Border.all( + color: Color(0xffF3F3F3), width: 2), + borderRadius: BorderRadius.circular(8)), + child: Row( + children: [ + Expanded( + child: Row( + children: [ + Showcase( + key: _one, + description: 'Tap to see menu options', + child: Icon( + Icons.menu, + color: Theme.of(context).primaryColor, + ), + ), + SizedBox( + width: 10, + ), + Text( + 'Search email', + style: TextStyle( + color: Colors.black45, + fontSize: 16, + letterSpacing: 0.4), + ), + Spacer(), + Icon( + Icons.search, + color: Color(0xffADADAD), + ), + ], + ), + ), + ], + ), + ), + ), + ), + Showcase( + overlayPadding: EdgeInsets.all(5), + key: _two, + title: 'Profile', + description: + 'Tap to see profile which contains user\'s name, profile picture, mobile number and country', + contentPadding: EdgeInsets.all(8.0), + showcaseBackgroundColor: Theme.of(context).primaryColor, + textColor: Colors.white, + shapeBorder: CircleBorder(), + child: Container( + padding: EdgeInsets.all(5), + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).primaryColor), + child: Image.asset('assets/simform.png'), + ), + ), + SizedBox( + width: 12, + ) + ], + ), + SizedBox( + height: 10, + ), + Container( + padding: const EdgeInsets.only(left: 16, top: 4), + child: Text( + 'PRIMARY', + style: TextStyle( + color: Colors.black, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + Padding(padding: EdgeInsets.only(top: 8)), + Expanded( + child: ListView.builder( + physics: BouncingScrollPhysics(), + itemBuilder: (context, index) { + if (index == 0) { + return showcaseMailTile(context); + } + return MailTile(mails[index % mails.length]); + }), + ) + ], + ), + ), + floatingActionButton: Showcase( + key: _five, + title: 'Compose Mail', + description: 'Click here to compose mail', + shapeBorder: CircleBorder(), + child: FloatingActionButton( + backgroundColor: Theme.of(context).primaryColor, + onPressed: () { + setState(() { + ShowCaseWidget.of(context) + .startShowCase([_one, _two, _three, _four, _five]); + }); + }, + child: Icon( + Icons.add, + ), + ), + ), + ); + } + + GestureDetector showcaseMailTile(BuildContext context) { + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => Detail(), + ), + ); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Showcase( + key: _three, + description: 'Tap to check mail', + disposeOnTap: true, + onTargetClick: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => Detail(), + ), + ).then((_) { + setState(() { + ShowCaseWidget.of(context).startShowCase([_four, _five]); + }); + }); + }, + child: Container( + padding: + const EdgeInsets.only(left: 6, right: 16, top: 5, bottom: 5), + color: Color(0xffFFF6F7), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Showcase.withWidget( + key: _four, + height: 50, + width: 140, + shapeBorder: CircleBorder(), + container: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xffFCD8DC), + ), + child: Center( + child: Text( + 'S', + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ), + SizedBox( + height: 10, + ), + Text( + 'Your sender\'s profile ', + style: TextStyle(color: Colors.white), + ) + ], + ), + child: Container( + margin: const EdgeInsets.all(10), + child: Container( + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xffFCD8DC), + ), + child: Center( + child: Text( + 'S', + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ), + ), + ), + Padding(padding: EdgeInsets.only(left: 8)), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Slack', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 17, + ), + ), + Text( + 'Flutter Notification', + style: TextStyle( + fontSize: 16, + ), + ), + Text( + 'Hi, you have new Notification', + style: TextStyle( + fontWeight: FontWeight.normal, + color: Theme.of(context).primaryColor, + fontSize: 15, + ), + ), + ], + ) + ], + ), + ), + Container( + width: 50, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: 5, + ), + Text( + '1 Jun', + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 12, + color: Colors.grey, + ), + ), + SizedBox( + height: 10, + ), + Icon( + Icons.star, + color: Color(0xffFBC800), + ) + ], + ), + ), + ], + ), + ), + ), + ), + ); + } +} + +class Mail { + String sender; + String sub; + String msg; + String date; + bool isUnread; + + Mail({ + @required this.sender, + @required this.sub, + @required this.msg, + @required this.date, + @required this.isUnread, + }); +} + +class MailTile extends StatelessWidget { + final Mail mail; + + MailTile(this.mail); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only(left: 6, right: 16, top: 8, bottom: 8), + color: mail.isUnread ? Color(0xffFFF6F7) : Colors.white, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: const EdgeInsets.all(10), + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xffFCD8DC), + ), + child: Center( + child: Text( + mail.sender[0], + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ), + Padding(padding: EdgeInsets.only(left: 8)), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + mail.sender, + style: TextStyle( + fontWeight: + mail.isUnread ? FontWeight.bold : FontWeight.normal, + fontSize: 17, + ), + ), + Text( + mail.sub, + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 16, + ), + ), + Text( + mail.msg, + style: TextStyle( + fontWeight: FontWeight.normal, + color: mail.isUnread + ? Theme.of(context).primaryColor + : Colors.black, + fontSize: 15, + ), + ), + ], + ) + ], + ), + ), + Container( + width: 50, + child: Column( + children: [ + SizedBox( + height: 5, + ), + Text( + mail.date, + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 12, + color: Colors.grey, + ), + ), + SizedBox( + height: 10, + ), + Icon( + mail.isUnread ? Icons.star : Icons.star_border, + color: mail.isUnread ? Color(0xffFBC800) : Colors.grey, + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/lib/scroll_to_index.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/lib/scroll_to_index.dart new file mode 100644 index 00000000..a0232e20 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/lib/scroll_to_index.dart @@ -0,0 +1,644 @@ +//Copyright (C) 2019 Potix Corporation. All Rights Reserved. +//History: Tue Apr 24 09:17 CST 2019 +// Author: Jerry Chen + +library scroll_to_index; + +import 'dart:async'; +import 'dart:math' as math; + +import 'package:flutter/rendering.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter/widgets.dart'; + +import 'util.dart'; + +const defaultScrollDistanceOffset = 100.0; +const defaultDurationUnit = 40; + +const _millisecond = Duration(milliseconds: 1); +const _highlightDuration = const Duration(seconds: 3); +const scrollAnimationDuration = Duration(milliseconds: 250); + +typedef Rect ViewportBoundaryGetter(); +typedef double AxisValueGetter(Rect rect); + +Rect defaultViewportBoundaryGetter() => Rect.zero; + +abstract class AutoScrollController implements ScrollController { + factory AutoScrollController( + {double initialScrollOffset: 0.0, + bool keepScrollOffset: true, + double suggestedRowHeight, + ViewportBoundaryGetter viewportBoundaryGetter: + defaultViewportBoundaryGetter, + Axis axis, + String debugLabel, + AutoScrollController copyTagsFrom}) { + return SimpleAutoScrollController( + initialScrollOffset: initialScrollOffset, + keepScrollOffset: keepScrollOffset, + suggestedRowHeight: suggestedRowHeight, + viewportBoundaryGetter: viewportBoundaryGetter, + beginGetter: axis == Axis.horizontal ? (r) => r.left : (r) => r.top, + endGetter: axis == Axis.horizontal ? (r) => r.right : (r) => r.bottom, + copyTagsFrom: copyTagsFrom, + debugLabel: debugLabel); + } + + /// used to quick scroll to a index if the row height is the same + double get suggestedRowHeight; + + /// used to make the additional boundary for viewport + /// e.g. a sticky header which covers the real viewport of a list view + ViewportBoundaryGetter get viewportBoundaryGetter; + + /// used to choose which direction you are using. + /// e.g. axis == Axis.horizontal ? (r) => r.left : (r) => r.top + AxisValueGetter get beginGetter; + AxisValueGetter get endGetter; + + /// detect if it's in scrolling (scrolling is a async process) + bool get isAutoScrolling; + + /// all layout out states will be put into this map + Map get tagMap; + + /// used to chaining parent scroll controller + set parentController(ScrollController parentController); + + /// check if there is a parent controller + bool get hasParentController; + + /// scroll to the giving index + Future scrollToIndex(int index, + {Duration duration: scrollAnimationDuration, + AutoScrollPosition preferPosition}); + + /// highlight the item + Future highlight(int index, + {bool cancelExistHighlights: true, + Duration highlightDuration: _highlightDuration, + bool animated: true}); + + /// cancel all highlight item immediately. + void cancelAllHighlights(); + + /// check if the state is created. that is, is the indexed widget is layout out. + /// NOTE: state created doesn't mean it's in viewport. it could be a buffer range, depending on flutter's implementation. + bool isIndexStateInLayoutRange(int index); +} + +class SimpleAutoScrollController extends ScrollController + with AutoScrollControllerMixin { + @override + final double suggestedRowHeight; + @override + final ViewportBoundaryGetter viewportBoundaryGetter; + @override + final AxisValueGetter beginGetter; + @override + final AxisValueGetter endGetter; + + SimpleAutoScrollController( + {double initialScrollOffset: 0.0, + bool keepScrollOffset: true, + this.suggestedRowHeight, + this.viewportBoundaryGetter: defaultViewportBoundaryGetter, + @required this.beginGetter, + @required this.endGetter, + AutoScrollController copyTagsFrom, + String debugLabel}) + : super( + initialScrollOffset: initialScrollOffset, + keepScrollOffset: keepScrollOffset, + debugLabel: debugLabel) { + if (copyTagsFrom != null) tagMap.addAll(copyTagsFrom.tagMap); + } +} + +class PageAutoScrollController extends PageController + with AutoScrollControllerMixin { + @override + final double suggestedRowHeight; + @override + final ViewportBoundaryGetter viewportBoundaryGetter; + @override + final AxisValueGetter beginGetter = (r) => r.left; + @override + final AxisValueGetter endGetter = (r) => r.right; + + PageAutoScrollController( + {int initialPage: 0, + bool keepPage: true, + double viewportFraction: 1.0, + this.suggestedRowHeight, + this.viewportBoundaryGetter: defaultViewportBoundaryGetter, + AutoScrollController copyTagsFrom, + String debugLabel}) + : super( + initialPage: initialPage, + keepPage: keepPage, + viewportFraction: viewportFraction) { + if (copyTagsFrom != null) tagMap.addAll(copyTagsFrom.tagMap); + } +} + +enum AutoScrollPosition { begin, middle, end } +mixin AutoScrollControllerMixin on ScrollController + implements AutoScrollController { + @override + final Map tagMap = {}; + double get suggestedRowHeight; + ViewportBoundaryGetter get viewportBoundaryGetter; + AxisValueGetter get beginGetter; + AxisValueGetter get endGetter; + + bool __isAutoScrolling = false; + set _isAutoScrolling(bool isAutoScrolling) { + __isAutoScrolling = isAutoScrolling; + if (!isAutoScrolling && + hasClients) //after auto scrolling, we should sync final scroll position without flag on + notifyListeners(); + } + + @override + bool get isAutoScrolling => __isAutoScrolling; + + ScrollController _parentController; + @override + set parentController(ScrollController parentController) { + if (_parentController == parentController) return; + + final isNotEmpty = positions.isNotEmpty; + if (isNotEmpty && _parentController != null) { + for (final p in _parentController.positions) + if (positions.contains(p)) _parentController.detach(p); + } + + _parentController = parentController; + + if (isNotEmpty && _parentController != null) + for (final p in positions) _parentController.attach(p); + } + + @override + bool get hasParentController => _parentController != null; + + @override + void attach(ScrollPosition position) { + super.attach(position); + + _parentController?.attach(position); + } + + @override + void detach(ScrollPosition position) { + _parentController?.detach(position); + + super.detach(position); + } + + static const maxBound = 30; // 0.5 second if 60fps + @override + Future scrollToIndex(int index, + {Duration duration: scrollAnimationDuration, + AutoScrollPosition preferPosition}) async { + return co( + this, + () => _scrollToIndex(index, + duration: duration, preferPosition: preferPosition)); + } + + Future _scrollToIndex(int index, + {Duration duration: scrollAnimationDuration, + AutoScrollPosition preferPosition}) async { + assert(duration > Duration.zero); + + // In listView init or reload case, widget state of list item may not be ready for query. + // this prevent from over scrolling becoming empty screen or unnecessary scroll bounce. + Future makeSureStateIsReady() async { + for (var count = 0; count < maxBound; count++) { + if (_isEmptyStates) { + await _waitForWidgetStateBuild(); + } else + return null; + } + + return null; + } + + await makeSureStateIsReady(); + + if (!hasClients) return null; + + // two cases, + // 1. already has state. it's in viewport layout + // 2. doesn't have state yet. it's not in viewport so we need to start scrolling to make it into layout range. + if (isIndexStateInLayoutRange(index)) { + _isAutoScrolling = true; + + await _bringIntoViewportIfNeed(index, preferPosition, + (double offset) async { + await animateTo(offset, duration: duration, curve: Curves.ease); + await _waitForWidgetStateBuild(); + return null; + }); + + _isAutoScrolling = false; + } else { + // the idea is scrolling based on either + // 1. suggestedRowHeight or + // 2. testDistanceOffset + double prevOffset = offset - 1; + double currentOffset = offset; + bool contains = false; + Duration spentDuration = const Duration(); + double lastScrollDirection = 0.5; // alignment, default center; + final moveDuration = duration ~/ defaultDurationUnit; + + _isAutoScrolling = true; + + /// ideally, the suggest row height will move to the final corrent offset approximately in just one scroll(iteration). + /// if the given suggest row height is the minimal/maximal height in variable row height enviroment, + /// we can just use viewport calculation to reach the final offset in other iteration. + bool usedSuggestedRowHeightIfAny = true; + while (prevOffset != currentOffset && + !(contains = isIndexStateInLayoutRange(index))) { + prevOffset = currentOffset; + final nearest = _getNearestIndex(index); + final moveTarget = + _forecastMoveUnit(index, nearest, usedSuggestedRowHeightIfAny); + if (moveTarget < 0) //can't forecast the move range + return null; + // assume suggestRowHeight will move to correct offset in just one time. + // if the rule doesn't work (in variable row height case), we will use backup solution (non-suggested way) + final suggestedDuration = + usedSuggestedRowHeightIfAny && suggestedRowHeight != null + ? duration + : null; + usedSuggestedRowHeightIfAny = false; // just use once + lastScrollDirection = moveTarget - prevOffset > 0 ? 1 : 0; + currentOffset = moveTarget; + spentDuration += suggestedDuration ?? moveDuration; + final oldOffset = offset; + await animateTo(currentOffset, + duration: suggestedDuration ?? moveDuration, curve: Curves.ease); + await _waitForWidgetStateBuild(); + if (!hasClients || offset == oldOffset) { + // already scroll to begin or end + contains = isIndexStateInLayoutRange(index); + break; + } + } + _isAutoScrolling = false; + + if (contains && hasClients) { + await _bringIntoViewportIfNeed( + index, preferPosition ?? _alignmentToPosition(lastScrollDirection), + (finalOffset) async { + if (finalOffset != offset) { + _isAutoScrolling = true; + final remaining = duration - spentDuration; + await animateTo(finalOffset, + duration: remaining <= Duration.zero ? _millisecond : remaining, + curve: Curves.ease); + await _waitForWidgetStateBuild(); + + // not sure why it doesn't scroll to the given offset, try more within 3 times + if (hasClients && offset != finalOffset) { + final count = 3; + for (var i = 0; + i < count && hasClients && offset != finalOffset; + i++) { + await animateTo(finalOffset, + duration: _millisecond, curve: Curves.ease); + await _waitForWidgetStateBuild(); + } + } + _isAutoScrolling = false; + } + }); + } + } + + return null; + } + + @override + Future highlight(int index, + {bool cancelExistHighlights: true, + Duration highlightDuration: _highlightDuration, + bool animated: true}) async { + final tag = tagMap[index]; + return tag == null + ? null + : await tag.highlight( + cancelExisting: cancelExistHighlights, + highlightDuration: highlightDuration, + animated: animated); + } + + @override + void cancelAllHighlights() { + _cancelAllHighlights(); + } + + @override + bool isIndexStateInLayoutRange(int index) => tagMap[index] != null; + + /// this means there is no widget state existing, usually happened before build. + /// we should wait for next frame. + bool get _isEmptyStates => tagMap.isEmpty; + + /// wait until the [SchedulerPhase] in [SchedulerPhase.persistentCallbacks]. + /// it means if we do animation scrolling to a position, the Future call back will in [SchedulerPhase.midFrameMicrotasks]. + /// if we want to search viewport element depending on Widget State, we must delay it to [SchedulerPhase.persistentCallbacks]. + /// which is the phase widget build/layout/draw + Future _waitForWidgetStateBuild() => SchedulerBinding.instance.endOfFrame; + + /// NOTE: this is used to forcase the nearestIndex. if the the index equals targetIndex, + /// we will use the function, calling _directionalOffsetToRevealInViewport to get move unit. + double _forecastMoveUnit( + int targetIndex, int currentNearestIndex, bool useSuggested) { + assert(targetIndex != currentNearestIndex); + currentNearestIndex = currentNearestIndex ?? 0; //null as none of state + + final alignment = targetIndex > currentNearestIndex ? 1.0 : 0.0; + double absoluteOffsetToViewport; + + if (tagMap[currentNearestIndex] == null) return -1; + + if (useSuggested && suggestedRowHeight != null) { + final indexDiff = (targetIndex - currentNearestIndex); + final offsetToLastState = _offsetToRevealInViewport( + currentNearestIndex, indexDiff <= 0 ? 0 : 1); + absoluteOffsetToViewport = math.max( + offsetToLastState.offset + indexDiff * suggestedRowHeight, 0); + } else { + final offsetToLastState = + _offsetToRevealInViewport(currentNearestIndex, alignment); + assert((offsetToLastState?.offset ?? 0) >= 0, + "ERROR: %%%%%%%%%%%%%%: $targetIndex, $currentNearestIndex, $alignment, $offsetToLastState, ${tagMap.keys.toList().join(',')}"); + absoluteOffsetToViewport = offsetToLastState?.offset; + if (absoluteOffsetToViewport == null) + absoluteOffsetToViewport = defaultScrollDistanceOffset; + } + + return absoluteOffsetToViewport; + } + + int _getNearestIndex(int index) { + final list = tagMap.keys; + if (list.isEmpty) return null; + + final sorted = list.toList() + ..sort((int first, int second) => first.compareTo(second)); + final min = sorted.first; + final max = sorted.last; + return (index - min).abs() < (index - max).abs() ? min : max; + } + + /// bring the state node (already created but all of it may not be fully in the viewport) into viewport + Future _bringIntoViewportIfNeed(int index, AutoScrollPosition preferPosition, + Future move(double offset)) async { + final begin = _directionalOffsetToRevealInViewport(index, 0); + final end = _directionalOffsetToRevealInViewport(index, 1); + + if (preferPosition != null) { + double targetOffset = _directionalOffsetToRevealInViewport( + index, _positionToAlignment(preferPosition)); + + if (targetOffset < position.minScrollExtent) + targetOffset = position.minScrollExtent; + else if (targetOffset > position.maxScrollExtent) + targetOffset = position.maxScrollExtent; + + await move(targetOffset); + } else { + final alreadyInViewport = offset < begin && offset > end; + if (!alreadyInViewport) { + double value; + if ((end - offset).abs() < (begin - offset).abs()) + value = end; + else + value = begin; + + await move(value > 0 ? value : 0); + } + } + } + + double _positionToAlignment(AutoScrollPosition position) { + return position == AutoScrollPosition.begin + ? 0 + : position == AutoScrollPosition.end + ? 1 + : 0.5; + } + + AutoScrollPosition _alignmentToPosition(double alignment) => alignment == 0 + ? AutoScrollPosition.begin + : alignment == 1 + ? AutoScrollPosition.end + : AutoScrollPosition.middle; + + /// return offset, which is a absolute offset to bring the target index object into the location(depends on [direction]) of viewport + /// see also: _offsetYToRevealInViewport() + double _directionalOffsetToRevealInViewport(int index, double alignment) { + assert(alignment == 0 || alignment == 0.5 || alignment == 1); + // 1.0 bottom, 0.5 center, 0.0 begin if list is vertically from begin to end + final tagOffsetInViewport = _offsetToRevealInViewport(index, alignment); + + if (tagOffsetInViewport == null) { + return -1; + } else { + double absoluteOffsetToViewport = tagOffsetInViewport.offset; + if (alignment == 0.5) { + return absoluteOffsetToViewport; + } else if (alignment == 0) { + return absoluteOffsetToViewport - beginGetter(viewportBoundaryGetter()); + } else { + return absoluteOffsetToViewport + endGetter(viewportBoundaryGetter()); + } + } + } + + /// return offset, which is a absolute offset to bring the target index object into the center of the viewport + /// see also: _directionalOffsetToRevealInViewport() + RevealedOffset _offsetToRevealInViewport(int index, double alignment) { + final ctx = tagMap[index]?.context; + if (ctx == null) return null; + + final renderBox = ctx.findRenderObject(); + assert(Scrollable.of(ctx) != null); + final RenderAbstractViewport viewport = + RenderAbstractViewport.of(renderBox); + final revealedOffset = viewport.getOffsetToReveal(renderBox, alignment); + + return revealedOffset; + } +} + +void _cancelAllHighlights([AutoScrollTagState state]) { + for (final tag in _highlights.keys) + tag._cancelController(reset: tag != state); + + _highlights.clear(); +} + +class AutoScrollTag extends StatefulWidget { + final AutoScrollController controller; + final int index; + final Widget child; + final Color color; + final Color highlightColor; + final bool disabled; + + AutoScrollTag( + {@required Key key, + @required this.controller, + @required this.index, + @required this.child, + this.color, + this.highlightColor, + this.disabled: false}) + : super(key: key); + + @override + AutoScrollTagState createState() { + return new AutoScrollTagState(); + } +} + +Map _highlights = + {}; + +class AutoScrollTagState extends State + with TickerProviderStateMixin { + AnimationController _controller; + + @override + void initState() { + super.initState(); + if (!widget.disabled) { + register(widget.index); + } + } + + @override + void dispose() { + _cancelController(); + if (!widget.disabled) { + unregister(widget.index); + } + _controller = null; + _highlights.remove(this); + super.dispose(); + } + + @override + void didUpdateWidget(W oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.index != widget.index || + oldWidget.key != widget.key || + oldWidget.disabled != widget.disabled) { + if (!oldWidget.disabled) unregister(oldWidget.index); + + if (!widget.disabled) register(widget.index); + } + } + + void register(int index) { + // the caller in initState() or dispose() is not in the order of first dispose and init + // so we can't assert there isn't a existing key + // assert(!widget.controller.tagMap.keys.contains(index)); + widget.controller.tagMap[index] = this; + } + + void unregister(int index) { + _cancelController(); + _highlights.remove(this); + // the caller in initState() or dispose() is not in the order of first dispose and init + // so we can't assert there isn't a existing key + // assert(widget.controller.tagMap.keys.contains(index)); + if (widget.controller.tagMap[index] == this) + widget.controller.tagMap.remove(index); + } + + @override + Widget build(BuildContext context) { + return new DecoratedBoxTransition( + decoration: new DecorationTween( + begin: widget.color != null + ? new BoxDecoration(color: widget.color) + : new BoxDecoration(), + end: widget.color != null + ? new BoxDecoration(color: widget.color) + : new BoxDecoration(color: widget.highlightColor)) + .animate(_controller ?? kAlwaysDismissedAnimation), + child: widget.child); + } + + //used to make sure we will drop the old highlight + //it's rare that we call it more than once in same millisecond, so we just make the time stamp as the unique key + DateTime _startKey; + + /// this function can be called multiple times. every call will reset the highlight style. + Future highlight( + {bool cancelExisting: true, + Duration highlightDuration: _highlightDuration, + bool animated: true}) async { + if (!mounted) return null; + + if (cancelExisting) { + _cancelAllHighlights(this); + } + + if (_highlights.containsKey(this)) { + assert(_controller != null); + _controller.stop(); + } + + if (_controller == null) { + _controller = new AnimationController(vsync: this); + _highlights[this] = _controller; + } + + final startKey0 = _startKey = DateTime.now(); + const animationShow = 1.0; + setState(() {}); + if (animated) + await catchAnimationCancel(_controller + .animateTo(animationShow, duration: scrollAnimationDuration)); + else + _controller.value = animationShow; + await Future.delayed(highlightDuration); + + if (startKey0 == _startKey) { + if (mounted) { + setState(() {}); + const animationHide = 0.0; + if (animated) + await catchAnimationCancel(_controller + .animateTo(animationHide, duration: scrollAnimationDuration)); + else + _controller.value = animationHide; + } + + if (startKey0 == _startKey) { + _controller = null; + _highlights.remove(this); + } + } + return null; + } + + void _cancelController({bool reset: true}) { + if (_controller != null) { + if (_controller.isAnimating) _controller.stop(); + + if (reset && _controller.value != 0.0) _controller.value = 0.0; + } + } +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/lib/util.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/lib/util.dart new file mode 100644 index 00000000..55568c43 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/lib/util.dart @@ -0,0 +1,59 @@ +//Copyright (C) 2019 Potix Corporation. All Rights Reserved. +//History: Tue Apr 24 09:17 CST 2019 +// Author: Jerry Chen + +library util; + +import 'dart:async'; +import 'dart:collection'; + +import 'package:flutter/animation.dart'; + +/// used to invoke async functions in order +Future co(key, FutureOr action()) async { + for (;;) { + final c = _locks[key]; + if (c == null) break; + try { + await c.future; + } catch (_) {} //ignore error (so it will continue) + } + + final c = _locks[key] = new Completer(); + void then(T result) { + final c2 = _locks.remove(key); + c.complete(result); + + assert(identical(c, c2)); + } + + void catchError(ex, StackTrace st) { + final c2 = _locks.remove(key); + c.completeError(ex, st); + + assert(identical(c, c2)); + } + + try { + final result = action(); + if (result is Future) { + result.then(then).catchError(catchError); + } else { + then(result); + } + } catch (ex, st) { + catchError(ex, st); + } + + return c.future; +} + +final _locks = new HashMap(); + +/// skip the TickerCanceled exception +Future catchAnimationCancel(TickerFuture future) async { + return future.orCancel.catchError((_) async { + // do nothing, skip TickerCanceled exception + return null; + }, test: (ex) => ex is TickerCanceled); +} diff --git a/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/main.dart b/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/main.dart new file mode 100644 index 00000000..14d277a3 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/ui_helpers/scroll_to_index/main.dart @@ -0,0 +1,114 @@ +//Copyright (C) 2019 Potix Corporation. All Rights Reserved. +//History: Tue Apr 24 09:29 CST 2019 +// Author: Jerry Chen + +import 'dart:math' as math; + +import 'package:flutter/material.dart'; + +import 'lib/scroll_to_index.dart'; + +void main() => runApp(ScrollToIndexApp()); + +class ScrollToIndexApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Scroll To Index Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyHomePage(title: 'Scroll To Index Demo'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, @required this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + static const maxCount = 100; + final random = math.Random(); + final scrollDirection = Axis.vertical; + + AutoScrollController controller; + List> randomList; + + @override + void initState() { + super.initState(); + controller = AutoScrollController( + viewportBoundaryGetter: () => + Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), + axis: scrollDirection); + randomList = List.generate(maxCount, + (index) => [index, (1000 * random.nextDouble()).toInt()]); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: ListView( + scrollDirection: scrollDirection, + controller: controller, + children: randomList.map((data) { + return Padding( + padding: EdgeInsets.all(8), + child: _getRow(data[0], math.max(data[1].toDouble(), 50.0)), + ); + }).toList(), + ), + floatingActionButton: FloatingActionButton( + onPressed: _scrollToIndex, + tooltip: 'Increment', + child: Text(counter.toString()), + ), + ); + } + + int counter = -1; + Future _scrollToIndex() async { + setState(() { + counter++; + + if (counter >= maxCount) counter = 0; + }); + + await controller.scrollToIndex(counter, + preferPosition: AutoScrollPosition.begin); + controller.highlight(counter); + } + + Widget _getRow(int index, double height) { + return _wrapScrollTag( + index: index, + child: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.topCenter, + height: height, + decoration: BoxDecoration( + border: Border.all(color: Colors.lightBlue, width: 4), + borderRadius: BorderRadius.circular(12)), + child: Text('index: $index, height: $height'), + )); + } + + Widget _wrapScrollTag({@required int index, @required Widget child}) => + AutoScrollTag( + key: ValueKey(index), + controller: controller, + index: index, + child: child, + highlightColor: Colors.black.withOpacity(0.1), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_date.dart b/FlutterHelper/flutter_helper/lib/utils/util_date.dart new file mode 100644 index 00000000..2b54aa05 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_date.dart @@ -0,0 +1,267 @@ +class DateFormats { + static String full = 'yyyy-MM-dd HH:mm:ss'; + static String y_mo_d_h_m = 'yyyy-MM-dd HH:mm'; + static String y_mo_d = 'yyyy-MM-dd'; + static String y_mo = 'yyyy-MM'; + static String mo_d = 'MM-dd'; + static String mo_d_h_m = 'MM-dd HH:mm'; + static String h_m_s = 'HH:mm:ss'; + static String h_m = 'HH:mm'; + + static String zh_full = 'yyyy年MM月dd日 HH时mm分ss秒'; + static String zh_y_mo_d_h_m = 'yyyy年MM月dd日 HH时mm分'; + static String zh_y_mo_d = 'yyyy年MM月dd日'; + static String zh_y_mo = 'yyyy年MM月'; + static String zh_mo_d = 'MM月dd日'; + static String zh_mo_d_h_m = 'MM月dd日 HH时mm分'; + static String zh_h_m_s = 'HH时mm分ss秒'; + static String zh_h_m = 'HH时mm分'; +} + +// 这个月一共有几天, 1,2,5,7,8,10,腊,31天永不差 +Map MONTH_DAY = { + 1: 31, + 2: 28, + 3: 31, + 4: 30, + 5: 31, + 6: 30, + 7: 31, + 8: 31, + 9: 30, + 10: 31, + 11: 30, + 12: 31, +}; + +class DateUtil { + /// get DateTime By DateStr. + static DateTime getDateTime(String dateStr, {bool isUtc}) { + DateTime dateTime = DateTime.tryParse(dateStr); + if (isUtc ?? false) { + dateTime = dateTime?.toUtc(); + } else { + dateTime = dateTime?.toLocal(); + } + return dateTime; + } + + /// get DateTime By Milliseconds. + static DateTime getDateTimeByMs(int ms, {bool isUtc = false}) => + DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc); + + /// get DateMilliseconds By DateStr. + static int getDateMsByTimeStr(String dateStr, {bool isUtc}) => + getDateTime(dateStr, isUtc: isUtc).millisecondsSinceEpoch; + + /// get Now Date Milliseconds. + static int getNowDateMs() => DateTime.now().millisecondsSinceEpoch; + + /// get Now Date Str.(yyyy-MM-dd HH:mm:ss) + static String getNowDateStr() => formatDate(DateTime.now()); + + /// format date by milliseconds. + /// milliseconds 日期毫秒 + static String formatDateMs(int ms, {bool isUtc = false, String format}) => + formatDate(getDateTimeByMs(ms, isUtc: isUtc), format: format); + + /// format date by date str. + /// dateStr 日期字符串 + static String formatDateStr(String dateStr, {bool isUtc, String format}) => + formatDate(getDateTime(dateStr, isUtc: isUtc), format: format); + + /// format date by DateTime. + /// format 转换格式(已提供常用格式 DateFormats,可以自定义格式:'yyyy/MM/dd HH:mm:ss') + /// 格式要求 + /// year -> yyyy/yy month -> MM/M day -> dd/d + /// hour -> HH/H minute -> mm/m second -> ss/s + static String formatDate(DateTime dateTime, {String format}) { + if (dateTime == null) return ''; + format = format ?? DateFormats.full; + if (format.contains('yy')) { + String year = dateTime.year.toString(); + if (format.contains('yyyy')) { + format = format.replaceAll('yyyy', year); + } else { + format = format.replaceAll( + 'yy', year.substring(year.length - 2, year.length)); + } + } + + format = _comFormat(dateTime.month, format, 'M', 'MM'); + format = _comFormat(dateTime.day, format, 'd', 'dd'); + format = _comFormat(dateTime.hour, format, 'H', 'HH'); + format = _comFormat(dateTime.minute, format, 'm', 'mm'); + format = _comFormat(dateTime.second, format, 's', 'ss'); + format = _comFormat(dateTime.millisecond, format, 'S', 'SSS'); + + return format; + } + + /// com format. + static String _comFormat( + int value, String format, String single, String full) { + if (format.contains(single)) { + if (format.contains(full)) { + format = + format.replaceAll(full, value < 10 ? '0$value' : value.toString()); + } else { + format = format.replaceAll(single, value.toString()); + } + } + return format; + } + + /// get WeekDay. + /// dateTime + /// isUtc + /// languageCode zh or en + /// short + static String getWeekday(DateTime dateTime, + {String languageCode = 'en', bool short = false}) { + if (dateTime == null) return ""; + String weekday = ""; + switch (dateTime.weekday) { + case 1: + weekday = languageCode == 'zh' ? '星期一' : 'Monday'; + break; + case 2: + weekday = languageCode == 'zh' ? '星期二' : 'Tuesday'; + break; + case 3: + weekday = languageCode == 'zh' ? '星期三' : 'Wednesday'; + break; + case 4: + weekday = languageCode == 'zh' ? '星期四' : 'Thursday'; + break; + case 5: + weekday = languageCode == 'zh' ? '星期五' : 'Friday'; + break; + case 6: + weekday = languageCode == 'zh' ? '星期六' : 'Saturday'; + break; + case 7: + weekday = languageCode == 'zh' ? '星期日' : 'Sunday'; + break; + default: + break; + } + return languageCode == 'zh' + ? (short ? weekday.replaceAll('星期', '周') : weekday) + : weekday.substring(0, short ? 3 : weekday.length); + } + + /// get WeekDay By Milliseconds. + static String getWeekdayByMs(int milliseconds, + {bool isUtc = false, + String languageCode = 'en', + bool short = false}) => + getWeekday(getDateTimeByMs(milliseconds, isUtc: isUtc), + languageCode: languageCode, short: short); + + /// get day of year. + /// 在今年的第几天. + static int getDayOfYear(DateTime dateTime) { + int year = dateTime.year; + int month = dateTime.month; + int days = dateTime.day; + for (int i = 1; i < month; i++) { + days = days + MONTH_DAY[i]; + } + if (isLeapYearByYear(year) && month > 2) { + days = days + 1; + } + return days; + } + + /// get day of year. + /// 在今年的第几天. + static int getDayOfYearByMs(int ms, {bool isUtc = false}) { + return getDayOfYear(DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc)); + } + + /// is today. + /// 是否是当天. + static bool isToday(int milliseconds, {bool isUtc = false, int locMs}) { + if (milliseconds == null || milliseconds == 0) return false; + DateTime old = + DateTime.fromMillisecondsSinceEpoch(milliseconds, isUtc: isUtc); + DateTime now; + if (locMs != null) { + now = DateUtil.getDateTimeByMs(locMs); + } else { + now = isUtc ? DateTime.now().toUtc() : DateTime.now().toLocal(); + } + return old.year == now.year && old.month == now.month && old.day == now.day; + } + + /// is yesterday by dateTime. + /// 是否是昨天. + static bool isYesterday(DateTime dateTime, DateTime locDateTime) { + if (yearIsEqual(dateTime, locDateTime)) { + int spDay = getDayOfYear(locDateTime) - getDayOfYear(dateTime); + return spDay == 1; + } else { + return ((locDateTime.year - dateTime.year == 1) && + dateTime.month == 12 && + locDateTime.month == 1 && + dateTime.day == 31 && + locDateTime.day == 1); + } + } + + /// is yesterday by millis. + /// 是否是昨天. + static bool isYesterdayByMs(int ms, int locMs) { + return isYesterday(DateTime.fromMillisecondsSinceEpoch(ms), + DateTime.fromMillisecondsSinceEpoch(locMs)); + } + + /// is Week. + /// 是否是本周. + static bool isWeek(int ms, {bool isUtc = false, int locMs}) { + if (ms == null || ms <= 0) { + return false; + } + DateTime _old = DateTime.fromMillisecondsSinceEpoch(ms, isUtc: isUtc); + DateTime _now; + if (locMs != null) { + _now = DateUtil.getDateTimeByMs(locMs, isUtc: isUtc); + } else { + _now = isUtc ? DateTime.now().toUtc() : DateTime.now().toLocal(); + } + + DateTime old = + _now.millisecondsSinceEpoch > _old.millisecondsSinceEpoch ? _old : _now; + DateTime now = + _now.millisecondsSinceEpoch > _old.millisecondsSinceEpoch ? _now : _old; + return (now.weekday >= old.weekday) && + (now.millisecondsSinceEpoch - old.millisecondsSinceEpoch <= + 7 * 24 * 60 * 60 * 1000); + } + + /// year is equal. + /// 是否同年. + static bool yearIsEqual(DateTime dateTime, DateTime locDateTime) { + return dateTime.year == locDateTime.year; + } + + /// year is equal. + /// 是否同年. + static bool yearIsEqualByMs(int ms, int locMs) { + return yearIsEqual(DateTime.fromMillisecondsSinceEpoch(ms), + DateTime.fromMillisecondsSinceEpoch(locMs)); + } + + /// Return whether it is leap year. + /// 是否是闰年 + static bool isLeapYear(DateTime dateTime) { + return isLeapYearByYear(dateTime.year); + } + + /// Return whether it is leap year. + /// 是否是闰年 + static bool isLeapYearByYear(int year) { + return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_encrypt.dart b/FlutterHelper/flutter_helper/lib/utils/util_encrypt.dart new file mode 100644 index 00000000..d6267aad --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_encrypt.dart @@ -0,0 +1,50 @@ +import 'dart:convert'; +import 'package:crypto/crypto.dart'; +import 'package:convert/convert.dart'; + +/// Encrypt Utils. +class EncryptUtil { + // md5 加密 + static String encodeMd5(String data) { + return hex.encode(md5.convert(Utf8Encoder().convert(data)).bytes); + } + + // 异或对称加密 + static String xorCode(String res, String key) { + List keyList = key.split(','); + List codeUnits = res.codeUnits; + List codes = []; + for (int i = 0, length = codeUnits.length; i < length; i++) { + codes.add(codeUnits[i] ^ int.parse(keyList[i % keyList.length])); + } + return String.fromCharCodes(codes); + } + + /// 异或对称 Base64 加密 + static String xorBase64Encode(String res, String key) { + String encode = xorCode(res, key); + encode = encodeBase64(encode); + return encode; + } + + /// 异或对称 Base64 解密 + static String xorBase64Decode(String res, String key) { + String encode = decodeBase64(res); + encode = xorCode(encode, key); + return encode; + } + + /// Base64加密 + static String encodeBase64(String data) { + var content = utf8.encode(data); + var digest = base64Encode(content); + return digest; + } + + /// Base64解密 + static String decodeBase64(String data) { + List bytes = base64Decode(data); + String result = utf8.decode(bytes); + return result; + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_json.dart b/FlutterHelper/flutter_helper/lib/utils/util_json.dart new file mode 100644 index 00000000..179038ca --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_json.dart @@ -0,0 +1,72 @@ +import 'dart:convert'; + +class JsonUtil { + /// Converts object [value] to a JSON string. + static String encodeObj(dynamic value) { + return value == null ? null : json.encode(value); + } + + /// Converts JSON string [source] to object; + static T getObj(String source, T f(Map v)) { + if (source == null || source.isEmpty) return null; + try { + Map map = json.decode(source); + return f(map); + } catch (e, s) { + print('JsonUtil convert error, Exception: ${e.toString()}'); + } + return null; + } + + /// Converst JSON string or JSON map [source] t object. + static T getObject(dynamic source, T f(Map v)) { + if (source == null || source.toString().isEmpty) return null; + try { + Map map; + if (source is String) { + map = json.decode(source); + } else { + map = source; + } + return f(map); + } catch (e) { + print('JsonUtil convert error, Exception: ${e.toString()}'); + } + return null; + } + + // Converts JSON string list [source] to object list. + static List getObjectList(dynamic source, T f(Map v)) { + if (source == null || source.toString().isEmpty) return null; + try { + List list; + if (source is String) { + list = json.decode(source); + } else { + list = source; + } + return list.map((value) { + if (value is String) { + value = json.decode(value); + } + return f(value); + }); + } catch (e) { + print('JsonUtil convert error, Exception: ${e.toString()}'); + } + return null; + } + + /// get List + /// [1,2,3,4,5,6] + /// "[\"tom\",\"tony\",\"jacky\"]"; + static List getList(dynamic source) { + List list; + if (source is String) { + list = json.decode(source); + } else { + list = source; + } + return list?.map((e) => e as T)?.toList(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_log.dart b/FlutterHelper/flutter_helper/lib/utils/util_log.dart new file mode 100644 index 00000000..14d6a438 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_log.dart @@ -0,0 +1,51 @@ +import 'dart:developer'; + +/// 工具类 +class LogUtil { + static const String _defTag = "common_utils"; + static bool _debugMode = true; + static int _maxLen = 128; + static String _tagValue = _defTag; + + static void init({ + String tag = _defTag, + bool isDebug = false, + int maxLen = 128, + }) { + _tagValue = tag; + _debugMode = isDebug; + _maxLen = _maxLen; + } + + static void d(object, {tag}) { + if (_debugMode) log('$tag d | ${object?.toString()}'); + } + + static void e(object, {tag}) { + //if (_debugMode) log('$tag e | ${object?.toString()}'); + if (_debugMode) _printLog(tag, ' e ', object); + } + + static void v(object, {tag}) { + if (_debugMode) _printLog(tag, ' v ', object); + } + + static void _printLog(tag, String stag, object) { + String da = object?.toString() ?? 'null'; + tag = tag ?? _tagValue; + if (da.length <= _maxLen) { + print('$tag$stag $da'); + } + print('$tag$stag---------------st--------------'); + while (da.isNotEmpty) { + if (da.length > _maxLen) { + print('$tag$stag| ${da.substring(0, _maxLen)}'); + da = da.substring(_maxLen, da.length); + } else { + print('$tag$stag| $da'); + da = ''; + } + } + print('$tag$stag---------------ed--------------'); + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_money.dart b/FlutterHelper/flutter_helper/lib/utils/util_money.dart new file mode 100644 index 00000000..d0e48e51 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_money.dart @@ -0,0 +1,108 @@ +import 'package:flutter_helper/utils/util_num.dart'; + +enum MoneyUnit { + NORMAL, // 6.00 + YUAN, // ¥6.00 + YUAN_ZH, // 6.00元 + DOLLAR, // $6.00 +} +enum MoneyFormat { + NORMAL, //保留两位小数(6.00元) + END_INTEGER, //去掉末尾'0'(6.00元 -> 6元, 6.60元 -> 6.6元) + YUAN_INTEGER, //整元(6.00元 -> 6元) +} +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Money Util. + * @Date: 2018/9/29 + */ + +/// Money Util. +class MoneyUtil { + static const String YUAN = '¥'; + static const String YUAN_ZH = '元'; + static const String DOLLAR = '\$'; + + /// fen to yuan, format output. + /// 分 转 元, format格式输出. + static String changeF2Y(int amount, + {MoneyFormat format = MoneyFormat.NORMAL}) { + String moneyTxt; + double yuan = NumUtil.divide(amount, 100); + switch (format) { + case MoneyFormat.NORMAL: + moneyTxt = yuan.toStringAsFixed(2); + break; + case MoneyFormat.END_INTEGER: + if (amount % 100 == 0) { + moneyTxt = yuan.toInt().toString(); + } else if (amount % 10 == 0) { + moneyTxt = yuan.toStringAsFixed(1); + } else { + moneyTxt = yuan.toStringAsFixed(2); + } + break; + case MoneyFormat.YUAN_INTEGER: + moneyTxt = (amount % 100 == 0) + ? yuan.toInt().toString() + : yuan.toStringAsFixed(2); + break; + } + return moneyTxt; + } + + /// fen str to yuan, format & unit output. + /// 分字符串 转 元, format 与 unit 格式 输出. + static String changeFStr2YWithUnit(String amountStr, + {MoneyFormat format = MoneyFormat.NORMAL, + MoneyUnit unit = MoneyUnit.NORMAL}) { + int amount = int.parse(amountStr); + return changeF2YWithUnit(amount, format: format, unit: unit); + } + + /// fen to yuan, format & unit output. + /// 分 转 元, format 与 unit 格式 输出. + static String changeF2YWithUnit(int amount, + {MoneyFormat format = MoneyFormat.NORMAL, + MoneyUnit unit = MoneyUnit.NORMAL}) { + return withUnit(changeF2Y(amount, format: format), unit); + } + + /// yuan, format & unit output.(yuan is int,double,str). + /// 元, format 与 unit 格式 输出. + static String changeYWithUnit(Object yuan, MoneyUnit unit, + {MoneyFormat format}) { + String yuanTxt = yuan.toString(); + if (format != null) { + int amount = changeY2F(yuan); + yuanTxt = changeF2Y(amount.toInt(), format: format); + } + return withUnit(yuanTxt, unit); + } + + /// yuan to fen. + /// 元 转 分, + static int changeY2F(Object yuan) { + return NumUtil.multiplyDecStr(yuan.toString(), '100').toInt(); + } + + /// with unit. + /// 拼接单位. + static String withUnit(String moneyTxt, MoneyUnit unit) { + switch (unit) { + case MoneyUnit.YUAN: + moneyTxt = YUAN + moneyTxt; + break; + case MoneyUnit.YUAN_ZH: + moneyTxt = moneyTxt + YUAN_ZH; + break; + case MoneyUnit.DOLLAR: + moneyTxt = DOLLAR + moneyTxt; + break; + default: + break; + } + return moneyTxt; + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_num.dart b/FlutterHelper/flutter_helper/lib/utils/util_num.dart new file mode 100644 index 00000000..fcf74230 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_num.dart @@ -0,0 +1,152 @@ +import 'package:decimal/decimal.dart'; + +/// Num Util. +class NumUtil { + /// The parameter [fractionDigits] must be an integer satisfying: `0 <= fractionDigits <= 20`. + static num getNumByValueStr(String valueStr, {int fractionDigits}) { + double value = double.tryParse(valueStr); + return fractionDigits == null + ? value + : getNumByValueDouble(value, fractionDigits); + } + + /// The parameter [fractionDigits] must be an integer satisfying: `0 <= fractionDigits <= 20`. + static num getNumByValueDouble(double value, int fractionDigits) { + if (value == null) return null; + String valueStr = value.toStringAsFixed(fractionDigits); + return fractionDigits == 0 + ? int.tryParse(valueStr) + : double.tryParse(valueStr); + } + + /// get int by value str. + static int getIntByValueStr(String valueStr, {int defValue = 0}) { + return int.tryParse(valueStr) ?? defValue; + } + + /// get double by value str. + static double getDoubleByValueStr(String valueStr, {double defValue = 0}) { + return double.tryParse(valueStr) ?? defValue; + } + + ///isZero + static bool isZero(num value) => value == null || value == 0; + + /// 加 (精确相加,防止精度丢失). + /// add (without loosing precision). + static double add(num a, num b) { + return addDec(a, b).toDouble(); + } + + /// 减 (精确相减,防止精度丢失). + /// subtract (without loosing precision). + static double subtract(num a, num b) { + return subtractDec(a, b).toDouble(); + } + + /// 乘 (精确相乘,防止精度丢失). + /// multiply (without loosing precision). + static double multiply(num a, num b) { + return multiplyDec(a, b).toDouble(); + } + + /// 除 (精确相除,防止精度丢失). + /// divide (without loosing precision). + static double divide(num a, num b) { + return divideDec(a, b).toDouble(); + } + + /// 加 (精确相加,防止精度丢失). + /// add (without loosing precision). + static Decimal addDec(num a, num b) { + return addDecStr(a.toString(), b.toString()); + } + + /// 减 (精确相减,防止精度丢失). + /// subtract (without loosing precision). + static Decimal subtractDec(num a, num b) { + return subtractDecStr(a.toString(), b.toString()); + } + + /// 乘 (精确相乘,防止精度丢失). + /// multiply (without loosing precision). + static Decimal multiplyDec(num a, num b) { + return multiplyDecStr(a.toString(), b.toString()); + } + + /// 除 (精确相除,防止精度丢失). + /// divide (without loosing precision). + static Decimal divideDec(num a, num b) { + return divideDecStr(a.toString(), b.toString()); + } + + /// 余数 + static Decimal remainder(num a, num b) { + return remainderDecStr(a.toString(), b.toString()); + } + + /// Relational less than operator. + static bool lessThan(num a, num b) { + return lessThanDecStr(a.toString(), b.toString()); + } + + /// Relational less than or equal operator. + static bool thanOrEqual(num a, num b) { + return thanOrEqualDecStr(a.toString(), b.toString()); + } + + /// Relational greater than operator. + static bool greaterThan(num a, num b) { + return greaterThanDecStr(a.toString(), b.toString()); + } + + /// Relational greater than or equal operator. + static bool greaterOrEqual(num a, num b) { + return greaterOrEqualDecStr(a.toString(), b.toString()); + } + + /// 加 + static Decimal addDecStr(String a, String b) { + return Decimal.parse(a) + Decimal.parse(b); + } + + /// 减 + static Decimal subtractDecStr(String a, String b) { + return Decimal.parse(a) - Decimal.parse(b); + } + + /// 乘 + static Decimal multiplyDecStr(String a, String b) { + return Decimal.parse(a) * Decimal.parse(b); + } + + /// 除 + static Decimal divideDecStr(String a, String b) { + return Decimal.parse(a) / Decimal.parse(b); + } + + /// 余数 + static Decimal remainderDecStr(String a, String b) { + return Decimal.parse(a) % Decimal.parse(b); + } + + /// Relational less than operator. + static bool lessThanDecStr(String a, String b) { + return Decimal.parse(a) < Decimal.parse(b); + } + + /// Relational less than or equal operator. + static bool thanOrEqualDecStr(String a, String b) { + return Decimal.parse(a) <= Decimal.parse(b); + } + + /// Relational greater than operator. + static bool greaterThanDecStr(String a, String b) { + return Decimal.parse(a) > Decimal.parse(b); + } + + /// Relational greater than or equal operator. + static bool greaterOrEqualDecStr(String a, String b) { + return Decimal.parse(a) >= Decimal.parse(b); + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_object.dart b/FlutterHelper/flutter_helper/lib/utils/util_object.dart new file mode 100644 index 00000000..afeb6cd6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_object.dart @@ -0,0 +1,47 @@ +class ObjectUtil { + /// Returns true if the string is null or 0-length + static bool isEmptyString(String str) => str == null || str.isEmpty; + + /// Returns true if the list is null or 0-lenght + static bool isEmptyList(Iterable list) => list == null || list.isEmpty; + + /// Returns true if there is no key/value pair in the map + static bool isEmptyMap(Map map) => map == null || map.isEmpty; + + /// Returns true String or List or Map is empty. + static bool isEmpty(Object object) { + if (object == null) return true; + if (object is String && object.isEmpty) + return true; + else if (object is Iterable && object.isEmpty) + return true; + else if (object is Map && object.isEmpty) + return true; + else + return false; + } + + /// Returns true String or List or Map is not empty. + static bool isNotEmpty(Object object) => !isEmpty(object); + + static bool twoListIsEqual(List listA, List listB) { + if (listA == listB) return true; + if (listA == null || listB == null) return false; + if (listA.length != listB.length) return false; + listA.forEach((element) { + if (!listB.contains(element)) { + return false; + } + }); + return true; + } + + /// get length. + static int getLength(Object value) { + if (value == null) return 0; + if (value is String) return value.length; + if (value is Iterable) return value.length; + if (value is Map) return value.length; + return 0; + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_regex.dart b/FlutterHelper/flutter_helper/lib/utils/util_regex.dart new file mode 100644 index 00000000..17d92610 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_regex.dart @@ -0,0 +1,231 @@ +/// id card province dict. +List ID_CARD_PROVINCE_DICT = [ + '11=北京', + '12=天津', + '13=河北', + '14=山西', + '15=内蒙古', + '21=辽宁', + '22=吉林', + '23=黑龙江', + '31=上海', + '32=江苏', + '33=浙江', + '34=安徽', + '35=福建', + '36=江西', + '37=山东', + '41=河南', + '42=湖北', + '43=湖南', + '44=广东', + '45=广西', + '46=海南', + '50=重庆', + '51=四川', + '52=贵州', + '53=云南', + '54=西藏', + '61=陕西', + '62=甘肃', + '63=青海', + '64=宁夏', + '65=新疆', + '71=台湾老', + '81=香港', + '82=澳门', + '83=台湾新', + '91=国外', +]; + +/// Regex Util. +class RegexUtil { + /// Regex of simple mobile. + static final String regexMobileSimple = '^[1]\\d{10}\$'; + + /// Regex of exact mobile. + ///

china mobile: 134(0-8), 135, 136, 137, 138, 139, 147, 150, 151, 152, 157, 158, 159, 165, 172, 178, 182, 183, 184, 187, 188, 195, 198

+ ///

china unicom: 130, 131, 132, 145, 155, 156, 166, 167, 171, 175, 176, 185, 186

+ ///

china telecom: 133, 153, 162, 173, 177, 180, 181, 189, 199, 191

+ ///

global star: 1349

+ ///

virtual operator: 170

+ static final String regexMobileExact = + '^((13[0-9])|(14[57])|(15[0-35-9])|(16[2567])|(17[01235-8])|(18[0-9])|(19[1589]))\\d{8}\$'; + + /// Regex of telephone number. + static final String regexTel = '^0\\d{2,3}[- ]?\\d{7,8}'; + + /// Regex of id card number which length is 15. + static final String regexIdCard15 = + '^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}\$'; + + /// Regex of id card number which length is 18. + static final String regexIdCard18 = + '^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9Xx])\$'; + + /// Regex of email. + static final String regexEmail = + '^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*\$'; + + /// Regex of url. + static final String regexUrl = '[a-zA-Z]+://[^\\s]*'; + + /// Regex of Chinese character. + static final String regexZh = '[\\u4e00-\\u9fa5]'; + + /// Regex of date which pattern is 'yyyy-MM-dd'. + static final String regexDate = + '^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)\$'; + + /// Regex of ip address. + static final String regexIp = + '((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)'; + + /// must contain letters and numbers, 6 ~ 18. + /// 必须包含字母和数字, 6~18. + static const String regexUsername = + '^(?![0-9]+\$)(?![a-zA-Z]+\$)[0-9A-Za-z]{6,18}\$'; + + /// must contain letters and numbers, can contain special characters 6 ~ 18. + /// 必须包含字母和数字,可包含特殊字符 6~18. + static const String regexUsername2 = + '^(?![0-9]+\$)(?![a-zA-Z]+\$)[0-9A-Za-z\\W]{6,18}\$'; + + /// must contain letters and numbers and special characters, 6 ~ 18. + /// 必须包含字母和数字和殊字符, 6~18. + static const String regexUsername3 = + '^(?![0-9]+\$)(?![a-zA-Z]+\$)(?![0-9a-zA-Z]+\$)(?![0-9\\W]+\$)(?![a-zA-Z\\W]+\$)[0-9A-Za-z\\W]{6,18}\$'; + + /// Regex of QQ number. + static final String regexQQ = '[1-9][0-9]{4,}'; + + /// Regex of postal code in China. + static final String regexChinaPostalCode = "[1-9]\\d{5}(?!\\d)"; + + /// Regex of Passport. + static final String regexPassport = + r'(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)'; + + static final Map cityMap = Map(); + + ///Return whether input matches regex of simple mobile. + static bool isMobileSimple(String input) { + return matches(regexMobileSimple, input); + } + + ///Return whether input matches regex of exact mobile. + static bool isMobileExact(String input) { + return matches(regexMobileExact, input); + } + + /// Return whether input matches regex of telephone number. + static bool isTel(String input) { + return matches(regexTel, input); + } + + /// Return whether input matches regex of id card number. + static bool isIDCard(String input) { + if (input.length == 15) { + return isIDCard15(input); + } + if (input.length == 18) { + return isIDCard18Exact(input); + } + return false; + } + + /// Return whether input matches regex of id card number which length is 15. + static bool isIDCard15(String input) { + return matches(regexIdCard15, input); + } + + /// Return whether input matches regex of id card number which length is 18. + static bool isIDCard18(String input) { + return matches(regexIdCard18, input); + } + + ///Return whether input matches regex of exact id card number which length is 18. + static bool isIDCard18Exact(String input) { + if (isIDCard18(input)) { + List factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; + List suffix = [ + '1', + '0', + 'X', + '9', + '8', + '7', + '6', + '5', + '4', + '3', + '2' + ]; + if (cityMap.isEmpty) { + List list = ID_CARD_PROVINCE_DICT; + List> mapEntryList = []; + for (int i = 0, length = list.length; i < length; i++) { + List tokens = list[i].trim().split('='); + MapEntry mapEntry = MapEntry(tokens[0], tokens[1]); + mapEntryList.add(mapEntry); + } + cityMap.addEntries(mapEntryList); + } + if (cityMap[input.substring(0, 2)] != null) { + int weightSum = 0; + for (int i = 0; i < 17; ++i) { + weightSum += (input.codeUnitAt(i) - '0'.codeUnitAt(0)) * factor[i]; + } + int idCardMod = weightSum % 11; + String idCardLast = String.fromCharCode(input.codeUnitAt(17)); + return idCardLast == suffix[idCardMod]; + } + } + return false; + } + + /// Return whether input matches regex of email. + static bool isEmail(String input) { + return matches(regexEmail, input); + } + + /// Return whether input matches regex of url. + static bool isURL(String input) { + return matches(regexUrl, input); + } + + /// Return whether input matches regex of Chinese character. + static bool isZh(String input) { + return '〇' == input || matches(regexZh, input); + } + + /// Return whether input matches regex of date which pattern is 'yyyy-MM-dd'. + static bool isDate(String input) { + return matches(regexDate, input); + } + + /// Return whether input matches regex of ip address. + static bool isIP(String input) { + return matches(regexIp, input); + } + + /// Return whether input matches regex of username. + static bool isUserName(String input, {String regex = regexUsername}) { + return matches(regex, input); + } + + /// Return whether input matches regex of QQ. + static bool isQQ(String input) { + return matches(regexQQ, input); + } + + ///Return whether input matches regex of Passport. + static bool isPassport(String input) { + return matches(regexPassport, input); + } + + static bool matches(String regex, String input) { + if (input.isEmpty) return false; + return RegExp(regex).hasMatch(input); + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_text.dart b/FlutterHelper/flutter_helper/lib/utils/util_text.dart new file mode 100644 index 00000000..3d0c1983 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_text.dart @@ -0,0 +1,73 @@ +class TextUtil { + /// isEmpty + static bool isEmpty(String text) => text?.isEmpty ?? true; + + /// 每隔x位 加pattern + static String formatDigitPattern(String text, + {int digit = 4, String pattern = ' '}) { + text = text.replaceAllMapped(RegExp('(.{$digit})'), (Match match) { + return '${match.group(0)}$pattern'; + }); + if (text.endsWith(pattern)) { + text = text.substring(0, text.length - 1); + } + return text; + } + + /// 每隔 x位 加 pattern, 从末尾开始 + static String formatDigitPatternEnd(String text, + {int digit = 4, String pattern = ' '}) { + String temp = reverse(text); + temp = formatDigitPattern(temp, digit: digit, pattern: pattern); + temp = reverse(temp); + return temp; + } + + /// 每隔4位加空格 + static String formatSpace4(String text) { + return formatDigitPattern(text); + } + + /// 每隔3三位加逗号 + /// num 数字或数字字符串。int型。 + static String formatComma3(Object num) { + return formatDigitPatternEnd(num.toString(), digit: 3, pattern: ','); + } + + /// 每隔3三位加逗号 + /// num 数字或数字字符串。double型。 + static String formatDoubleComma3(Object num, + {int digit = 3, String pattern = ','}) { + List list = num.toString().split('.'); + String left = + formatDigitPatternEnd(list[0], digit: digit, pattern: pattern); + String right = list[1]; + return '$left.$right'; + } + + /// hideNumber + static String hideNumber(String phoneNo, + {int start = 3, int end = 7, String replacement = '****'}) { + return phoneNo.replaceRange(start, end, replacement); + } + + /// replace + static String replace(String text, Pattern from, String replace) { + return text.replaceAll(from, replace); + } + + /// split + static List split(String text, Pattern pattern) { + return text.split(pattern); + } + + /// reverse + static String reverse(String text) { + if (isEmpty(text)) return ''; + StringBuffer sb = StringBuffer(); + for (int i = text.length - 1; i >= 0; i--) { + sb.writeCharCode(text.codeUnitAt(i)); + } + return sb.toString(); + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_timeline.dart b/FlutterHelper/flutter_helper/lib/utils/util_timeline.dart new file mode 100644 index 00000000..b1b57bea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_timeline.dart @@ -0,0 +1,374 @@ +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Timeline Util. + * @Date: 2018/10/3 + */ + +import 'package:flutter_helper/utils/util_date.dart'; + +/// (xx)Configurable output. +/// (xx)为可配置输出. +enum DayFormat { + /// (less than 10s->just now)、x minutes、x hours、(Yesterday)、x days. + /// (小于10s->刚刚)、x分钟、x小时、(昨天)、x天. + Simple, + + /// (less than 10s->just now)、x minutes、x hours、[This year:(Yesterday/a day ago)、(two days age)、MM-dd ]、[past years: yyyy-MM-dd] + /// (小于10s->刚刚)、x分钟、x小时、[今年: (昨天/1天前)、(2天前)、MM-dd],[往年: yyyy-MM-dd]. + Common, + + /// 日期 + HH:mm + /// (less than 10s->just now)、x minutes、x hours、[This year:(Yesterday HH:mm/a day ago)、(two days age)、MM-dd HH:mm]、[past years: yyyy-MM-dd HH:mm] + /// 小于10s->刚刚)、x分钟、x小时、[今年: (昨天 HH:mm/1天前)、(2天前)、MM-dd HH:mm],[往年: yyyy-MM-dd HH:mm]. + Full, +} + +/// Timeline information configuration. +/// Timeline信息配置. +abstract class TimelineInfo { + String suffixAgo(); //suffix ago(后缀 后). + + String suffixAfter(); //suffix after(后缀 前). + + int maxJustNowSecond() => 30; // max just now second. + + String lessThanOneMinute() => ''; //just now(刚刚). + + String customYesterday() => ''; //Yesterday(昨天).优先级高于keepOneDay + + bool keepOneDay(); //保持1天,example: true -> 1天前, false -> MM-dd. + + bool keepTwoDays(); //保持2天,example: true -> 2天前, false -> MM-dd. + + String oneMinute(int minutes); //a minute(1分钟). + + String minutes(int minutes); //x minutes(x分钟). + + String anHour(int hours); //an hour(1小时). + + String hours(int hours); //x hours(x小时). + + String oneDay(int days); //a day(1天). + + String weeks(int week) => ''; //x week(星期x). + + String days(int days); //x days(x天). + +} + +class ZhInfo implements TimelineInfo { + String suffixAgo() => '前'; + + String suffixAfter() => '后'; + + int maxJustNowSecond() => 30; + + String lessThanOneMinute() => '刚刚'; + + String customYesterday() => '昨天'; + + bool keepOneDay() => true; + + bool keepTwoDays() => true; + + String oneMinute(int minutes) => '$minutes分钟'; + + String minutes(int minutes) => '$minutes分钟'; + + String anHour(int hours) => '$hours小时'; + + String hours(int hours) => '$hours小时'; + + String oneDay(int days) => '$days天'; + + String weeks(int week) => ''; //x week(星期x). + + String days(int days) => '$days天'; +} + +class EnInfo implements TimelineInfo { + String suffixAgo() => ' ago'; + + String suffixAfter() => ' after'; + + int maxJustNowSecond() => 30; + + String lessThanOneMinute() => 'just now'; + + String customYesterday() => 'Yesterday'; + + bool keepOneDay() => true; + + bool keepTwoDays() => true; + + String oneMinute(int minutes) => 'a minute'; + + String minutes(int minutes) => '$minutes minutes'; + + String anHour(int hours) => 'an hour'; + + String hours(int hours) => '$hours hours'; + + String oneDay(int days) => 'a day'; + + String weeks(int week) => ''; //x week(星期x). + + String days(int days) => '$days days'; +} + +class ZhNormalInfo implements TimelineInfo { + String suffixAgo() => '前'; + + String suffixAfter() => '后'; + + int maxJustNowSecond() => 30; + + String lessThanOneMinute() => '刚刚'; + + String customYesterday() => '昨天'; + + bool keepOneDay() => true; + + bool keepTwoDays() => false; + + String oneMinute(int minutes) => '$minutes分钟'; + + String minutes(int minutes) => '$minutes分钟'; + + String anHour(int hours) => '$hours小时'; + + String hours(int hours) => '$hours小时'; + + String oneDay(int days) => '$days天'; + + String weeks(int week) => ''; //x week(星期x). + + String days(int days) => '$days天'; +} + +class EnNormalInfo implements TimelineInfo { + String suffixAgo() => ' ago'; + + String suffixAfter() => ' after'; + + int maxJustNowSecond() => 30; + + String lessThanOneMinute() => 'just now'; + + String customYesterday() => 'Yesterday'; + + bool keepOneDay() => true; + + bool keepTwoDays() => false; + + String oneMinute(int minutes) => 'a minute'; + + String minutes(int minutes) => '$minutes minutes'; + + String anHour(int hours) => 'an hour'; + + String hours(int hours) => '$hours hours'; + + String oneDay(int days) => 'a day'; + + String weeks(int week) => ''; //x week(星期x). + + String days(int days) => '$days days'; +} + +Map _timelineInfoMap = { + 'zh': ZhInfo(), + 'en': EnInfo(), + 'zh_normal': ZhNormalInfo(), //keepTwoDays() => false + 'en_normal': EnNormalInfo(), //keepTwoDays() => false +}; + +/// add custom configuration. +void setLocaleInfo(String locale, TimelineInfo timelineInfo) { + ArgumentError.checkNotNull(locale, '[locale] must not be null'); + ArgumentError.checkNotNull(timelineInfo, '[timelineInfo] must not be null'); + _timelineInfoMap[locale] = timelineInfo; +} + +/// TimelineUtil +class TimelineUtil { + /// format time by DateTime. + /// dateTime + /// locDateTime: current time or schedule time. + /// locale: output key. + static String formatByDateTime( + DateTime dateTime, { + DateTime locDateTime, + String locale, + DayFormat dayFormat, + }) { + return format( + dateTime.millisecondsSinceEpoch, + locTimeMs: locDateTime?.millisecondsSinceEpoch, + locale: locale, + dayFormat: dayFormat, + ); + } + + /// format time by millis. + /// dateTime : millis. + /// locDateTime: current time or schedule time. millis. + /// locale: output key. + static String format( + int ms, { + int locTimeMs, + String locale, + DayFormat dayFormat, + }) { + int _locTimeMs = locTimeMs ?? DateTime.now().millisecondsSinceEpoch; + String _locale = locale ?? 'en'; + TimelineInfo _info = _timelineInfoMap[_locale] ?? EnInfo(); + DayFormat _dayFormat = dayFormat ?? DayFormat.Common; + + int elapsed = _locTimeMs - ms; + String suffix; + if (elapsed < 0) { + suffix = _info.suffixAfter(); + // suffix after is empty. user just now. + if (suffix.isNotEmpty) { + elapsed = elapsed.abs(); + _dayFormat = DayFormat.Simple; + } else { + return _info.lessThanOneMinute(); + } + } else { + suffix = _info.suffixAgo(); + } + + String timeline; + if (_info.customYesterday().isNotEmpty && + DateUtil.isYesterdayByMs(ms, _locTimeMs)) { + return _getYesterday(ms, _info, _dayFormat); + } + + if (!DateUtil.yearIsEqualByMs(ms, _locTimeMs)) { + timeline = _getYear(ms, _dayFormat); + if (timeline.isNotEmpty) return timeline; + } + + final num seconds = elapsed / 1000; + final num minutes = seconds / 60; + final num hours = minutes / 60; + final num days = hours / 24; + + if (seconds < 90) { + timeline = _info.oneMinute(1); + if (suffix != _info.suffixAfter() && + _info.lessThanOneMinute().isNotEmpty && + seconds < _info.maxJustNowSecond()) { + timeline = _info.lessThanOneMinute(); + suffix = ''; + } + } else if (minutes < 60) { + timeline = _info.minutes(minutes.round()); + } else if (minutes < 90) { + timeline = _info.anHour(1); + } else if (hours < 24) { + timeline = _info.hours(hours.round()); + } else { + if ((days.round() == 1 && _info.keepOneDay() == true) || + (days.round() == 2 && _info.keepTwoDays() == true)) { + _dayFormat = DayFormat.Simple; + } + timeline = _formatDays(ms, days.round(), _info, _dayFormat); + suffix = (_dayFormat == DayFormat.Simple ? suffix : ''); + } + return timeline + suffix; + } + + /// Timeline like QQ. + /// + /// today (HH:mm) + /// yesterday (昨天;Yesterday) + /// this week (星期一,周一;Monday,Mon) + /// others (yyyy-MM-dd) + static String formatA( + int ms, { + int locMs, + String formatToday = 'HH:mm', + String format = 'yyyy-MM-dd', + String languageCode = 'en', + bool short = false, + }) { + int _locTimeMs = locMs ?? DateTime.now().millisecondsSinceEpoch; + int elapsed = _locTimeMs - ms; + if (elapsed < 0) { + return DateUtil.formatDateMs(ms, format: formatToday); + } + + if (DateUtil.isToday(ms, locMs: _locTimeMs)) { + return DateUtil.formatDateMs(ms, format: formatToday); + } + + if (DateUtil.isYesterdayByMs(ms, _locTimeMs)) { + return languageCode == 'zh' ? '昨天' : 'Yesterday'; + } + + if (DateUtil.isWeek(ms, locMs: _locTimeMs)) { + return DateUtil.getWeekdayByMs(ms, + languageCode: languageCode, short: short); + } + + return DateUtil.formatDateMs(ms, format: format); + } + + /// get Yesterday. + /// 获取昨天. + static String _getYesterday( + int ms, + TimelineInfo info, + DayFormat dayFormat, + ) { + return info.customYesterday() + + (dayFormat == DayFormat.Full + ? (' ' + DateUtil.formatDateMs(ms, format: 'HH:mm')) + : ''); + } + + /// get is not year info. + /// 获取非今年信息. + static String _getYear( + int ms, + DayFormat dayFormat, + ) { + if (dayFormat != DayFormat.Simple) { + return DateUtil.formatDateMs(ms, + format: (dayFormat == DayFormat.Common + ? 'yyyy-MM-dd' + : 'yyyy-MM-dd HH:mm')); + } + return ''; + } + + /// format Days. + static String _formatDays( + int ms, + num days, + TimelineInfo info, + DayFormat dayFormat, + ) { + String timeline; + switch (dayFormat) { + case DayFormat.Simple: + timeline = (days == 1 + ? info.customYesterday().isEmpty + ? info.oneDay(days.round()) + : info.days(2) + : info.days(days.round())); + break; + case DayFormat.Common: + timeline = DateUtil.formatDateMs(ms, format: 'MM-dd'); + break; + case DayFormat.Full: + timeline = DateUtil.formatDateMs(ms, format: 'MM-dd HH:mm'); + break; + } + return timeline; + } +} diff --git a/FlutterHelper/flutter_helper/lib/utils/util_timer.dart b/FlutterHelper/flutter_helper/lib/utils/util_timer.dart new file mode 100644 index 00000000..d5a1ebe6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/utils/util_timer.dart @@ -0,0 +1,119 @@ +import 'dart:async'; + +///timer callback.(millisUntilFinished 毫秒). +typedef void OnTimerTickCallback(int millisUntilFinished); + +/** + * @Author: Sky24n + * @GitHub: https://github.com/Sky24n + * @Description: Timer Util. + * @Date: 2018/9/28 + */ + +/// TimerUtil. +class TimerUtil { + TimerUtil( + {this.mInterval = Duration.millisecondsPerSecond, this.mTotalTime = 0}); + + /// Timer. + Timer _mTimer; + + /// Is Timer active. + /// Timer是否启动. + bool _isActive = false; + + /// Timer interval (unit millisecond,def: 1000 millisecond). + /// Timer间隔 单位毫秒,默认1000毫秒(1秒). + int mInterval; + + /// countdown totalTime. + /// 倒计时总时间 + int mTotalTime; //单位毫秒 + + OnTimerTickCallback _onTimerTickCallback; + + /// set Timer interval. (unit millisecond). + /// 设置Timer间隔. + void setInterval(int interval) { + if (interval <= 0) interval = Duration.millisecondsPerSecond; + mInterval = interval; + } + + /// set countdown totalTime. (unit millisecond). + /// 设置倒计时总时间. + void setTotalTime(int totalTime) { + if (totalTime <= 0) return; + mTotalTime = totalTime; + } + + /// start Timer. + /// 启动定时Timer. + void startTimer() { + if (_isActive || mInterval <= 0) return; + _isActive = true; + Duration duration = Duration(milliseconds: mInterval); + _doCallback(0); + _mTimer = Timer.periodic(duration, (Timer timer) { + _doCallback(timer.tick); + }); + } + + /// start countdown Timer. + /// 启动倒计时Timer. + void startCountDown() { + if (_isActive || mInterval <= 0 || mTotalTime <= 0) return; + _isActive = true; + Duration duration = Duration(milliseconds: mInterval); + _doCallback(mTotalTime); + _mTimer = Timer.periodic(duration, (Timer timer) { + int time = mTotalTime - mInterval; + mTotalTime = time; + if (time >= mInterval) { + _doCallback(time); + } else if (time == 0) { + _doCallback(time); + cancel(); + } else { + timer.cancel(); + Future.delayed(Duration(milliseconds: time), () { + mTotalTime = 0; + _doCallback(0); + cancel(); + }); + } + }); + } + + void _doCallback(int time) { + if (_onTimerTickCallback != null) { + _onTimerTickCallback(time); + } + } + + /// update countdown totalTime. + /// 重设倒计时总时间. + void updateTotalTime(int totalTime) { + cancel(); + mTotalTime = totalTime; + startCountDown(); + } + + /// timer is Active. + /// Timer是否启动. + bool isActive() { + return _isActive; + } + + /// Cancels the timer. + /// 取消计时器. + void cancel() { + _mTimer?.cancel(); + _mTimer = null; + _isActive = false; + } + + /// set timer callback. + void setOnTimerTickCallback(OnTimerTickCallback callback) { + _onTimerTickCallback = callback; + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a001_about_dialog.dart b/FlutterHelper/flutter_helper/lib/widgets/a001_about_dialog.dart new file mode 100644 index 00000000..4761d041 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a001_about_dialog.dart @@ -0,0 +1,247 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class DialogHomeApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: DialogHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class DialogHomePage extends StatefulWidget { + DialogHomePage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _DialogHomePageState createState() => _DialogHomePageState(); +} + +class _DialogHomePageState extends State { + int _counter = 0; + + void _incrementCounter() { + setState(() { + showSimpleDialog(); + _counter++; + }); + } + + // 显示第一个Dialog + void showAlertDialog() { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new AlertDialog( + title: Text("标题"), + //可滑动 + content: SingleChildScrollView( + child: ListBody( + children: [ + Text("内容1"), + Text("内容2"), + Text("内容1"), + Text("内容2"), + Text("内容2"), + ], + ), + ), + actions: [ + FlatButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text("确定")), + FlatButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text("取消")) + ], + ); + }); + } + + void showCupertinoAlertDialog() { + showDialog( + context: context, + // false = user must tap button, true = tap outside dialog + builder: (BuildContext dialogContext) { + return CupertinoAlertDialog( + title: Text('这是一个iOS风格的对话框'), + content: Column( + children: [ + SizedBox( + height: 10, + ), + Align( + child: Text('这是消息'), + ) + ], + ), + actions: [ + CupertinoDialogAction( + child: Text('取消'), + onPressed: () { + Navigator.pop(context); + print('取消'); + }, + ), + CupertinoDialogAction( + child: Text('确定'), + onPressed: () { + //Navigator.pop(context); + print('确定'); + }, + ), + ], + ); + }, + ); + } + + //属性说明如下: + // applicationIcon:应用程序的图标。 + // applicationName:应用程序名称。 + // applicationVersion:应用程序版本。 + // applicationLegalese:著作权(copyright)的提示。 + // children:位置如上图的红蓝绿色的位置。 + // http://laomengit.com/flutter/widgets/AboutDialog.html + void showAboutDialog2() { + showAboutDialog( + context: context, + applicationIcon: + Image.asset('images/bird.png', height: 100, width: 100), + applicationName: '应用程序', + applicationVersion: '1.0.0', + applicationLegalese: 'copyrith 老孟,一枚有态度的程序员', + children: [ + Container( + height: 30, + color: Colors.red, + ), + Container( + height: 30, + color: Colors.blue, + ), + Container( + height: 30, + color: Colors.green, + ), + ]); + } + + void showAboutDialog3() { + final TextStyle textStyle = Theme.of(context).textTheme.body1; + final List aboutBoxChildren = [ + SizedBox( + height: 24, + ), + RichText( + text: TextSpan(children: [ + TextSpan( + style: textStyle, + text: 'Flutter is Google’s UI toolkit for building beautiful, ' + 'natively compiled applications for mobile, web, and desktop ' + 'from a single codebase. Learn more about Flutter at '), + TextSpan( + style: textStyle.copyWith(color: Theme.of(context).accentColor), + text: 'https://flutter.dev'), + TextSpan(style: textStyle, text: '.'), + ]), + ) + ]; + var aboutListTile = AboutListTile( + icon: FlutterLogo(), + child: Text('About 老孟程序员'), + applicationName: '老孟程序员', + applicationVersion: 'V1.0.0', + applicationIcon: FlutterLogo(), + applicationLegalese: '专注分享Flutter相关内容', + aboutBoxChildren: aboutBoxChildren, + dense: false, + ); + showDialog( + context: context, + builder: (BuildContext context) { + return Scaffold(); + }); + } + + // SimpleDialog + void showSimpleDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return SimpleDialog( + title: Text('选择'), + children: [ + SimpleDialogOption( + child: Text('showAlertDialog'), + onPressed: () { + Navigator.of(context).pop(); + showAlertDialog(); + }, + ), + SimpleDialogOption( + child: Text('showCupertinoAlertDialog'), + onPressed: () { + Navigator.of(context).pop(); + showCupertinoAlertDialog(); + }, + ), + SimpleDialogOption( + child: Text('showAboutDialog2()'), + onPressed: () { + Navigator.of(context).pop(); + showAboutDialog2(); + }, + ), + SimpleDialogOption( + child: Text('showAboutDialog3()'), + onPressed: () { + Navigator.of(context).pop(); + showAboutDialog3(); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'You have pushed the button this many times:', + ), + Text( + '$_counter', + style: Theme.of(context).textTheme.headline4, + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: Icon(Icons.add), + ), // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a002_about_list_tile.dart b/FlutterHelper/flutter_helper/lib/widgets/a002_about_list_tile.dart new file mode 100644 index 00000000..d51d1035 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a002_about_list_tile.dart @@ -0,0 +1,194 @@ +/// Flutter code sample for AboutListTile + +// This sample shows two ways to open [AboutDialog]. The first one +// uses an [AboutListTile], and the second uses the [showAboutDialog] function. + +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/HighIconButton.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/hightlight/syntax_highlight.dart'; + +// void main() => runApp(const MyApp()); + +/// This is the main application widget. +class AboutListTileApp extends StatelessWidget with HighMixin{ + const AboutListTileApp({key}) : super(key: key); + + static const String _title = 'Flutter Code Sample'; + + @override + Widget build(BuildContext context) { + return const MaterialApp( + title: _title, + home: MyStatelessWidget(), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/HighIconButton.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/hightlight/syntax_highlight.dart'; + +// void main() => runApp(const MyApp()); + +/// This is the main application widget. +class AboutListTileApp extends StatelessWidget with Highlight{ + const AboutListTileApp({key}) : super(key: key); + + static const String _title = 'Flutter Code Sample'; + + @override + Widget build(BuildContext context) { + return const MaterialApp( + title: _title, + home: MyStatelessWidget(), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ + + """ + ); +} + +/// This is the stateless widget that the main application instantiates. +class MyStatelessWidget extends StatelessWidget { + const MyStatelessWidget({key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final TextStyle textStyle = theme.textTheme.bodyText2; + final List aboutBoxChildren = [ + const SizedBox(height: 24), + RichText( + text: TextSpan( + children: [ + TextSpan( + style: textStyle, + text: "Flutter is Google's UI toolkit for building beautiful, " + 'natively compiled applications for mobile, web, and desktop ' + 'from a single codebase. Learn more about Flutter at '), + TextSpan( + style: textStyle.copyWith(color: theme.colorScheme.primary), + text: 'https://flutter.dev'), + TextSpan(style: textStyle, text: '.'), + ], + ), + ), + ]; + + return Scaffold( + appBar: AppBar( + title: const Text('Show About Example'), + actions: [ + HightIconButton(), + ], + ), + drawer: Drawer( + child: SingleChildScrollView( + child: SafeArea( + child: AboutListTile( + icon: const Icon(Icons.info), + applicationIcon: const FlutterLogo(), + applicationName: 'Show About Example', + applicationVersion: 'August 2019', + applicationLegalese: '\u{a9} 2014 The Flutter Authors', + aboutBoxChildren: aboutBoxChildren, + ), + ), + ), + ), + body: Center( + child: ElevatedButton( + child: const Text('Show About Example'), + onPressed: () { + showAboutDialog( + context: context, + applicationIcon: const FlutterLogo(), + applicationName: 'Show About Example', + applicationVersion: 'August 2019', + applicationLegalese: '\u{a9} 2014 The Flutter Authors', + children: aboutBoxChildren, + ); + }, + ), + ), + ); + } +} + """ + ); +} + +/// This is the stateless widget that the main application instantiates. +class MyStatelessWidget extends StatelessWidget { + const MyStatelessWidget({key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final TextStyle textStyle = theme.textTheme.bodyText2; + final List aboutBoxChildren = [ + const SizedBox(height: 24), + RichText( + text: TextSpan( + children: [ + TextSpan( + style: textStyle, + text: "Flutter is Google's UI toolkit for building beautiful, " + 'natively compiled applications for mobile, web, and desktop ' + 'from a single codebase. Learn more about Flutter at '), + TextSpan( + style: textStyle.copyWith(color: theme.colorScheme.primary), + text: 'https://flutter.dev'), + TextSpan(style: textStyle, text: '.'), + ], + ), + ), + ]; + + return Scaffold( + appBar: AppBar( + title: const Text('Show About Example'), + actions: [ + HightIconButton(), + ], + ), + drawer: Drawer( + child: SingleChildScrollView( + child: SafeArea( + child: AboutListTile( + icon: const Icon(Icons.info), + applicationIcon: const FlutterLogo(), + applicationName: 'Show About Example', + applicationVersion: 'August 2019', + applicationLegalese: '\u{a9} 2014 The Flutter Authors', + aboutBoxChildren: aboutBoxChildren, + ), + ), + ), + ), + body: Center( + child: ElevatedButton( + child: const Text('Show About Example'), + onPressed: () { + showAboutDialog( + context: context, + applicationIcon: const FlutterLogo(), + applicationName: 'Show About Example', + applicationVersion: 'August 2019', + applicationLegalese: '\u{a9} 2014 The Flutter Authors', + children: aboutBoxChildren, + ); + }, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a003_absorbpointer.dart b/FlutterHelper/flutter_helper/lib/widgets/a003_absorbpointer.dart new file mode 100644 index 00000000..a2816240 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a003_absorbpointer.dart @@ -0,0 +1,128 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +/// This is them application widgets +class AbsorbPointerApp extends StatelessWidget with HighMixin{ + AbsorbPointerApp({key}) : super(key: key) {} + + @override + Widget build(BuildContext context) { + String _title = 'Flutter Code Sample'; + return MaterialApp( + title: _title, + home: Scaffold( + appBar: AppBar( + title: Text(_title), + ), + body: const Center( + child: MyStatelessWidget(), + ), + ), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ + /// This is them application widgets +class AbsorbPointerApp extends StatelessWidget with Highlight{ + AbsorbPointerApp({key}) : super(key: key) {} + + @override + Widget build(BuildContext context) { + String _title = 'Flutter Code Sample'; + return MaterialApp( + title: _title, + home: Scaffold( + appBar: AppBar( + title: Text(_title), + ), + body: const Center( + child: MyStatelessWidget(), + ), + ), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ + + """ + ); +} + +class MyStatelessWidget extends StatelessWidget { + const MyStatelessWidget({key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Stack( + alignment: AlignmentDirectional.center, + children: [ + SizedBox( + width: 200.0, + height: 100.0, + child: ElevatedButton( + onPressed: () {}, + child: null, + ), + ), + SizedBox( + width: 100.0, + height: 200.0, + child: AbsorbPointer( + absorbing: true, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + primary: Colors.blue.shade200, + ), + onPressed: () {}, + child: null, + ), + ), + ), + ], + ); + } +} + + """ + ); +} + +class MyStatelessWidget extends StatelessWidget { + const MyStatelessWidget({key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Stack( + alignment: AlignmentDirectional.center, + children: [ + SizedBox( + width: 200.0, + height: 100.0, + child: ElevatedButton( + onPressed: () {}, + child: null, + ), + ), + SizedBox( + width: 100.0, + height: 200.0, + child: AbsorbPointer( + absorbing: true, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + primary: Colors.blue.shade200, + ), + onPressed: () {}, + child: null, + ), + ), + ), + ], + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a004_actionchip.dart b/FlutterHelper/flutter_helper/lib/widgets/a004_actionchip.dart new file mode 100644 index 00000000..e1ce654c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a004_actionchip.dart @@ -0,0 +1,291 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +/// http://laomengit.com/flutter/widgets/Chip.html#actionchip +/// This is them application widgets +class ActionChipApp extends StatelessWidget with HighMixin{ + ActionChipApp({key}) : super(key: key) {} + + @override + Widget build(BuildContext context) { + String _title = 'Flutter Code Sample'; + return MaterialApp( + title: _title, + home: Scaffold( + appBar: AppBar( + title: Text(_title), + ), + body: const Center( + child: MyStatelessWidget(), + ), + ), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ + class ActionChipApp extends StatelessWidget with Highlight{ + ActionChipApp({key}) : super(key: key) {} + + @override + Widget build(BuildContext context) { + String _title = 'Flutter Code Sample'; + return MaterialApp( + title: _title, + home: Scaffold( + appBar: AppBar( + title: Text(_title), + ), + body: const Center( + child: MyStatelessWidget(), + ), + ), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ + """); +} + +class MyStatelessWidget extends StatelessWidget { + const MyStatelessWidget({key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scrollbar( + child: SingleChildScrollView( + child: Column( + children: [ + RawChip( + label: Text('老孟'), + ), + RawChip( + label: Text('老孟禁用'), + isEnabled: false, + ), + RawChip( + avatar: CircleAvatar( + child: Text('孟'), + ), + label: Text('老孟'), + ), + RawChip( + label: Text('老孟'), + labelStyle: TextStyle(color: Colors.blue), + labelPadding: EdgeInsets.symmetric(horizontal: 100 /*左右间距*/), + ), + RawChip( + label: Text('老孟'), + onDeleted: () { + print('onDeleted'); + }, + deleteIcon: Icon(Icons.delete), + deleteIconColor: Colors.red, + deleteButtonTooltipMessage: '删除', + ), + RawChip( + label: Text('老孟'), + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + backgroundColor: Colors.blue, + padding: EdgeInsets.symmetric(vertical: 10), + ), + RawChip( + label: Text('老孟'), + elevation: 8, + shadowColor: Colors.blue, + ), +//bool _selected = false; +// RawChip( +// label: Text('老孟'), +// selected: _selected, +// onSelected: (v){ +// setState(() { +// _selected = v; +// }); +// }, +// selectedColor: Colors.blue, +// selectedShadowColor: Colors.red, +// ) +// + RawChip( + label: Text('老孟'), + selected: true, + showCheckmark: true, + checkmarkColor: Colors.red, + ), + RawChip( + label: Text('老孟'), + onPressed: () { + print('onPressed'); + }, + pressElevation: 12, + ), + Wrap( + spacing: 15, + children: [ + ChoiceChip(label: Text('老孟 0'), selected: false), + ChoiceChip(label: Text('老孟 1'), selected: false), + ChoiceChip(label: Text('老孟 2'), selected: false), + ChoiceChip(label: Text('老孟 3'), selected: false), + ChoiceChip(label: Text('老孟 4'), selected: false), + ChoiceChip(label: Text('老孟 5'), selected: false), + ChoiceChip(label: Text('老孟 6'), selected: false), + ChoiceChip(label: Text('老孟 7'), selected: false), + ], + ), + Column( + children: [ + Wrap( + children: [ + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + ], + ), + Text('选中:1'), + ], + ), + ActionChip( + avatar: CircleAvatar( + backgroundColor: Colors.grey.shade800, + child: Text('孟'), + ), + label: Text('老孟'), + onPressed: () { + print("onPressed"); + }) + ], + ), + )); + } +} + + """); +} + +class MyStatelessWidget extends StatelessWidget { + const MyStatelessWidget({key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scrollbar( + child: SingleChildScrollView( + child: Column( + children: [ + RawChip( + label: Text('老孟'), + ), + RawChip( + label: Text('老孟禁用'), + isEnabled: false, + ), + RawChip( + avatar: CircleAvatar( + child: Text('孟'), + ), + label: Text('老孟'), + ), + RawChip( + label: Text('老孟'), + labelStyle: TextStyle(color: Colors.blue), + labelPadding: EdgeInsets.symmetric(horizontal: 100 /*左右间距*/), + ), + RawChip( + label: Text('老孟'), + onDeleted: () { + print('onDeleted'); + }, + deleteIcon: Icon(Icons.delete), + deleteIconColor: Colors.red, + deleteButtonTooltipMessage: '删除', + ), + RawChip( + label: Text('老孟'), + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + backgroundColor: Colors.blue, + padding: EdgeInsets.symmetric(vertical: 10), + ), + RawChip( + label: Text('老孟'), + elevation: 8, + shadowColor: Colors.blue, + ), +//bool _selected = false; +// RawChip( +// label: Text('老孟'), +// selected: _selected, +// onSelected: (v){ +// setState(() { +// _selected = v; +// }); +// }, +// selectedColor: Colors.blue, +// selectedShadowColor: Colors.red, +// ) +// + RawChip( + label: Text('老孟'), + selected: true, + showCheckmark: true, + checkmarkColor: Colors.red, + ), + RawChip( + label: Text('老孟'), + onPressed: () { + print('onPressed'); + }, + pressElevation: 12, + ), + Wrap( + spacing: 15, + children: [ + ChoiceChip(label: Text('老孟 0'), selected: false), + ChoiceChip(label: Text('老孟 1'), selected: false), + ChoiceChip(label: Text('老孟 2'), selected: false), + ChoiceChip(label: Text('老孟 3'), selected: false), + ChoiceChip(label: Text('老孟 4'), selected: false), + ChoiceChip(label: Text('老孟 5'), selected: false), + ChoiceChip(label: Text('老孟 6'), selected: false), + ChoiceChip(label: Text('老孟 7'), selected: false), + ], + ), + Column( + children: [ + Wrap( + children: [ + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + FilterChip(label: Text("zj 1"), onSelected: (v) {}), + ], + ), + Text('选中:1'), + ], + ), + ActionChip( + avatar: CircleAvatar( + backgroundColor: Colors.grey.shade800, + child: Text('孟'), + ), + label: Text('老孟'), + onPressed: () { + print("onPressed"); + }) + ], + ), + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a005_alertdialog.dart b/FlutterHelper/flutter_helper/lib/widgets/a005_alertdialog.dart new file mode 100644 index 00000000..10f59cea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a005_alertdialog.dart @@ -0,0 +1,512 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class AlertDialogApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: AlertDialogPage(title: 'Flutter Demo Home Page'), + ); + } + + @override + High getHigh() => High( + toStringShort(), + """ +class AlertDialogApp extends StatelessWidget with Highlight{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: AlertDialogPage(title: 'Flutter Demo Home Page'), + ); + } + + @override + High getHigh() => High( + toStringShort(), + """ + """ + ); +} + +class AlertDialogPage extends StatefulWidget { + AlertDialogPage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _DialogHomePageState createState() => _DialogHomePageState(); +} + +class _DialogHomePageState extends State { + int _counter = 0; + + void _incrementCounter() { + setState(() { + showSimpleDialog(); + _counter++; + }); + } + + void showAlertDialog1() { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text('显示'), + content: Text('确认删除吗?'), + actions: [ + FlatButton(onPressed: () {}, child: Text('取消')), + FlatButton(onPressed: () {}, child: Text('确认')), + ], + ); + }); + } + + void showAlertDialog2() { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text('显示'), + content: Text('确认删除吗?'), + backgroundColor: Colors.lightBlueAccent, + elevation: 24, + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)), + actions: [ + FlatButton(onPressed: () {}, child: Text('取消')), + FlatButton(onPressed: () {}, child: Text('确认')), + ], + ); + }); + } + + void showAlertDialog3() async { + var result = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text('显示'), + content: Text('确认删除吗?'), + backgroundColor: Colors.lightBlueAccent, + elevation: 24, + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)), + actions: [ + FlatButton( + onPressed: () { + Navigator.of(context).pop('cancel'); + }, + child: Text('取消')), + FlatButton( + onPressed: () { + Navigator.of(context).pop('ok'); + }, + child: Text('确认')), + ], + ); + }); + print("the result is "); + } + + void showCupertinoAlertDialog() { + showCupertinoDialog( + context: context, + builder: (context) { + return CupertinoAlertDialog( + title: Text('显示'), + content: Text('确认删除吗?'), + actions: [ + CupertinoDialogAction( + child: Text('取消'), + onPressed: () {}, + ), + CupertinoDialogAction( + child: Text('确认'), + onPressed: () {}, + ), + ], + ); + }); + } + + // http://laomengit.com/flutter/widgets/Dialog.html + void showSimpleDialog___() { + SimpleDialog( + title: Text('提示'), + children: [ + Container( + height: 80, + alignment: Alignment.center, + + child: Text('确认删除吗?'), + ), + Divider(height: 1,), + FlatButton( + child: Text('取消'), + onPressed: () { + Navigator.of(context).pop('cancel'); + }, + ), + Divider(height: 1,), + FlatButton( + child: Text('确认'), + onPressed: () { + Navigator.of(context).pop('ok'); + }, + ), + ], + ); + + // SimpleDialog( + // title: Text('提示'), + // children: [ + // Container( + // height: 80, + // alignment: Alignment.center, + // child: Text('确认删除吗?'), + // ), + // Divider( + // height: 1, + // ), + // FlatButton( + // onPressed: () { + // Navigator.of(context).pop('cancel'); + // }, + // child: Text('取消')), + // Divider( + // height: 1, + // ), + // FlatButton(onPressed: () {}, child: Text('确认')), + // ], + // ); + } + + // SimpleDialog + void showSimpleDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return SimpleDialog( + title: Text('选择'), + children: [ + SimpleDialogOption( + child: Text('showAlertDialog1'), + onPressed: () { + Navigator.of(context).pop(); + showAlertDialog1(); + }, + ), + SimpleDialogOption( + child: Text('showAlertDialog2'), + onPressed: () { + Navigator.of(context).pop(); + showAlertDialog2(); + }, + ), + SimpleDialogOption( + child: Text('showAlertDialog3'), + onPressed: () async { + // 等待结果 + //Navigator.of(context).pop(); + showAlertDialog3(); + }, + ), + SimpleDialogOption( + child: Text('showCupertinoAlertDialog'), + onPressed: () { + // 等待结果 + //Navigator.of(context).pop(); + showCupertinoAlertDialog(); + }, + ), + SimpleDialogOption( + child: Text('showSimpleDialog___'), + onPressed: () { + // 等待结果 + //Navigator.of(context).pop(); + showSimpleDialog___(); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'You have pushed the button this many times:', + ), + Text(, + style: Theme.of(context).textTheme.headline4, + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: Icon(Icons.add), + ), // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} + + """ + ); +} + +class AlertDialogPage extends StatefulWidget { + AlertDialogPage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _DialogHomePageState createState() => _DialogHomePageState(); +} + +class _DialogHomePageState extends State { + int _counter = 0; + + void _incrementCounter() { + setState(() { + showSimpleDialog(); + _counter++; + }); + } + + void showAlertDialog1() { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text('显示'), + content: Text('确认删除吗?'), + actions: [ + FlatButton(onPressed: () {}, child: Text('取消')), + FlatButton(onPressed: () {}, child: Text('确认')), + ], + ); + }); + } + + void showAlertDialog2() { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text('显示'), + content: Text('确认删除吗?'), + backgroundColor: Colors.lightBlueAccent, + elevation: 24, + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)), + actions: [ + FlatButton(onPressed: () {}, child: Text('取消')), + FlatButton(onPressed: () {}, child: Text('确认')), + ], + ); + }); + } + + void showAlertDialog3() async { + var result = await showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text('显示'), + content: Text('确认删除吗?'), + backgroundColor: Colors.lightBlueAccent, + elevation: 24, + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(50)), + actions: [ + FlatButton( + onPressed: () { + Navigator.of(context).pop('cancel'); + }, + child: Text('取消')), + FlatButton( + onPressed: () { + Navigator.of(context).pop('ok'); + }, + child: Text('确认')), + ], + ); + }); + print("the result is $result"); + } + + void showCupertinoAlertDialog() { + showCupertinoDialog( + context: context, + builder: (context) { + return CupertinoAlertDialog( + title: Text('显示'), + content: Text('确认删除吗?'), + actions: [ + CupertinoDialogAction( + child: Text('取消'), + onPressed: () {}, + ), + CupertinoDialogAction( + child: Text('确认'), + onPressed: () {}, + ), + ], + ); + }); + } + + // http://laomengit.com/flutter/widgets/Dialog.html + void showSimpleDialog___() { + SimpleDialog( + title: Text('提示'), + children: [ + Container( + height: 80, + alignment: Alignment.center, + + child: Text('确认删除吗?'), + ), + Divider(height: 1,), + FlatButton( + child: Text('取消'), + onPressed: () { + Navigator.of(context).pop('cancel'); + }, + ), + Divider(height: 1,), + FlatButton( + child: Text('确认'), + onPressed: () { + Navigator.of(context).pop('ok'); + }, + ), + ], + ); + + // SimpleDialog( + // title: Text('提示'), + // children: [ + // Container( + // height: 80, + // alignment: Alignment.center, + // child: Text('确认删除吗?'), + // ), + // Divider( + // height: 1, + // ), + // FlatButton( + // onPressed: () { + // Navigator.of(context).pop('cancel'); + // }, + // child: Text('取消')), + // Divider( + // height: 1, + // ), + // FlatButton(onPressed: () {}, child: Text('确认')), + // ], + // ); + } + + // SimpleDialog + void showSimpleDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return SimpleDialog( + title: Text('选择'), + children: [ + SimpleDialogOption( + child: Text('showAlertDialog1'), + onPressed: () { + Navigator.of(context).pop(); + showAlertDialog1(); + }, + ), + SimpleDialogOption( + child: Text('showAlertDialog2'), + onPressed: () { + Navigator.of(context).pop(); + showAlertDialog2(); + }, + ), + SimpleDialogOption( + child: Text('showAlertDialog3'), + onPressed: () async { + // 等待结果 + //Navigator.of(context).pop(); + showAlertDialog3(); + }, + ), + SimpleDialogOption( + child: Text('showCupertinoAlertDialog'), + onPressed: () { + // 等待结果 + //Navigator.of(context).pop(); + showCupertinoAlertDialog(); + }, + ), + SimpleDialogOption( + child: Text('showSimpleDialog___'), + onPressed: () { + // 等待结果 + //Navigator.of(context).pop(); + showSimpleDialog___(); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'You have pushed the button this many times:', + ), + Text( + '$_counter', + style: Theme.of(context).textTheme.headline4, + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: Icon(Icons.add), + ), // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a006_align.dart b/FlutterHelper/flutter_helper/lib/widgets/a006_align.dart new file mode 100644 index 00000000..f68cebe8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a006_align.dart @@ -0,0 +1,503 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class AlignApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: AlignPage(), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class AlignApp extends StatelessWidget with Highlight{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: AlignPage(), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ + + """ + ); +} + +class AlignPage extends StatefulWidget { + @override + State createState() => AlignPageState(); +} + +class AlignPageState extends State + with SingleTickerProviderStateMixin { + AnimationController _animationController; + Animation _animation; + + var _alignment = Alignment.topLeft; + + @override + void initState() { + _animationController = + AnimationController(duration: Duration(seconds: 10), vsync: this); + _animation = Tween( + begin: Alignment.topLeft, end: Alignment.bottomRight) + .animate(_animationController); + //开始动画 + _animationController.forward(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Zhaojian"), + ), + body: Center( + child: Scrollbar( + child: SingleChildScrollView( + //physics: ClampingScrollPhysics(), + physics: AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Container( + width: 200, + height: 200, + color: Colors.black12, + // http://laomengit.com/flutter/widgets/AnimatedAlign.html + child: AnimatedAlign( + onEnd: () { + print('onEnd'); + }, + curve: Curves.bounceInOut, + alignment: _alignment, + duration: Duration(seconds: 10), + child: IconButton( + icon: Icon( + Icons.print, + color: Colors.red, + size: 30, + ), + onPressed: () { + setState(() { + _alignment = Alignment.bottomRight; + }); + }), + ), + ), + Divider( + height: 1, + ), + Container( + height: 200, + width: 200, + color: Colors.blue, + child: AlignTransition( + alignment: _animation, + child: Container( + height: 30, + width: 30, + color: Colors.red, + ), + ), + ), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + child: Align( + alignment: Alignment.topLeft, + widthFactor: 2, + heightFactor: 2, + child: Container( + height: 50, + width: 50, + color: Colors.red, + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.topLeft, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.topCenter, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.topRight, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.center, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.centerRight, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.bottomLeft, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.bottomCenter, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.bottomRight, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )) + ], + ), + ), + )), + ); + } +} + + """ + ); +} + +class AlignPage extends StatefulWidget { + @override + State createState() => AlignPageState(); +} + +class AlignPageState extends State + with SingleTickerProviderStateMixin { + AnimationController _animationController; + Animation _animation; + + var _alignment = Alignment.topLeft; + + @override + void initState() { + _animationController = + AnimationController(duration: Duration(seconds: 10), vsync: this); + _animation = Tween( + begin: Alignment.topLeft, end: Alignment.bottomRight) + .animate(_animationController); + //开始动画 + _animationController.forward(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + print("$_animation"); + return Scaffold( + appBar: AppBar( + title: Text("Zhaojian"), + ), + body: Center( + child: Scrollbar( + child: SingleChildScrollView( + //physics: ClampingScrollPhysics(), + physics: AlwaysScrollableScrollPhysics(), + child: Column( + children: [ + Container( + width: 200, + height: 200, + color: Colors.black12, + // http://laomengit.com/flutter/widgets/AnimatedAlign.html + child: AnimatedAlign( + onEnd: () { + print('onEnd'); + }, + curve: Curves.bounceInOut, + alignment: _alignment, + duration: Duration(seconds: 10), + child: IconButton( + icon: Icon( + Icons.print, + color: Colors.red, + size: 30, + ), + onPressed: () { + setState(() { + _alignment = Alignment.bottomRight; + }); + }), + ), + ), + Divider( + height: 1, + ), + Container( + height: 200, + width: 200, + color: Colors.blue, + child: AlignTransition( + alignment: _animation, + child: Container( + height: 30, + width: 30, + color: Colors.red, + ), + ), + ), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + child: Align( + alignment: Alignment.topLeft, + widthFactor: 2, + heightFactor: 2, + child: Container( + height: 50, + width: 50, + color: Colors.red, + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.topLeft, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.topCenter, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.topRight, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.center, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.centerRight, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.bottomLeft, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.bottomCenter, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )), + Divider( + height: 1, + ), + Container( + color: Colors.lightBlue, + width: 100, + height: 100, + child: Align( + alignment: Alignment.bottomRight, + child: Text( + 'AA', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + )) + ], + ), + ), + )), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a007_aniatedbuilder.dart b/FlutterHelper/flutter_helper/lib/widgets/a007_aniatedbuilder.dart new file mode 100644 index 00000000..617a5ce7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a007_aniatedbuilder.dart @@ -0,0 +1,80 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class AnimatedBuilderApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + //return Test(); + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: Test(), + ); + } +} + +class Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State with TickerProviderStateMixin { + AnimationController _animationController; + Animation _animation; + + @override + void initState() { + _animationController = AnimationController( + duration: Duration(seconds: 10), + vsync: this, + )..addStatusListener((status) { + if (status == AnimationStatus.completed) { + _animationController.reverse(); + } else if (status == AnimationStatus.dismissed) { + _animationController.forward(); + } + }); + _animation = Tween(begin: 0.0, end: 2.0 * pi).animate(_animationController); + // 开始动画 + _animationController.forward(); + super.initState(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("zhaojan"), + ), + body: AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return Transform.rotate( + angle: _animation.value, + child: child, + ); + }, + child: FlutterLogo( + size: 60, + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () {}, + child: Text('h'), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a008_animated_container.dart b/FlutterHelper/flutter_helper/lib/widgets/a008_animated_container.dart new file mode 100644 index 00000000..bdb710cb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a008_animated_container.dart @@ -0,0 +1,49 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +/// http://laomengit.com/flutter/widgets/AnimatedContainer.html +class AnimatedContainerApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter APP", + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> { + bool click = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text("zhaojian"),), + body: Center( + child: GestureDetector( + onTap: () { + setState(() { + click = !click; + }); + }, + child: AnimatedContainer( + height: click ? 200 : 100, + width: click ? 200 : 100, + color: Colors.green, + duration: Duration(seconds: 1), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a009_animated_crossfade.dart b/FlutterHelper/flutter_helper/lib/widgets/a009_animated_crossfade.dart new file mode 100644 index 00000000..d801e84c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a009_animated_crossfade.dart @@ -0,0 +1,76 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// http://laomengit.com/flutter/widgets/AnimatedContainer.html +class AnimatedCrossFadeApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter APP", + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> { + bool _showFirst = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("zhaojian"), + ), + body: Center( + child: AnimatedCrossFade( + firstChild: Container( + width: 150, + height: 150, + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.blue, + ), + child: Text( + 'first child', + style: TextStyle(color: Colors.white), + ), + ), + secondChild: Container( + width: 150, + height: 150, + alignment: Alignment.center, + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.orange, + borderRadius: BorderRadius.circular(20), + ), + child: Text( + 'second child', + style: TextStyle(color: Colors.white), + ), + ), + crossFadeState: _showFirst + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + duration: Duration(seconds: 1)), + ), + floatingActionButton: FloatingActionButton(onPressed: () { + setState(() { + _showFirst = !_showFirst; + }); + }), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a010_animate_default_textstyle.dart b/FlutterHelper/flutter_helper/lib/widgets/a010_animate_default_textstyle.dart new file mode 100644 index 00000000..a3268f3e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a010_animate_default_textstyle.dart @@ -0,0 +1,68 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + + +///http://laomengit.com/flutter/widgets/AnimatedDefaultTextStyle.html#animateddefaulttextstyle +class AnimatedDefaultTextStyleApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + TextStyle _style; + + @override + void initState() { + _style = TextStyle(color: Colors.blue, fontSize: 14); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("FFFFFF"), + ), + body: Column( + children: [ + SizedBox( + height: 200, + ), + AnimatedDefaultTextStyle( + child: Text('老孟'), + style: _style, + duration: Duration(seconds: 1), + ), + SizedBox( + height: 100, + ), + RaisedButton(onPressed: () { + setState(() { + if (_style.fontSize == 42) { + _style = TextStyle(color: Colors.red, fontSize: 14); + } else { + _style = TextStyle(color: Colors.red, fontSize: 42); + } + }); + }), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a011_animate_icon.dart b/FlutterHelper/flutter_helper/lib/widgets/a011_animate_icon.dart new file mode 100644 index 00000000..e1e95990 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a011_animate_icon.dart @@ -0,0 +1,73 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + + +///http://laomengit.com/flutter/widgets/AnimatedIcon.html +class AnimatedIconApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with TickerProviderStateMixin { + //TextStyle _style; + AnimationController _animationController; + + @override + void initState() { + //_style = TextStyle(color: Colors.blue, fontSize: 14); + _animationController = AnimationController( + duration: Duration(seconds: 1), + vsync: this, + ) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + _animationController.reverse(); + } else if (status == AnimationStatus.dismissed) { + _animationController.forward(); + } + }); + _animationController.forward(); + super.initState(); + } + + @override + void dispose() { + // double: implement dispose + super.dispose(); + _animationController.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("FFFFFF"), + ), + body: Container( + height: 100, + width: 100, + alignment: Alignment.center, + child: AnimatedIcon( + icon: AnimatedIcons.view_list, + progress: _animationController, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a012_animate_list.dart b/FlutterHelper/flutter_helper/lib/widgets/a012_animate_list.dart new file mode 100644 index 00000000..e52aa670 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a012_animate_list.dart @@ -0,0 +1,107 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedIcon.html +class AnimatedListApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + List _list = []; + final GlobalKey _listKey = GlobalKey(); + + void _addItem() { + final int _index = _list.length; + _list.insert(_index, _index); + _listKey.currentState.insertItem(_index); + } + + void _removeItem() { + final int _index = _list.length - 1; + var item = _list[_index].toString(); + _listKey.currentState.removeItem( + _index, (context, animation) => _buildItem(item, animation)); + _list.removeAt(_index); + } + + Widget _buildItem(String _item, Animation _animation) { + if (true) + return _buildItem2(_item, _animation); + else + return SlideTransition( + position: _animation + .drive( + CurveTween(curve: Curves.easeIn), + ) + .drive(Tween(begin: Offset(1, 1), end: Offset(0, 1))), + child: Card( + child: ListTile( + title: Text(_item), + ), + ), + ); + } + + Widget _buildItem2(String _item, Animation _animation) { + return SizeTransition( + sizeFactor: _animation, + child: Card( + child: ListTile( + title: Text(_item), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("FFFFFF"), + ), + body: AnimatedList( + key: _listKey, + initialItemCount: _list.length, + itemBuilder: (context, index, animation) { + return _buildItem(_list[index].toString(), animation); + }, + ), + floatingActionButton: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + FloatingActionButton( + onPressed: () { + _addItem(); + }, + child: Icon(Icons.add), + ), + SizedBox( + width: 60, + ), + FloatingActionButton( + onPressed: () => _removeItem(), + child: Icon(Icons.remove), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a013_animate_modalbarrier.dart b/FlutterHelper/flutter_helper/lib/widgets/a013_animate_modalbarrier.dart new file mode 100644 index 00000000..c3798ee1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a013_animate_modalbarrier.dart @@ -0,0 +1,68 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AnimatedModalBarrierApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + AnimationController _animationController; + Animation _animation; + + @override + void initState() { + _animationController = + AnimationController(duration: Duration(seconds: 2), vsync: this) + ..addStatusListener((status) { + if(status == AnimationStatus.completed) + _animationController.reverse(); + else if(status == AnimationStatus.dismissed) + _animationController.forward(); + }); + + _animation = ColorTween( + begin: Colors.red, + end: Colors.blue, + ).animate(_animationController); + + _animationController.forward(); + super.initState(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: Container( + height: 100, + width: 100, + child: AnimatedModalBarrier( + color: _animation, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a014_animate_opacity.dart b/FlutterHelper/flutter_helper/lib/widgets/a014_animate_opacity.dart new file mode 100644 index 00000000..4f76d1b8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a014_animate_opacity.dart @@ -0,0 +1,71 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AnimatedOpacityApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _opacity = 1.0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Center( + child: Container( + child: AnimatedOpacity( + opacity: _opacity, + duration: Duration(seconds: 2), + child: Container( + height: 60, + width: 150, + color: Colors.blue, + ), + ), + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() { + if (_opacity == 0) { + _opacity = 1.0; + } else { + _opacity = 0; + } + }); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a015_animate_padding.dart b/FlutterHelper/flutter_helper/lib/widgets/a015_animate_padding.dart new file mode 100644 index 00000000..3604e07f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a015_animate_padding.dart @@ -0,0 +1,70 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AnimatedPaddingApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _padding = 0.0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Center( + child: Container( + child: AnimatedPadding( + padding: EdgeInsets.symmetric(horizontal: _padding), + duration: Duration(milliseconds: 400), + child: Container( + height: 100, + color: Colors.red, + ), + ), + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() { + if (_padding == 0.0) { + _padding = 50.0; + } else { + _padding = 0.0; + } + }); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a016_animate_physicalmodel.dart b/FlutterHelper/flutter_helper/lib/widgets/a016_animate_physicalmodel.dart new file mode 100644 index 00000000..e6d78e2e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a016_animate_physicalmodel.dart @@ -0,0 +1,91 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AnimatedPhysicalModelApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _padding = 0.0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + RaisedButton( + onPressed: () { + setState(() { + _animated = !_animated; + }); + }, + child: Text('dong hua'), + ), + _buildAnimatedPhysicalModel(), + ], + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() { + if (_padding == 0.0) { + _padding = 50.0; + } else { + _padding = 0.0; + } + }); + }, + ), + ); + } + + bool _animated = false; + + _buildAnimatedPhysicalModel() { + return AnimatedPhysicalModel( + child: Container( + height: 100, + width: 100, + ), + borderRadius: BorderRadius.circular(_animated ? 20 : 10), + shape: BoxShape.rectangle, + elevation: _animated ? 18 : 8, + color: _animated ? Colors.blue : Colors.red, + shadowColor: !_animated ? Colors.blue : Colors.red, + duration: Duration(seconds: 1), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a017_animate_positioned.dart b/FlutterHelper/flutter_helper/lib/widgets/a017_animate_positioned.dart new file mode 100644 index 00000000..81b67a0c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a017_animate_positioned.dart @@ -0,0 +1,90 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AnimatedPositionedApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _top = 30.0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Center( + child: Stack( + alignment: Alignment.center, + children: [ + AnimatedPositioned( + top: _top, + child: Container( + height: 50, + width: 50, + color: Colors.red, + ), + duration: Duration(seconds: 2)), + ], + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() { + if (_top == 400.0) { + _top = 0.0; + } else { + _top = 400.0; + } + }); + }, + ), + ); + } + + bool _animated = false; + + _buildAnimatedPhysicalModel() { + return AnimatedPhysicalModel( + child: Container( + height: 100, + width: 100, + ), + borderRadius: BorderRadius.circular(_animated ? 20 : 10), + shape: BoxShape.rectangle, + elevation: _animated ? 18 : 8, + color: _animated ? Colors.blue : Colors.red, + shadowColor: !_animated ? Colors.blue : Colors.red, + duration: Duration(milliseconds: 100), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a018_animate_positioned_directional.dart b/FlutterHelper/flutter_helper/lib/widgets/a018_animate_positioned_directional.dart new file mode 100644 index 00000000..fe8beea2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a018_animate_positioned_directional.dart @@ -0,0 +1,73 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AnimatedPositionedDirectionalApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _start = 0.0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Center( + child: Stack( + alignment: Alignment.center, + children: [ + AnimatedPositionedDirectional( + start: _start, + child: Container( + height: 50, + width: 50, + color: Colors.red, + ), + duration: Duration(seconds: 2)), + ], + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() { + if (_start == 180.0) { + _start = 0.0; + } else { + _start = 180.0; + } + }); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a019_animate_size.dart b/FlutterHelper/flutter_helper/lib/widgets/a019_animate_size.dart new file mode 100644 index 00000000..318b379e --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a019_animate_size.dart @@ -0,0 +1,83 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AnimatedSizeApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _height = 100.0; + var _width = 100.0; + var _color = Colors.red; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton(onPressed: () { + setState(() { + if(_height == 100.0) { + _height = 200.0; + _width = 200.0; + _color = Colors.blue; + } else { + _height = 100.0; + _width = 100.0; + _color = Colors.green; + } + }); + }), + AnimatedSize( + duration: Duration(seconds: 1), + vsync: this, + child: Container( + height: _height, + width: _width, + color: _color, + ), + ) + ], + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() {}); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a020_animate_switcher.dart b/FlutterHelper/flutter_helper/lib/widgets/a020_animate_switcher.dart new file mode 100644 index 00000000..80bdd275 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a020_animate_switcher.dart @@ -0,0 +1,83 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AnimatedSwitcherApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + var _firstChild = Container( + key: ValueKey("1"), + height: 300, + width: 300, + color: Colors.red, + ); + + var _secondChild = Container( + key: ValueKey("2"), + height: 100, + width: 100, + color: Colors.green, + ); + + var _displayChild; + + @override + void initState() { + _displayChild = _firstChild; + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Center( + child: AnimatedSwitcher( + duration: Duration(seconds: 1), + child: _displayChild, + switchInCurve: Curves.bounceInOut, + transitionBuilder: (Widget child, Animation value) { + return ScaleTransition(scale: value, child: child,); + }, + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() { + if (_displayChild == _firstChild) { + _displayChild = _secondChild; + } else { + _displayChild = _firstChild; + } + }); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a021_appbar.dart b/FlutterHelper/flutter_helper/lib/widgets/a021_appbar.dart new file mode 100644 index 00000000..8a4fb91b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a021_appbar.dart @@ -0,0 +1,148 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/AnimatedModalBarrier.html#animatedmodalbarrier +class AppbarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + var _firstChild = Container( + key: ValueKey("1"), + height: 300, + width: 300, + color: Colors.red, + ); + + var _secondChild = Container( + key: ValueKey("2"), + height: 100, + width: 100, + color: Colors.green, + ); + + var _displayChild; + + @override + void initState() { + _displayChild = _firstChild; + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + drawer: Drawer( + child: Column( + children: [ + SizedBox( + height: 100, + ), + Text(".....", textAlign: TextAlign.left,), + Text(".....", textAlign: TextAlign.left,), + Text(".....", textAlign: TextAlign.left,), + Text(".....", textAlign: TextAlign.left,), + Text(".....", textAlign: TextAlign.left,), + ], + ), + ), + body: Center( + child: Column( + children: [ + AppBar( + leading: BackButton(), + title: Text('老孟'), + ), + RaisedButton(onPressed: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + centerTitle: true, + title: Text('zhaojian'), + ), + ); + })); + }), + AppBar( + title: Text('laomeng'), + actions: [ + IconButton( + icon: Icon(Icons.menu), + onPressed: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return Scaffold( + appBar: AppBar( + title: Text('zj'), + bottom: TabBar( + tabs: [ + Text('语文'), + Text('数学'), + Text('英语'), + Text('体育'), + Text('音乐'), + ], + controller: TabController(length: 5, vsync: this), + ), + ), + ); + })); + }), + IconButton(icon: Icon(Icons.add), onPressed: () {}), + ], + ), + AppBar( + elevation: 10, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20)), + backgroundColor: Colors.red, + ), + AppBar( + iconTheme: IconThemeData(size: 74), + actionsIconTheme: IconThemeData(size: 24), + textTheme: TextTheme(title: TextStyle(color: Colors.red)), + title: Text('zzzjjj'), + ), + ], + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() { + if (_displayChild == _firstChild) { + _displayChild = _secondChild; + } else { + _displayChild = _firstChild; + } + }); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a022_aspectratio.dart b/FlutterHelper/flutter_helper/lib/widgets/a022_aspectratio.dart new file mode 100644 index 00000000..37f1bf4a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a022_aspectratio.dart @@ -0,0 +1,173 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + + +/// 1. ConstrainedBox、 +/// ConstrainedBox组件约束子组件的最大宽高和最小宽高,假如一个组件宽高都是300,包裹在ConstrainedBox中,并给ConstrainedBox添加最大宽高约束 +/// 2. UnconstrainedBox、 +/// UnconstrainedBox组件不对子组件做任何约束,比如有一个父组件大小是200x200,子组件是UnconstrainedBox,UnconstrainedBox包裹一个300x300的组件 +/// 3. SizedBox、 +/// SizedBox是具有固定宽高的组件,直接指定具体的宽高, +/// 4. AspectRatio、 +/// AspectRatio组件是固定宽高比的组件,如果组件的宽度固定,希望高是宽的1/2,可以用AspectRatio实现此效果, +/// 5. FractionallySizedBox、 +/// 当我们需要一个控件的尺寸是相对尺寸时,比如当前按钮的宽度占父组件的70%,可以使用FractionallySizedBox来实现此效果。 +/// 使用FractionallySizedBox包裹子控件,设置widthFactor宽度系数或者heightFactor高度系数,系数值的范围是0-1,0.7表示占父组件的70%, +/// 6. LimitedBox +/// LimitedBox组件是当不受父组件约束时限制它的尺寸,什么叫不受父组件约束? +/// 就像这篇文章介绍的其他组件,它们都会对子组件约束,没有约束的父组件有ListView、Row、Column等,如果LimitedBox的父组件受到约束,此时LimitedBox将会不做任何操作,我们可以认为没有这个组件,代码如下: +/// 7. Container +/// 总结 +/// 这么多约束类的容器组件,到底要使用哪一个组件呢?总结如下: +/// +/// ConstrainedBox:适用于需要设置最大/小宽高,组件大小以来子组件大小,但不能超过设置的界限。 +/// UnconstrainedBox:用到情况不多,当作ConstrainedBox的子组件可以“突破”ConstrainedBox的限制,超出界限的部分会被截取。 +/// SizedBox:适用于固定宽高的情况,常用于当作2个组件之间间隙组件。 +/// AspectRatio:适用于固定宽高比的情况。 +/// FractionallySizedBox:适用于占父组件百分比的情况。 +/// LimitedBox:适用于没有父组件约束的情况。 +/// Container:适用于不仅有尺寸的约束,还有装饰(颜色、边框、等)、内外边距等需求的情况。 +class AppbarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + var _firstChild = Container( + key: ValueKey("1"), + height: 300, + width: 300, + color: Colors.red, + ); + + var _secondChild = Container( + key: ValueKey("2"), + height: 100, + width: 100, + color: Colors.green, + ); + + var _displayChild; + + @override + void initState() { + _displayChild = _firstChild; + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + drawer: Drawer( + child: Column( + children: [ + SizedBox( + height: 100, + ), + Text(".....", textAlign: TextAlign.left,), + Text(".....", textAlign: TextAlign.left,), + Text(".....", textAlign: TextAlign.left,), + Text(".....", textAlign: TextAlign.left,), + Text(".....", textAlign: TextAlign.left,), + ], + ), + ), + body: Center( + child: Column( + children: [ + AppBar( + leading: BackButton(), + title: Text('老孟'), + ), + RaisedButton(onPressed: () { + Navigator.push(context, MaterialPageRoute(builder: (context) { + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + centerTitle: true, + title: Text('zhaojian'), + ), + ); + })); + }), + AppBar( + title: Text('laomeng'), + actions: [ + IconButton( + icon: Icon(Icons.menu), + onPressed: () { + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return Scaffold( + appBar: AppBar( + title: Text('zj'), + bottom: TabBar( + tabs: [ + Text('语文'), + Text('数学'), + Text('英语'), + Text('体育'), + Text('音乐'), + ], + controller: TabController(length: 5, vsync: this), + ), + ), + ); + })); + }), + IconButton(icon: Icon(Icons.add), onPressed: () {}), + ], + ), + AppBar( + elevation: 10, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20)), + backgroundColor: Colors.red, + ), + AppBar( + iconTheme: IconThemeData(size: 74), + actionsIconTheme: IconThemeData(size: 24), + textTheme: TextTheme(title: TextStyle(color: Colors.red)), + title: Text('zzzjjj'), + ), + ], + ), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() { + if (_displayChild == _firstChild) { + _displayChild = _secondChild; + } else { + _displayChild = _firstChild; + } + }); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a023_buttons.dart b/FlutterHelper/flutter_helper/lib/widgets/a023_buttons.dart new file mode 100644 index 00000000..14e69291 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a023_buttons.dart @@ -0,0 +1,430 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class ButtonsApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class ButtonsApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } + + @override + High getHigh() => High(toStringShort(), + """ + + """ + ); +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _dropValue = null; + var _popValue = Text('学科'); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + drawer: Drawer( + child: Scrollbar( + child: SingleChildScrollView( + child: Column( + children: [ + RaisedButton( + textTheme: ButtonTextTheme.primary, + textColor: Colors.black, + disabledTextColor: Colors.grey, + color: Colors.green, + highlightColor: Colors.red, + splashColor: Colors.blue, + onHighlightChanged: (high) { + }, + onPressed: () {}, + child: Text('Button'), + ), + RaisedButton( + shape: CircleBorder(), + textTheme: ButtonTextTheme.primary, + textColor: Colors.black, + disabledTextColor: Colors.grey, + color: Colors.green, + highlightColor: Colors.red, + splashColor: Colors.blue, + onHighlightChanged: (high) { + }, + onPressed: () {}, + child: Text('Button'), + ), + FlatButton( + onPressed: () {}, + child: Text('Button'), + color: Colors.blue, + ), + OutlineButton( + borderSide: BorderSide(color: Colors.blue, width: 2), + disabledBorderColor: Colors.red, + onPressed: () {}, + child: Text('Button'), + ), + DropdownButton( + icon: Icon(Icons.add), + iconSize: 24, + iconDisabledColor: Colors.red, + iconEnabledColor: Colors.red, + selectedItemBuilder: (context) { + return [ + Text( + '111', + style: TextStyle(color: Colors.red), + ), + Text( + '222', + style: TextStyle(color: Colors.red), + ), + Text( + '333', + style: TextStyle(color: Colors.red), + ), + ]; + }, + value: _dropValue, + hint: Text('请选择科目'), + items: [ + DropdownMenuItem( + child: Text('111'), + value: '111', + ), + DropdownMenuItem( + child: Text('222'), + value: '222', + ), + DropdownMenuItem( + child: Text('333'), + value: '333', + ), + ], + onChanged: (value) { + setState(() { + _dropValue = value; + }); + }, + ), + RawMaterialButton( + onPressed: () {}, + fillColor: Colors.blue, + child: Text('Button'), + ), + PopupMenuButton( + shape: RoundedRectangleBorder( + side: BorderSide(color: Colors.blue, width: 5), + borderRadius: BorderRadius.circular(10), + ), + icon: Icon(Icons.add), + //child: _popValue, + elevation: 5, + padding: EdgeInsets.all(5), + color: Colors.red, + tooltip: 'PopupMenuButton', + onSelected: (value) { + setState(() { + _popValue = Text(value); + }); + }, + onCanceled: () { + print("onCancel!"); + }, + initialValue: "数学", + itemBuilder: (context) { + return >[ + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('数学'), value: '数学'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + ]; + }), + IconButton( + tooltip: '这是一个图标按钮', + icon: Icon(Icons.person), + onPressed: () {}, + iconSize: 30, + color: Colors.red, + ), + BackButton(), + CloseButton(), + ButtonBar( + alignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + RaisedButton(), + RaisedButton(), + RaisedButton(), + RaisedButton(), + ], + ), + CupertinoButton( + child: Text('ios 风格按钮'), + onPressed: () {}, + color: Colors.blue, + pressedOpacity: .5, + borderRadius: BorderRadius.circular(40), + ), + ], + ), + )), + ), + body: SizedBox(), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() {}); + }, + ), + ); + } +} + + """ + ); +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _dropValue = null; + var _popValue = Text('学科'); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + drawer: Drawer( + child: Scrollbar( + child: SingleChildScrollView( + child: Column( + children: [ + RaisedButton( + textTheme: ButtonTextTheme.primary, + textColor: Colors.black, + disabledTextColor: Colors.grey, + color: Colors.green, + highlightColor: Colors.red, + splashColor: Colors.blue, + onHighlightChanged: (high) { + print('$high'); + }, + onPressed: () {}, + child: Text('Button'), + ), + RaisedButton( + shape: CircleBorder(), + textTheme: ButtonTextTheme.primary, + textColor: Colors.black, + disabledTextColor: Colors.grey, + color: Colors.green, + highlightColor: Colors.red, + splashColor: Colors.blue, + onHighlightChanged: (high) { + print('$high'); + }, + onPressed: () {}, + child: Text('Button'), + ), + FlatButton( + onPressed: () {}, + child: Text('Button'), + color: Colors.blue, + ), + OutlineButton( + borderSide: BorderSide(color: Colors.blue, width: 2), + disabledBorderColor: Colors.red, + onPressed: () {}, + child: Text('Button'), + ), + DropdownButton( + icon: Icon(Icons.add), + iconSize: 24, + iconDisabledColor: Colors.red, + iconEnabledColor: Colors.red, + selectedItemBuilder: (context) { + return [ + Text( + '111', + style: TextStyle(color: Colors.red), + ), + Text( + '222', + style: TextStyle(color: Colors.red), + ), + Text( + '333', + style: TextStyle(color: Colors.red), + ), + ]; + }, + value: _dropValue, + hint: Text('请选择科目'), + items: [ + DropdownMenuItem( + child: Text('111'), + value: '111', + ), + DropdownMenuItem( + child: Text('222'), + value: '222', + ), + DropdownMenuItem( + child: Text('333'), + value: '333', + ), + ], + onChanged: (value) { + setState(() { + _dropValue = value; + print("dropValue=$value"); + }); + }, + ), + RawMaterialButton( + onPressed: () {}, + fillColor: Colors.blue, + child: Text('Button'), + ), + PopupMenuButton( + shape: RoundedRectangleBorder( + side: BorderSide(color: Colors.blue, width: 5), + borderRadius: BorderRadius.circular(10), + ), + icon: Icon(Icons.add), + //child: _popValue, + elevation: 5, + padding: EdgeInsets.all(5), + color: Colors.red, + tooltip: 'PopupMenuButton', + onSelected: (value) { + print("$value"); + setState(() { + _popValue = Text(value); + }); + }, + onCanceled: () { + print("onCancel!"); + }, + initialValue: "数学", + itemBuilder: (context) { + return >[ + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('数学'), value: '数学'), + PopupMenuItem(child: Text('语文'), value: '语文'), + PopupMenuItem(child: Text('语文'), value: '语文'), + ]; + }), + IconButton( + tooltip: '这是一个图标按钮', + icon: Icon(Icons.person), + onPressed: () {}, + iconSize: 30, + color: Colors.red, + ), + BackButton(), + CloseButton(), + ButtonBar( + alignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + RaisedButton(), + RaisedButton(), + RaisedButton(), + RaisedButton(), + ], + ), + CupertinoButton( + child: Text('ios 风格按钮'), + onPressed: () {}, + color: Colors.blue, + pressedOpacity: .5, + borderRadius: BorderRadius.circular(40), + ), + ], + ), + )), + ), + body: SizedBox(), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() {}); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a024_backdropfilter.dart b/FlutterHelper/flutter_helper/lib/widgets/a024_backdropfilter.dart new file mode 100644 index 00000000..66a4ffba --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a024_backdropfilter.dart @@ -0,0 +1,73 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class BackdropFilterApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 300, + height: 400, + child: Image.asset('images/beatiful_lady.jpeg'), + ), + BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0), + child: Center( + child: Container( + color: Colors.red.withOpacity(0), + child: Text( + '一个有态度的程序员', + style: TextStyle(color: Colors.blue), + ), + ), + ), + ), + ], + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() {}); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a025_banner.dart b/FlutterHelper/flutter_helper/lib/widgets/a025_banner.dart new file mode 100644 index 00000000..d84c7c55 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a025_banner.dart @@ -0,0 +1,57 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class BannerApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Banner( + message: 'zhaojian', + location: BannerLocation.topStart, + color: Colors.blue, + textStyle: TextStyle(color: Colors.red), + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() {}); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a026_baseline.dart b/FlutterHelper/flutter_helper/lib/widgets/a026_baseline.dart new file mode 100644 index 00000000..62c2574f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a026_baseline.dart @@ -0,0 +1,85 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class BaselineApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Baseline( + baseline: 50.0, + baselineType: TextBaseline.alphabetic, + child: Text( + 'TjTjTj', + style: TextStyle( + fontSize: 20.0, + textBaseline: TextBaseline.alphabetic, + ), + ), + ), + Baseline( + baseline: 50.0, + baselineType: TextBaseline.alphabetic, + child: Container( + width: 30.0, + height: 30.0, + color: Colors.red, + ), + ), + Baseline( + baseline: 50.0, + baselineType: TextBaseline.alphabetic, + child: Text( + 'RyRyRy', + style: TextStyle( + fontSize: 35.0, textBaseline: TextBaseline.alphabetic), + ), + ) + ], + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() {}); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a027_border.dart b/FlutterHelper/flutter_helper/lib/widgets/a027_border.dart new file mode 100644 index 00000000..224c6d3c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a027_border.dart @@ -0,0 +1,148 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class BorderApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + RaisedButton( + shape: BeveledRectangleBorder( + side: BorderSide(width: 1, color: Colors.red), + borderRadius: BorderRadius.circular(10), + ), + onPressed: () {}, + child: Text('zhojian'), + ), + RaisedButton( + shape: BeveledRectangleBorder( + side: BorderSide(width: 1, color: Colors.red), + borderRadius: BorderRadius.circular(100), + ), + onPressed: () {}, + child: Text('zhojian'), + ), + RaisedButton( + shape: BeveledRectangleBorder( + side: BorderSide(width: 1, color: Colors.red), + borderRadius: BorderRadius.circular(0), + ), + onPressed: () {}, + child: Text('zhojian'), + ), + RaisedButton( + shape: Border( + top: BorderSide(color: Colors.red, width: 2), + ), + onPressed: () {}, + child: Text('zhojian'), + ), + RaisedButton( + shape: Border( + top: BorderSide(color: Colors.red, width: 10), + right: BorderSide(color: Colors.green, width: 10), + bottom: BorderSide(color: Colors.blue, width: 10), + left: BorderSide(color: Colors.grey, width: 10), + ), + onPressed: () {}, + child: Text('zhojian'), + ), + RaisedButton( + shape: BorderDirectional( + start: BorderSide(color: Colors.red, width: 2), + end: BorderSide(color: Colors.blue, width: 2), + ), + child: Text('ZHAOJIAN'), + onPressed: () {}, + ), + RaisedButton( + shape: CircleBorder(side: BorderSide(color: Colors.red)), + child: Text('ZHA'), + onPressed: () {}, + ), + RaisedButton( + shape: ContinuousRectangleBorder( + side: BorderSide(color: Colors.red), + borderRadius: BorderRadius.circular(20), + ), + child: Text('ZHA'), + onPressed: () {}, + ), + RaisedButton( + shape: RoundedRectangleBorder( + side: BorderSide(color: Colors.red), + borderRadius: BorderRadius.circular(10), + ), + child: Text('ZHA'), + onPressed: () {}, + ), + RaisedButton( + shape: StadiumBorder( + side: BorderSide(color: Colors.red), + ), + child: Text('ZHA'), + onPressed: () {}, + ), + RaisedButton( + shape: OutlineInputBorder( + borderSide: BorderSide(color: Colors.greenAccent), + borderRadius: BorderRadius.circular(20), + ), + child: Text('ZHA'), + onPressed: () {}, + ), + RaisedButton( + shape: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.red), + ), + child: Text('ZHAOJIAN'), + onPressed: () {}, + ), + ], + ), + floatingActionButton: RaisedButton( + onPressed: () { + setState(() {}); + }, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a028_bottomappbar.dart b/FlutterHelper/flutter_helper/lib/widgets/a028_bottomappbar.dart new file mode 100644 index 00000000..7ca02161 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a028_bottomappbar.dart @@ -0,0 +1,78 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class BottomAppBarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Container(), + // floatingActionButton: RaisedButton( + // shape: CircleBorder(), + // color: Colors.red, + // onPressed: () { + // setState(() {}); + // }, + // ), + floatingActionButton: FloatingActionButton.extended( + shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(100)), + onPressed: () {}, + label: Text('label'), + icon: Icon(Icons.add), + ), + floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, + bottomNavigationBar: BottomAppBar( + // notchMargin: -10, + elevation: 8.0, + // shape: CircularNotchedRectangle(), + shape: AutomaticNotchedShape( + RoundedRectangleBorder(), + // StadiumBorder(side: BorderSide()), + BeveledRectangleBorder(borderRadius: BorderRadius.circular(100)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + IconButton(icon: Icon(Icons.home), onPressed: () {}), + IconButton(icon: Icon(Icons.people), onPressed: () {}), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a029_bottomnavigationbar.dart b/FlutterHelper/flutter_helper/lib/widgets/a029_bottomnavigationbar.dart new file mode 100644 index 00000000..f5b7fa02 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a029_bottomnavigationbar.dart @@ -0,0 +1,115 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class BottomNavigationBarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + color: Colors.red, + ); + } +} + +class BookPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + color: Colors.green, + ); + } +} + +class MyPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + color: Colors.blue, + ); + } +} + +Widget _curBody = HomePage(); + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: _curBody, + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + switch (index) { + case 0: + _curBody = HomePage(); + break; + case 1: + _curBody = BookPage(); + break; + case 2: + _curBody = MyPage(); + break; + } + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a030_scrollpysics.dart b/FlutterHelper/flutter_helper/lib/widgets/a030_scrollpysics.dart new file mode 100644 index 00000000..26dc45af --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a030_scrollpysics.dart @@ -0,0 +1,77 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class BottomNavigationBarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a031_builder.dart b/FlutterHelper/flutter_helper/lib/widgets/a031_builder.dart new file mode 100644 index 00000000..1a95fe60 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a031_builder.dart @@ -0,0 +1,116 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/Builder.html#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E4%BA%8C +class BuildApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _HomePage(), + ); + } +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('老慢'), + ), + // body: Center( + // child: RaisedButton( + // color: Colors.pink, + // textColor: Colors.white, + // onPressed: _displaySnackBar(context), + // child: Text('show snakbar!'), + // ), + // ), + body: Builder( + builder: (context) => Center( + child: RaisedButton( + onPressed: () { + _displaySnackBar(context); + }, + color: Colors.pink, + textColor: Colors.white, + child: Text('Hello'), + ), + ), + ), + ); + } + + _displaySnackBar(BuildContext context) { + // final snackbar = SnackBar(content: Text("hello")); + // Scaffold.of(context).showSnackBar(snackbar); + + + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a032_card.dart b/FlutterHelper/flutter_helper/lib/widgets/a032_card.dart new file mode 100644 index 00000000..a2dad282 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a032_card.dart @@ -0,0 +1,170 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/Builder.html#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E4%BA%8C +class CardApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _HomePage(), + ); + } +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('老慢'), + ), + body: Column( + children: [ + Card( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: Icon(Icons.album), + title: Text('laomeng'), + subtitle: Text('一枚有态度的程序员'), + ), + ButtonBar( + children: [ + FlatButton( + child: Text('OK'), + onPressed: () {}, + ), + FlatButton( + child: Text('Right'), + onPressed: () {}, + ) + ], + ), + ], + ), + ), + Card( + color: Colors.blue, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: Icon(Icons.album), + title: Text('laomeng'), + subtitle: Text('一枚有态度的程序员'), + ), + ButtonBar( + children: [ + FlatButton( + child: Text('OK'), + onPressed: () {}, + ), + FlatButton( + child: Text('Right'), + onPressed: () {}, + ) + ], + ), + ], + ), + ), + Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + color: Colors.blue, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: Icon(Icons.album), + title: Text('laomeng'), + subtitle: Text('一枚有态度的程序员'), + ), + ButtonBar( + children: [ + FlatButton( + child: Text('OK'), + onPressed: () {}, + ), + FlatButton( + child: Text('Right'), + onPressed: () {}, + ) + ], + ), + ], + ), + ), + ], + ), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a033_circleavator.dart b/FlutterHelper/flutter_helper/lib/widgets/a033_circleavator.dart new file mode 100644 index 00000000..1d9a4eff --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a033_circleavator.dart @@ -0,0 +1,235 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class CircleAvatorApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _HomePage(), + ); + } + + @override + High getHigh() => High(toStringShort(), """ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class CircleAvatorApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _HomePage(), + ); + } + + @override + High getHigh() => High(toStringShort(), """ + """); +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('老慢'), + ), + body: Column( + children: [ + CircleAvatar( + child: Text('梦'), + ), + CircleAvatar( + backgroundColor: Colors.blue, + child: Text('梦'), + ), + CircleAvatar( + backgroundColor: Colors.red, + child: Text('梦'), + ), + CircleAvatar( + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ), + CircleAvatar( + radius: 40, + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ) + ], + ), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} + + """); +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('老慢'), + ), + body: Column( + children: [ + CircleAvatar( + child: Text('梦'), + ), + CircleAvatar( + backgroundColor: Colors.blue, + child: Text('梦'), + ), + CircleAvatar( + backgroundColor: Colors.red, + child: Text('梦'), + ), + CircleAvatar( + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ), + CircleAvatar( + radius: 40, + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ) + ], + ), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a034_cpertinoactionsheet.dart b/FlutterHelper/flutter_helper/lib/widgets/a034_cpertinoactionsheet.dart new file mode 100644 index 00000000..81131633 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a034_cpertinoactionsheet.dart @@ -0,0 +1,153 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class CupertinoActionSheetApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _HomePage(), + ); + } +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('老慢'), + ), + body: Column( + children: [ + CircleAvatar( + child: Text('梦'), + ), + CircleAvatar( + backgroundColor: Colors.blue, + child: Text('梦'), + ), + CircleAvatar( + backgroundColor: Colors.red, + child: Text('梦'), + ), + CircleAvatar( + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ), + CircleAvatar( + radius: 40, + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ) + ], + ), + floatingActionButton: RaisedButton( + child: CircleAvatar( + radius: 40, + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ), + onPressed: () async { + print("print"); + var result = await showCupertinoModalPopup( + context: context, + builder: (context) { + return CupertinoActionSheet( + title: Text('tips'), + message: Text('can u sure delete it?'), + cancelButton: CupertinoActionSheetAction( + child: Text('cancel'), + onPressed: () { + print("cancel button"); + }, + ), + actions: [ + CupertinoActionSheetAction( + onPressed: () { + print("DEL button"); + Navigator.of(context).pop('delete'); + }, + child: Text('DEL'), + isDefaultAction: true, + ), + CupertinoActionSheetAction( + onPressed: () { + print("OK button"); + }, + child: Text('OK'), + isDefaultAction: true, + ), + ], + ); + }); + print("result=$result"); + }, + )); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a035_indicator.dart b/FlutterHelper/flutter_helper/lib/widgets/a035_indicator.dart new file mode 100644 index 00000000..543dba2c --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a035_indicator.dart @@ -0,0 +1,215 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class IndicatorApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _HomePage(), + ); + } +} + +void test() { + MaterialApp( + routes: { + 'container': (context) => _HomePage(), + 'fitted': (context) => _HomePage(), + 'icon': (context) => _HomePage(), + }, + initialRoute: '/', + home: Scaffold( + appBar: AppBar( + title: Text('LLLL'), + ), + ), + onGenerateRoute: (RouteSettings routeSettings) { + print('onGenerateRouter:$routeSettings'); + if (routeSettings.name == 'icon') { + return MaterialPageRoute(builder: (context) { + return _HomePage(); + }); + } + return null; + }, + onUnknownRoute: (RouteSettings routeSettings) { + print('onUnkonwRoute$routeSettings'); + return MaterialPageRoute(builder: (context) { + return HomePage(); + }); + }, + ); +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('老慢'), + ), + body: Column( + children: [ + SizedBox( + height: 20, + ), + LinearProgressIndicator(), + SizedBox( + height: 20, + ), + LinearProgressIndicator( + value: 0.3, + ), + SizedBox( + height: 20, + ), + LinearProgressIndicator( + value: 0.3, + backgroundColor: Colors.greenAccent, + valueColor: AlwaysStoppedAnimation(Colors.red), + ), + SizedBox( + height: 20, + ), + CircularProgressIndicator(), + SizedBox( + height: 20, + ), + CircularProgressIndicator( + value: .3, + backgroundColor: Colors.greenAccent, + valueColor: AlwaysStoppedAnimation(Colors.red), + ), + SizedBox( + height: 20, + ), + CupertinoActivityIndicator( + radius: 10, + ), + SizedBox( + height: 20, + ), + RefreshProgressIndicator(), + SizedBox( + height: 20, + ), + RefreshProgressIndicator( + backgroundColor: Colors.greenAccent, + valueColor: AlwaysStoppedAnimation(Colors.red), + strokeWidth: 5.0, + ), + ], + ), + floatingActionButton: RaisedButton( + child: CircleAvatar( + radius: 40, + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ), + onPressed: () async { + print("print"); + var result = await showCupertinoModalPopup( + context: context, + builder: (context) { + return CupertinoActionSheet( + title: Text('tips'), + message: Text('can u sure delete it?'), + cancelButton: CupertinoActionSheetAction( + child: Text('cancel'), + onPressed: () { + print("cancel button"); + }, + ), + actions: [ + CupertinoActionSheetAction( + onPressed: () { + print("DEL button"); + Navigator.of(context).pop('delete'); + }, + child: Text('DEL'), + isDefaultAction: true, + ), + CupertinoActionSheetAction( + onPressed: () { + print("OK button"); + }, + child: Text('OK'), + isDefaultAction: true, + ), + ], + ); + }); + print("result=$result"); + }, + )); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme + .of(context) + .primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a036_cupertinocontextmenu.dart b/FlutterHelper/flutter_helper/lib/widgets/a036_cupertinocontextmenu.dart new file mode 100644 index 00000000..a185512a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a036_cupertinocontextmenu.dart @@ -0,0 +1,215 @@ +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CupertinoContextMenuApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _HomePage(), + ); + } +} + +void test() { + MaterialApp( + routes: { + 'container': (context) => _HomePage(), + 'fitted': (context) => _HomePage(), + 'icon': (context) => _HomePage(), + }, + initialRoute: '/', + home: Scaffold( + appBar: AppBar( + title: Text('LLLL'), + ), + ), + onGenerateRoute: (RouteSettings routeSettings) { + print('onGenerateRouter:$routeSettings'); + if (routeSettings.name == 'icon') { + return MaterialPageRoute(builder: (context) { + return _HomePage(); + }); + } + return null; + }, + onUnknownRoute: (RouteSettings routeSettings) { + print('onUnkonwRoute$routeSettings'); + return MaterialPageRoute(builder: (context) { + return HomePage(); + }); + }, + ); +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('老慢'), + ), + body: Column(children: [ + CupertinoContextMenu( + actions: [ + CupertinoContextMenuAction( + child: Text('Action one'), + onPressed: () { + Navigator.pop(context); + }, + ), + CupertinoContextMenuAction( + child: Text('Action two'), + onPressed: () { + Navigator.pop(context); + }, + ) + ], + child: Container( + color: Colors.red, + height: 60, + width: 100, + )), + CupertinoContextMenu( + previewBuilder: (context, animation, child) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10 * animation.value), + color: Colors.red, + ), + height: 60, + width: 100, + ); + }, + actions: [ + CupertinoContextMenuAction( + isDefaultAction: true, //字体变粗 + child: Text('Action one'), + onPressed: () { + Navigator.pop(context); + }, + ), + CupertinoContextMenuAction( + isDestructiveAction: true, //变为红色字体了 + child: Text('Action two'), + onPressed: () { + Navigator.pop(context); + }, + ) + ], + child: Container( + color: Colors.red, + height: 60, + width: 100, + )), + ]), + floatingActionButton: RaisedButton( + child: CircleAvatar( + radius: 40, + backgroundImage: AssetImage('images/beatiful_lady.jpeg'), + child: Text('梦'), + ), + onPressed: () async { + print("print"); + var result = await showCupertinoModalPopup( + context: context, + builder: (context) { + return CupertinoActionSheet( + title: Text('tips'), + message: Text('can u sure delete it?'), + cancelButton: CupertinoActionSheetAction( + child: Text('cancel'), + onPressed: () { + print("cancel button"); + }, + ), + actions: [ + CupertinoActionSheetAction( + onPressed: () { + print("DEL button"); + Navigator.of(context).pop('delete'); + }, + child: Text('DEL'), + isDefaultAction: true, + ), + CupertinoActionSheetAction( + onPressed: () { + print("OK button"); + }, + child: Text('OK'), + isDefaultAction: true, + ), + ], + ); + }); + print("result=$result"); + }, + )); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a037_cupertinodatepicker.dart b/FlutterHelper/flutter_helper/lib/widgets/a037_cupertinodatepicker.dart new file mode 100644 index 00000000..8f984ccd --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a037_cupertinodatepicker.dart @@ -0,0 +1,182 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CupertinoDatePickeruApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _HomePage(), + ); + } +} + +void test() { + MaterialApp( + routes: { + 'container': (context) => _HomePage(), + 'fitted': (context) => _HomePage(), + 'icon': (context) => _HomePage(), + }, + initialRoute: '/', + home: Scaffold( + appBar: AppBar( + title: Text('LLLL'), + ), + ), + onGenerateRoute: (RouteSettings routeSettings) { + print('onGenerateRouter:$routeSettings'); + if (routeSettings.name == 'icon') { + return MaterialPageRoute(builder: (context) { + return _HomePage(); + }); + } + return null; + }, + onUnknownRoute: (RouteSettings routeSettings) { + print('onUnkonwRoute$routeSettings'); + return MaterialPageRoute(builder: (context) { + return HomePage(); + }); + }, + ); +} +//cupertinofullscreendialogtransition +DateTime _selectedDate = DateTime.now(); + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('老慢'), + ), + body: Scrollbar( + child: SingleChildScrollView( + child: Column( + children: [ + // container( + // child: CupertinoDatePicker( + // onDateTimeChanged: (date) {}, + // initialDateTime: DateTime.now(), + // )), + // YearPicker( + // selectedDate: _selectedDate, + // onChanged: (date) { + // print("$date"); + // // setState(() { + // // _selectedDate = date; + // // }); + // }, + // firstDate: DateTime(2000, 1), + // lastDate: DateTime(2020, 12), + // ), + MonthPicker( + selectedDate: DateTime.now(), + onChanged: (date) { + print("$date"); + // setState(() { + // _selectedDate = date; + // }); + }, + firstDate: DateTime(2020, 1), + lastDate: DateTime(2020, 12), + ), + + // DayPicker( + // selectedDate: _selectedDate, + // currentDate: DateTime.now(), + // onChanged: (date) { + // // setState(() { + // // _selectedDate = date; + // // }); + // }, + // firstDate: DateTime(2020, 5, 1), + // lastDate: DateTime(2020, 5, 31), + // displayedMonth: DateTime(2020, 5), + // ), + ], + ), + ), + ), + floatingActionButton: RaisedButton(onPressed: () async { + var result = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2020), + lastDate: DateTime(2030), + builder: (context, child) { + return Theme( + data: ThemeData.dark(), + child: child, + ); + }); + print("$result"); + })); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: CustomScrollView( + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + // type: BottomNavigationBarType.fixed, + type: BottomNavigationBarType.shifting, + selectedItemColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.black, + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.home), + title: Text('首页'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.book), + title: Text('书籍'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.perm_identity), + title: Text('我的'), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a038_cupertinofullscrendialogtransitionr.dart b/FlutterHelper/flutter_helper/lib/widgets/a038_cupertinofullscrendialogtransitionr.dart new file mode 100644 index 00000000..5503af91 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a038_cupertinofullscrendialogtransitionr.dart @@ -0,0 +1,78 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CupertinoFullscreenDialogTransitionApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + AnimationController _animationController; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: 500), + ); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('zhaojan'), + ), + body: Column( + children: [ + Expanded(child: Container()), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + RaisedButton( + onPressed: () => _animationController.forward(), + child: Text('Forward'), + ), + RaisedButton( + onPressed: () => _animationController.reverse(), + child: Text('Reverse'), + ), + ], + ), + CupertinoFullscreenDialogTransition( + primaryRouteAnimation: _animationController, + secondaryRouteAnimation: _animationController, + child: Container( + color: Colors.blueGrey, + height: 300, + ), + linearTransition: true) + ], + ), + + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a039_cupertinonavigationnar.dart b/FlutterHelper/flutter_helper/lib/widgets/a039_cupertinonavigationnar.dart new file mode 100644 index 00000000..d69fe914 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a039_cupertinonavigationnar.dart @@ -0,0 +1,84 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CupertinoPageScaffoldApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + AnimationController _animationController; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: 500), + ); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + leading: Icon(Icons.arrow_back), + middle: Text('老孟'), + ), + child: Center( + child: RaisedButton( + child: Text('goto'), + color: Colors.red, + onPressed: () { + Navigator.of(context).push(CupertinoPageRoute(builder: (context) { + return SecondPage(); + })); + }, + ), + )); + } +} + +class SecondPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + previousPageTitle: '返回', + middle: Text('老孟'), + ), + child: Center( + child: RaisedButton( + child: Text('to third'), + onPressed: () { + // Navigator.of(context).push(CupertinoPageRoute(builder: (context) { + // return ThirdPage(); + // })); + }, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a040_cupertinopicker.dart b/FlutterHelper/flutter_helper/lib/widgets/a040_cupertinopicker.dart new file mode 100644 index 00000000..753c0a36 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a040_cupertinopicker.dart @@ -0,0 +1,88 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CupertinoPickerApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + AnimationController _animationController; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: 500), + ); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + leading: Icon(Icons.arrow_back), + middle: Text('老孟'), + ), + child: Center( + child: Column( + children: [ + SizedBox( + height: 500, + child: CupertinoPicker( + backgroundColor: Colors.red, + itemExtent: 45, + onSelectedItemChanged: (index) { + print('$index'); + }, + children: [ + Container( + color: Colors.primaries[1], + ), + Container( + color: Colors.primaries[2], + ), + Container( + color: Colors.primaries[3], + ), + Container( + color: Colors.primaries[4], + ), + Container( + color: Colors.primaries[5], + ), + Container( + color: Colors.primaries[6], + ), + ], + ), + ), + + ], + ), + )); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a041_scrollbar.dart b/FlutterHelper/flutter_helper/lib/widgets/a041_scrollbar.dart new file mode 100644 index 00000000..baa586a8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a041_scrollbar.dart @@ -0,0 +1,61 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class ScrollbarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + AnimationController _animationController; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: 500), + ); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + leading: Icon(Icons.arrow_back), + middle: Text('老孟'), + ), + child: Scrollbar( + child: ListView.builder( + itemBuilder: (BuildContext context, int index) { + return Text('Item $index'); + }, + itemExtent: 50, + itemCount: 50, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a042_slider.dart b/FlutterHelper/flutter_helper/lib/widgets/a042_slider.dart new file mode 100644 index 00000000..350c2614 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a042_slider.dart @@ -0,0 +1,149 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class SliderApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + double _sliderValue = 0; + double _sliderValue2 = 0; + double _sliderValue3 = 0; + RangeValues _rangeValues = RangeValues(0, 1); + double _sliderValue4 = 0; + double _sliderValue5 = 0; + String _value = '语文'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('APPBAR'), + ), + body: Scrollbar( + child: Column( + children: [ + Slider( + value: _sliderValue, + onChanged: (v) { + setState(() { + _sliderValue = v; + }); + }, + ), + Slider( + min: 0, + max: 100, + value: _sliderValue2, + onChanged: (v) { + setState(() { + _sliderValue2 = v; + }); + }, + ), + Slider( + label: '$_sliderValue3', + min: 0, + max: 100, + divisions: 5, + value: _sliderValue3, + onChanged: (v) { + setState(() { + _sliderValue3 = v; + }); + }, + ), + Slider( + activeColor: Colors.red, + inactiveColor: Colors.blue, + label: '$_sliderValue3', + min: 0, + max: 100, + divisions: 5, + value: _sliderValue3, + onChanged: (v) { + setState(() { + _sliderValue3 = v; + }); + }, + ), + RangeSlider( + values: _rangeValues, + onChanged: (v) { + setState(() { + _rangeValues = v; + }); + }, + ), + CupertinoSlider( + value: _sliderValue4, + onChanged: (v) { + setState(() { + _sliderValue4 = v; + }); + }, + ), + Slider.adaptive( + value: _sliderValue5, + onChanged: (v) { + setState(() { + _sliderValue5 = v; + }); + }, + ), + CupertinoSlidingSegmentedControl( + children: { + '语文': Container( + child: Text('语文'), + padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10), + ), + '数学': Container( + child: Text('数学'), + padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10), + ), + '体育': Container( + child: Text('体育'), + padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10), + ), + }, + groupValue: _value, + onValueChanged: (value) { + setState(() { + _value = value; + }); + }, + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a043_refreshindicator.dart b/FlutterHelper/flutter_helper/lib/widgets/a043_refreshindicator.dart new file mode 100644 index 00000000..2f1ffa86 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a043_refreshindicator.dart @@ -0,0 +1,94 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class RefreshIndicatorApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _list = [1, 2, 3, 4, 5]; + + @override + Widget build2(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('APPBAR'), + ), + body: RefreshIndicator( + color: Colors.red, + backgroundColor: Colors.lightBlue, + displacement: 10, + onRefresh: () async { + _list.add(_list.length + 1); + }, + child: ListView.builder( + itemBuilder: (context, index) { + return ListTile( + title: Text('老孟${_list[index]}'), + ); + }, + itemExtent: 50, + itemCount: _list.length, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZHAOJIAN'), + ), + body: CustomScrollView( + slivers: [ + CupertinoSliverRefreshControl( + onRefresh: () async { + setState(() { + _list.add(_list.length + 1); + }); + }, + ), + SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + return ListTile( + title: Text('老孟${_list[index]}'), + ); + }, + childCount: _list.length, + ), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a044_switch.dart b/FlutterHelper/flutter_helper/lib/widgets/a044_switch.dart new file mode 100644 index 00000000..a4fa5cea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a044_switch.dart @@ -0,0 +1,115 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class SwitchApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _switchValue = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZHAOJIAN'), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Switch( + value: _switchValue, + onChanged: (value) { + setState(() { + _switchValue = value; + }); + }, + ), + Switch( + activeColor: Colors.red, + activeTrackColor: Colors.blue, + inactiveTrackColor: Colors.green, + value: _switchValue, + onChanged: (value) { + setState(() { + _switchValue = value; + }); + }, + ), + Switch( + activeThumbImage: AssetImage('images/beatiful_lady.jpeg'), + inactiveThumbImage: AssetImage('images/bird.png'), + activeColor: Colors.red, + activeTrackColor: Colors.blue, + inactiveTrackColor: Colors.green, + value: _switchValue, + onChanged: (value) { + setState(() { + _switchValue = value; + }); + }, + ), + Switch( + inactiveThumbColor: Colors.black54, + inactiveThumbImage: AssetImage('images/bird.png'), + activeColor: Colors.red, + activeTrackColor: Colors.blue, + inactiveTrackColor: Colors.green, + value: _switchValue, + onChanged: (value) { + setState(() { + _switchValue = value; + }); + }, + ), + SwitchListTile( + value: _switchValue, + title: Text('是否允许4G下载'), + onChanged: (value) { + setState(() { + _switchValue = value; + }); + }, + ), + CupertinoSwitch( + value: _switchValue, + onChanged: (value) { + setState(() { + _switchValue = value; + }); + }, + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a045_cupertinotab.dart b/FlutterHelper/flutter_helper/lib/widgets/a045_cupertinotab.dart new file mode 100644 index 00000000..1540b7e2 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a045_cupertinotab.dart @@ -0,0 +1,66 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CupertinoTabBarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _switchValue = false; + + @override + Widget build(BuildContext context) { + return CupertinoTabScaffold( + tabBar: CupertinoTabBar( + items: [ + BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('tab1')), + BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('tab2')), + ], + onTap: (index) { + print('$index'); + }, + currentIndex: 1, + backgroundColor: Colors.blue, + activeColor: Colors.red, + ), + tabBuilder: (BuildContext context, int index) { + return CupertinoTabView( + defaultTitle: '老孟', + builder: (context) { + return Center( + child: Text('$index'), + ); + }, + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a046_textfield.dart b/FlutterHelper/flutter_helper/lib/widgets/a046_textfield.dart new file mode 100644 index 00000000..69835bea --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a046_textfield.dart @@ -0,0 +1,233 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class TextFieldApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class TextFieldPage extends StatefulWidget { + String title; + + TextFieldPage({Key key, this.title}) : super(key: key); + + @override + _TextFieldPageState createState() => _TextFieldPageState(); +} + +class _TextFieldPageState extends State { + var _textFieldValue = ''; + TextEditingController _controller; + + @override + void initState() { + _controller = TextEditingController() + ..addListener(() { + //获取输入框的内容,变为大写 + _controller.text = _controller.text.toUpperCase(); + }); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + void test() { + var _focusNode = FocusNode(); + _focusNode.unfocus(); + // FocusScope.of(context).requestFocus(_focusNode); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: SingleChildScrollView( + child: Column( + children: [ + TextField( + maxLength: 100, + buildCounter: ( + BuildContext context, { + int currentLength, + int maxLength, + bool isFocused, + }) { + return Text( + '$currentLength/$maxLength', + ); + }, + ), + TextField( + decoration: InputDecoration(hintText: 'hello'), + onChanged: (value) { + print('onChanged:$value'); + }, + onEditingComplete: () { + print('onEditingComplete'); + }, + onTap: () { + print('onTap'); + }, + textInputAction: TextInputAction.go, + ), + TextField( + inputFormatters: [ + WhitelistingTextInputFormatter(RegExp("[a-zA-Z]")), + ], + decoration: InputDecoration(hintText: 'go'), + textInputAction: TextInputAction.go, + ), + TextField( + obscureText: true, + decoration: InputDecoration(hintText: 'go'), + textInputAction: TextInputAction.go, + ), + TextField( + decoration: InputDecoration(hintText: 'done'), + textInputAction: TextInputAction.done, + ), + TextField( + keyboardType: TextInputType.phone, + controller: _controller, + ), + Container( + height: 60, + width: 250, + child: TextField( + decoration: InputDecoration( + fillColor: Color(0x30cccccc), + filled: true, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0x00FF0000)), + borderRadius: BorderRadius.all(Radius.circular(100)), + ), + hintText: 'QQ👌/手机号/邮箱', + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Color(0x00000000)), + borderRadius: BorderRadius.all(Radius.circular(100)), + ), + ), + ), + ), + TextField( + onChanged: (value) { + print(value); + setState(() { + _textFieldValue = value; + }); + }, + decoration: + InputDecoration(counterText: '${_textFieldValue.length}/32'), + ), + TextField( + decoration: InputDecoration( + prefixIcon: Icon(Icons.person), + suffixIcon: Icon(Icons.person)), + ), + TextField( + decoration: InputDecoration( + errorText: '用户名输入错误', + errorStyle: TextStyle(fontSize: 12), + errorMaxLines: 1, + errorBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.red)), + ), + ), + TextField(), + TextField( + decoration: InputDecoration( + icon: Icon(Icons.person), + ), + ), + TextField( + decoration: InputDecoration( + labelText: '姓名:', + labelStyle: TextStyle(color: Colors.red), + ), + ), + TextField( + decoration: InputDecoration( + helperText: '用户长度为6-10个字符', + helperStyle: TextStyle(color: Colors.blue), + helperMaxLines: 1, + ), + ), + TextField( + decoration: InputDecoration( + hintText: '请输入用户名', + hintStyle: TextStyle(color: Colors.grey), + hintMaxLines: 1, + ), + ), + ], + ), + ), + ); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _switchValue = false; + + @override + Widget build(BuildContext context) { + return CupertinoTabScaffold( + tabBar: CupertinoTabBar( + items: [ + BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('tab1')), + BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('tab2')), + ], + onTap: (index) { + print('$index'); + }, + currentIndex: 0, + backgroundColor: Colors.blue, + activeColor: Colors.red, + ), + tabBuilder: (BuildContext context, int index) { + return CupertinoTabView( + defaultTitle: '老孟', + builder: (context) { + var page = TextFieldPage(); + page.title = '$index'; + return page; + }, + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a047_cliprect.dart b/FlutterHelper/flutter_helper/lib/widgets/a047_cliprect.dart new file mode 100644 index 00000000..c9d70419 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a047_cliprect.dart @@ -0,0 +1,343 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class ClipRectApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class TextFieldPage extends StatefulWidget { + String title; + + TextFieldPage({Key key, this.title}) : super(key: key); + + @override + _TextFieldPageState createState() => _TextFieldPageState(); +} + +class _TextFieldPageState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + void test() { + var _focusNode = FocusNode(); + _focusNode.unfocus(); + // FocusScope.of(context).requestFocus(_focusNode); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: SingleChildScrollView( + child: Column( + children: [ + Builder(builder: (context) { + return StartClip(); + }), + Builder(builder: (context) { + return Center( + child: ClipPath( + clipper: StarPath(), + child: Container( + height: 150, + width: 250, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ); + }), + Builder(builder: (context) { + return Center( + child: ClipPath( + clipper: TrianglePath(), + child: Container( + height: 150, + width: 250, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ); + }), + ClipPath.shape( + shape: BeveledRectangleBorder(), + child: Container( + height: 150, + width: 250, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ClipPath.shape( + shape: ContinuousRectangleBorder(), + child: Container( + height: 150, + width: 150, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ClipPath.shape( + shape: RoundedRectangleBorder(), + child: Container( + height: 150, + width: 150, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ClipPath.shape( + shape: StadiumBorder(), + child: Container( + height: 150, + width: 250, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ClipOval( + child: Container( + height: 150, + width: 250, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ClipOval( + child: Container( + height: 150, + width: 150, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ClipRRect( + borderRadius: BorderRadius.circular(20), + child: Container( + height: 150, + width: 150, + child: + Image.asset('images/beatiful_lady.jpeg', fit: BoxFit.cover), + ), + ), + ClipRect( + child: Align( + alignment: Alignment.topCenter, + heightFactor: 0.5, + child: Container( + height: 150, + width: 150, + child: Image.asset( + 'images/beatiful_lady.jpeg', + fit: BoxFit.cover, + ), + ), + ), + ), + ], + ), + ), + ); + } +} + +class StartClip extends StatefulWidget { + @override + State createState() => _StartClipState(); +} + +class _StartClipState extends State + with SingleTickerProviderStateMixin { + AnimationController _controller; + Animation _animation; + + @override + void initState() { + _controller = + AnimationController(duration: Duration(seconds: 2), vsync: this) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + _controller.reverse(); + } else if (status == AnimationStatus.dismissed) { + _controller.forward(); + } + }); + _animation = Tween(begin: 1.0, end: 4.0).animate(_controller); + _controller.forward(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return ClipPath( + clipper: StarPath(scale: _animation.value), + child: Container( + height: 150, + width: 150, + color: Colors.red, + ), + ); + }), + ); + } +} + + +class StarPath extends CustomClipper { + StarPath({this.scale = 2.5}); + + final double scale; + + double perDegree = 36; + + /// 角度转弧度公式 + double degree2Radian(double degree) { + return (pi * degree / 180); + } + + @override + Path getClip(Size size) { + var R = min(size.width / 2, size.height / 2); + var r = R / scale; + var x = size.width / 2; + var y = size.height / 2; + + var path = Path(); + path.moveTo(x, y - R); + path.lineTo(x - sin(degree2Radian(perDegree)) * r, + y - cos(degree2Radian(perDegree)) * r); + path.lineTo(x - sin(degree2Radian(perDegree * 2)) * R, + y - cos(degree2Radian(perDegree * 2)) * R); + path.lineTo(x - sin(degree2Radian(perDegree * 3)) * r, + y - cos(degree2Radian(perDegree * 3)) * r); + path.lineTo(x - sin(degree2Radian(perDegree * 4)) * R, + y - cos(degree2Radian(perDegree * 4)) * R); + path.lineTo(x - sin(degree2Radian(perDegree * 5)) * r, + y - cos(degree2Radian(perDegree * 5)) * r); + path.lineTo(x - sin(degree2Radian(perDegree * 6)) * R, + y - cos(degree2Radian(perDegree * 6)) * R); + path.lineTo(x - sin(degree2Radian(perDegree * 7)) * r, + y - cos(degree2Radian(perDegree * 7)) * r); + path.lineTo(x - sin(degree2Radian(perDegree * 8)) * R, + y - cos(degree2Radian(perDegree * 8)) * R); + path.lineTo(x - sin(degree2Radian(perDegree * 9)) * r, + y - cos(degree2Radian(perDegree * 9)) * r); + path.lineTo(x - sin(degree2Radian(perDegree * 10)) * R, + y - cos(degree2Radian(perDegree * 10)) * R); + return path; + } + + @override + bool shouldReclip(StarPath oldClipper) { + return oldClipper.scale != this.scale; + } +} + +class TrianglePath extends CustomClipper { + @override + Path getClip(Size size) { + var path = Path(); + path.moveTo(size.width / 2, 0); + path.lineTo(0, size.height); + path.lineTo(size.width, size.height); + return path; + } + + @override + bool shouldReclip(CustomClipper oldClipper) { + return true; + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + var _switchValue = false; + + @override + Widget build(BuildContext context) { + return CupertinoTabScaffold( + tabBar: CupertinoTabBar( + items: [ + BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('tab1')), + BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('tab2')), + ], + onTap: (index) { + print('$index'); + }, + currentIndex: 0, + backgroundColor: Colors.blue, + activeColor: Colors.red, + ), + tabBuilder: (BuildContext context, int index) { + return CupertinoTabView( + defaultTitle: '老孟', + builder: (context) { + var page = TextFieldPage(); + page.title = '$index'; + return page; + }, + ); + }, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a048_custommultichildlayout.dart b/FlutterHelper/flutter_helper/lib/widgets/a048_custommultichildlayout.dart new file mode 100644 index 00000000..7af2add8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a048_custommultichildlayout.dart @@ -0,0 +1,94 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CustomMultiChildLayoutApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Container( + width: 200, + height: 200, + color: Colors.red, + child: CustomMultiChildLayout( + delegate: FollowTheLeader(), + children: [ + LayoutId( + id: FollowTheLeaderId.leader, + child: Text('老孟'), + ), + LayoutId( + id: FollowTheLeaderId.follower, + child: Text('专注分享Flutter'), + ), + ], + ), + ), + ); + } +} + +enum FollowTheLeaderId { leader, follower } + +class FollowTheLeader extends MultiChildLayoutDelegate { + @override + void performLayout(Size size) { + Size leaderSize = Size.zero; + if (hasChild(FollowTheLeaderId.leader)) { + leaderSize = + layoutChild(FollowTheLeaderId.leader, BoxConstraints.loose(size)); + positionChild(FollowTheLeaderId.leader, Offset.zero); + } + if (hasChild(FollowTheLeaderId.follower)) { + Size followerSize = + layoutChild(FollowTheLeaderId.follower, BoxConstraints.loose(size)); + positionChild( + FollowTheLeaderId.follower, + Offset(size.width - followerSize.width, + size.height - followerSize.height)); + } + } + + @override + bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) { + return false; + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a050_custompaint.dart b/FlutterHelper/flutter_helper/lib/widgets/a050_custompaint.dart new file mode 100644 index 00000000..4c71bdfb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a050_custompaint.dart @@ -0,0 +1,146 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CustomPaintApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: SingleChildScrollView( + child: Container( + color: Colors.red, + child: Column( + children: [ + Container( + width: 200, + height: 200, + color: Colors.blue, + child: CustomPaint( + painter: MyCustomPainter(), + ), + ), + ], + ), + ), + ), + ); + } +} + +class MyCustomPainter extends CustomPainter { + Paint _paint = Paint() + ..color = Colors.red + ..strokeWidth = 10; + + @override + void paint(Canvas canvas, Size size) { + var points = [ + Offset(20, 20), + Offset(size.width / 2, size.height / 2), + Offset(size.width - 20, size.height - 20), + ]; + canvas.drawPoints(PointMode.points, points, _paint); + _paint.strokeWidth = 5; + canvas.drawLine(Offset(0,0), Offset(size.width, size.height), _paint); + + _paint.strokeWidth = 3; + _paint.style = PaintingStyle.stroke; + print('size:$size'); + var _path = Path() + ..moveTo(20, 10) + ..lineTo(size.width-10, 10) + ..lineTo(size.width-10, size.height-20) + ..close(); + canvas.drawPath(_path, _paint); + + + _path = Path() + ..moveTo(60, 20) + ..lineTo(size.width-20, 20) + ..lineTo(size.width-20, size.height-60) + ..close(); + _paint.style = PaintingStyle.fill; + canvas.drawPath(_path, _paint); + + canvas.drawCircle(Offset(size.width/2, size.height/2), 20, _paint); + canvas.drawOval(Rect.fromLTRB(40, 0, size.width/2, size.height/2), _paint); + + _paint.style = PaintingStyle.stroke; + canvas.drawArc(Rect.fromLTRB(70,70, size.width-20, size.height-20), 0, + pi/2, + true, _paint); + + _paint.color = Colors.yellow; + _paint.strokeWidth = 10; + canvas.drawRRect(RRect.fromLTRBR(0, 0, size.width, size.height, Radius + .circular(10)), _paint); + } + + /// + /// 绘制花骨朵 + /// + // _drawFlower(Canvas canvas, Size size) { + // //将花变为红色 + // if (flowerPaths.length >= RoseData.flowerPoints.length) { + // var path = Path(); + // for (int i = 0; i < flowerPaths.length; i++) { + // if (i == 0) { + // path.moveTo(flowerPaths[i].dx, flowerPaths[i].dy); + // } else { + // path.lineTo(flowerPaths[i].dx, flowerPaths[i].dy); + // } + // } + // _paint.style = PaintingStyle.fill; + // _paint.color = _flowerColor; + // canvas.drawPath(path, _paint); + // } + // //绘制线 + // _paint.style = PaintingStyle.stroke; + // _paint.color = _strokeColor; + // //去掉最后2个点,最后2个点为了绘制红色 + // var points = flowerPaths.sublist(0, max(0, flowerPaths.length - 2)); + // canvas.drawPoints(PointMode.polygon, points, _paint); + // } + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return this != oldDelegate; + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a051_customscrollview.dart b/FlutterHelper/flutter_helper/lib/widgets/a051_customscrollview.dart new file mode 100644 index 00000000..c60a76c7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a051_customscrollview.dart @@ -0,0 +1,138 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CustomScrollViewApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + + var _scrollController = ScrollController(); + + @override + void initState() { + // 监听滚动位置 + _scrollController.addListener(() { + print('${_scrollController.position}'); + }); + //滚动到指定位置 + _scrollController.animateTo(20.0, duration: Duration(seconds: 2), curve: + null); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + buildBody1() => + CustomScrollView( + slivers: [ + SliverGrid.count( + crossAxisCount: 4, + children: List.generate(8, (index) { + return Container( + color: Colors.primaries[index % Colors.primaries.length], + alignment: Alignment.center, + child: Text( + '$index', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + ); + }).toList(), + ), + SliverList( + delegate: SliverChildBuilderDelegate((content, index) { + return Container( + height: 85, + alignment: Alignment.center, + color: Colors.primaries[index % Colors.primaries.length], + child: Text( + '$index', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + ); + }, childCount: 25), + ) + ], + ); + + buildBody2() => + CustomScrollView( + controller: _scrollController, + scrollDirection: Axis.vertical, + reverse: false, + slivers: [ + SliverAppBar( + pinned: true, + expandedHeight: 230.0, + flexibleSpace: FlexibleSpaceBar( + title: Text('复仇者联盟'), + background: Image.network( + 'http://img.haote.com/upload/20180918/2018091815372344164.jpg', + fit: BoxFit.fitHeight, + ), + ), + ), + SliverGrid.count( + crossAxisCount: 4, + children: List.generate(8, (index) { + return Container( + color: Colors.primaries[index % Colors.primaries.length], + alignment: Alignment.center, + child: Text( + '$index', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + ); + }).toList(), + ), + SliverList( + delegate: SliverChildBuilderDelegate((context, index) { + return Container( + height: 85, + alignment: Alignment.center, + color: Colors.primaries[index % Colors.primaries.length], + child: Text( + '$index', + style: TextStyle(color: Colors.white, fontSize: 24), + ), + ); + }, childCount: 25)), + ], + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + //body: buildBody1(), + body: buildBody2(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a052_customsinglechildlayout.dart b/FlutterHelper/flutter_helper/lib/widgets/a052_customsinglechildlayout.dart new file mode 100644 index 00000000..dad5640b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a052_customsinglechildlayout.dart @@ -0,0 +1,78 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class CustomSingleChildLayoutApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class MySingleChildLayoutDelegate extends SingleChildLayoutDelegate { + final Offset position; + + MySingleChildLayoutDelegate(this.position); + + @override + Offset getPositionForChild(Size size, Size childSize) { + return Offset(position.dx, position.dy); + } + + @override + bool shouldRelayout(covariant MySingleChildLayoutDelegate oldDelegate) { + return oldDelegate.position != position; + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + buildBody() => Container( + width: 200, + height: 200, + color: Colors.blue, + child: CustomSingleChildLayout( + delegate: MySingleChildLayoutDelegate(Offset(10, 10)), + child: Container( + color: Colors.red, + ), + ), + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: buildBody(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a053_datatable.dart b/FlutterHelper/flutter_helper/lib/widgets/a053_datatable.dart new file mode 100644 index 00000000..d31a4acb --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a053_datatable.dart @@ -0,0 +1,240 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class DataTableApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class MySingleChildLayoutDelegate extends SingleChildLayoutDelegate { + final Offset position; + + MySingleChildLayoutDelegate(this.position); + + @override + Offset getPositionForChild(Size size, Size childSize) { + return Offset(position.dx, position.dy); + } + + @override + bool shouldRelayout(covariant MySingleChildLayoutDelegate oldDelegate) { + return oldDelegate.position != position; + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + buildBody() => SingleChildScrollView( + // child: buildChild(), + // child: buildDataTable(), + child: buildDataTable3(), + ); + + buildChild() => Column( + children: [ + DataTable( + // sortColumnIndex: 1, + // sortAscending: true, + columns: [ + DataColumn(label: Text('姓名')), + DataColumn(label: Text('年龄'), numeric: true), //右边对齐 + ], + rows: [ + DataRow( + cells: [DataCell(Text('老孟')), DataCell(Text('1'))], + onSelectChanged: (selected) {}), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('2'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('3'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('8'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('5'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('6'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('7'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('2'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('3'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('8'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('5'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('6'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('7'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('2'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('3'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('8'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('5'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('6'))]), + DataRow(cells: [DataCell(Text('赵健')), DataCell(Text('7'))]), + ], + ), + ], + ); + + List data = [ + User('老孟', 1), + User('老孟', 2, selected: true), + User('老孟', 1), + User('老孟', 4), + User('老孟', 1), + User('老孟', 5), + User('老孟', 17), + User('老孟', 17), + User('老孟', 7), + User('老孟', 9), + User('老孟', 4), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + User('老孟', 18), + ]; + + var _sortAscending = true; + + buildListDataRow() { + List dataRows = []; + for (int i = 0; i < data.length; i++) { + dataRows.add(DataRow( + selected: data[i].selected, + onSelectChanged: (selected) { + setState(() { + data[i].selected = selected; + }); + }, + cells: [ + DataCell(Text('${data[i].name}'), showEditIcon: true), + DataCell(Text('${data[i].age}'), placeholder: true) + ], + )); + } + return dataRows; + } + + buildDataTable() => DataTable(columns: [ + DataColumn(label: Text('姓名')), + DataColumn(label: Text('年龄')), + ], rows: buildListDataRow()); + + buildDataTable2() => DataTable( + sortColumnIndex: 1, + sortAscending: _sortAscending, + columns: [ + DataColumn(label: Text('姓名')), + DataColumn( + label: Text('年龄'), + onSort: (int columnIndex, bool ascending) { + setState(() { + _sortAscending = ascending; + if (ascending) { + data.sort((a, b) => a.age.compareTo(b.age)); + } else { + data.sort((a, b) => b.age.compareTo(a.age)); + } + }); + }), + ], + rows: data.map((user) { + return DataRow(cells: [ + DataCell(Text('${user.name}')), + DataCell(Text('${user.age}')), + ]); + }).toList(), + ); + + buildDataTable3() { + List dateRows = []; + for (int i = 0; i < data.length; i++) { + dateRows.add(DataRow( + cells: [ + DataCell(Text('${data[i].name}')), + DataCell(Text('${data[i].age}')), + DataCell(Text('男')), + DataCell(Text('2020')), + DataCell(Text('10')), + ], + )); + } + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: DataTable(columns: [ + DataColumn(label: Text('姓名')), + DataColumn( + label: Text('年龄'), + ), + DataColumn( + label: Text('性别'), + ), + DataColumn( + label: Text('出生年份'), + ), + DataColumn( + label: Text('出生月份'), + ), + ], rows: dateRows), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: buildBody(), + // body: buildDataTable(), + ); + } +} + +class User { + String name; + int age; + bool selected; + + User(this.name, this.age, {this.selected = false}); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a054_decoratedbox.dart b/FlutterHelper/flutter_helper/lib/widgets/a054_decoratedbox.dart new file mode 100644 index 00000000..2981fcb4 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a054_decoratedbox.dart @@ -0,0 +1,143 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; + +class DecoratedBoxApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + buildBody() => SingleChildScrollView( + child: Column( + children: [ + DecoratedBox( + child: Container( + width: 200, + height: 200, + ), + decoration: BoxDecoration( + gradient: RadialGradient( + center: const Alignment(-0.5, -0.6), + radius: 0.15, + colors: [ + const Color(0xFFEEEEEE), + const Color(0xFF111133), + ], + stops: [0.9, 1.0] + ), + ), + ), + DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage( + 'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl-2.jpg'), + fit: BoxFit.cover, + ), + shape: BoxShape.circle, + color: Colors.blue, + // borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Colors.red, + width: 2, + )), + child: Container( + height: 200, + width: 200, + ), + ), + DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage( + 'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl-2.jpg'), + fit: BoxFit.cover, + ), + shape: BoxShape.rectangle, + color: Colors.blue, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Colors.red, + width: 2, + )), + child: Container( + height: 200, + width: 200, + ), + ), + DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.blue, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Colors.red, + width: 2, + )), + child: Text('老孟,一个有态度的程序员'), + ), + SizedBox( + height: 10, + ), + DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + color: Colors.blue, + borderRadius: BorderRadius.circular(20), + ), + child: Text('老孟,一个有态度的程序员'), + ), + SizedBox( + height: 10, + ), + DecoratedBox( + decoration: + BoxDecoration(shape: BoxShape.rectangle, color: Colors.blue), + child: Text('老孟,一个有态度的程序员'), + ), + ], + ), + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: buildBody(), + // body: buildDataTable(), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a055decoratedboxtransition.dart b/FlutterHelper/flutter_helper/lib/widgets/a055decoratedboxtransition.dart new file mode 100644 index 00000000..b4bb9b43 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a055decoratedboxtransition.dart @@ -0,0 +1,104 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class DecoratedBoxTransitionApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: _AnimationDemo(), + // body: buildDataTable(), + ); + } +} + +class _AnimationDemo extends StatefulWidget { + @override + State createState() => _AnimationDemoState(); +} + +void test(BuildContext context) { + DefaultAssetBundle.of(context).loadString("images/beatiful_lady.jpeg"); +} + +class _AnimationDemoState extends State<_AnimationDemo> + with SingleTickerProviderStateMixin { + AnimationController _animationController; + Animation _animation; + + @override + void initState() { + _animationController = + AnimationController(duration: Duration(seconds: 2), vsync: this); + _animationController.addListener(() { + if (_animationController.status == AnimationStatus.completed) { + _animationController.reverse(); + } else if (_animationController.status == AnimationStatus.dismissed) { + _animationController.forward(); + } + }); + + _animation = DecorationTween( + begin: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(15), + ), + end: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(55), + )).animate(_animationController); + + _animationController.forward(); + super.initState(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return DecoratedBoxTransition( + decoration: _animation, + child: Container( + height: 100, + width: 100, + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a056_teststyle.dart b/FlutterHelper/flutter_helper/lib/widgets/a056_teststyle.dart new file mode 100644 index 00000000..6cc938db --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a056_teststyle.dart @@ -0,0 +1,146 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class TextStyleApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + AnimationController _animationController; + Animation _animation; + + @override + void initState() { + _animationController = AnimationController( + duration: Duration(seconds: 2), + vsync: this, + )..addListener(() { + if (_animationController.status == AnimationStatus.completed) { + _animationController.reverse(); + } else if (_animationController.status == AnimationStatus.dismissed) { + _animationController.forward(); + } + }); + + _animation = TextStyleTween( + begin: TextStyle(color: Colors.blue, fontSize: 14), + end: TextStyle(color: Colors.red, fontSize: 24)) + .animate(_animationController); + + //开始动画 + _animationController.forward(); + super.initState(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return DefaultTextStyleTransition( + style: _animation, + child: + Text('赵健'), + ); + }), + // body: buildDataTable(), + ); + } + + buildBody() => Column( + children: [ + Builder(builder: (context) { + return DefaultTextStyleTransition( + style: _animation, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ); + }), + Container( + width: 150, + color: Colors.red, + child: DefaultTextStyle( + style: TextStyle(fontSize: 18), + overflow: TextOverflow.clip, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ), + ), + SizedBox( + height: 10, + ), + Container( + width: 150, + color: Colors.red, + child: DefaultTextStyle( + style: TextStyle(fontSize: 18), + overflow: TextOverflow.fade, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ), + ), + SizedBox( + height: 10, + ), + Container( + width: 150, + color: Colors.red, + child: DefaultTextStyle( + style: TextStyle(fontSize: 18), + overflow: TextOverflow.visible, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ), + ), + SizedBox( + height: 10, + ), + Container( + width: 150, + color: Colors.red, + child: DefaultTextStyle( + style: TextStyle(fontSize: 18), + overflow: TextOverflow.ellipsis, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ), + ), + DefaultTextStyle( + style: TextStyle(color: Colors.red), + child: Text( + '老孟', + style: TextStyle(color: Colors.blue), + ), + ), + DefaultTextStyle( + style: TextStyle(color: Colors.red), + child: Text('老孟'), + ), + ], + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a057_directionly.dart b/FlutterHelper/flutter_helper/lib/widgets/a057_directionly.dart new file mode 100644 index 00000000..5f86c496 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a057_directionly.dart @@ -0,0 +1,150 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class DirectionlyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + AnimationController _animationController; + Animation _animation; + + @override + void initState() { + _animationController = AnimationController( + duration: Duration(seconds: 2), + vsync: this, + )..addListener(() { + if (_animationController.status == AnimationStatus.completed) { + _animationController.reverse(); + } else if (_animationController.status == AnimationStatus.dismissed) { + _animationController.forward(); + } + }); + + _animation = TextStyleTween( + begin: TextStyle(color: Colors.blue, fontSize: 14), + end: TextStyle(color: Colors.red, fontSize: 24)) + .animate(_animationController); + + //开始动画 + _animationController.forward(); + super.initState(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return Container( + height: 100, + width: 100, + color: Colors.red, + child: Directionality( + textDirection: TextDirection.rtl, + child: Text('老孟'), + ), + ); + }), + // body: buildDataTable(), + ); + } + + buildBody() => Column( + children: [ + Builder(builder: (context) { + return DefaultTextStyleTransition( + style: _animation, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ); + }), + Container( + width: 150, + color: Colors.red, + child: DefaultTextStyle( + style: TextStyle(fontSize: 18), + overflow: TextOverflow.clip, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ), + ), + SizedBox( + height: 10, + ), + Container( + width: 150, + color: Colors.red, + child: DefaultTextStyle( + style: TextStyle(fontSize: 18), + overflow: TextOverflow.fade, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ), + ), + SizedBox( + height: 10, + ), + Container( + width: 150, + color: Colors.red, + child: DefaultTextStyle( + style: TextStyle(fontSize: 18), + overflow: TextOverflow.visible, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ), + ), + SizedBox( + height: 10, + ), + Container( + width: 150, + color: Colors.red, + child: DefaultTextStyle( + style: TextStyle(fontSize: 18), + overflow: TextOverflow.ellipsis, + child: Text( + '11111111111111111111111111111111111111111111111111111111'), + ), + ), + DefaultTextStyle( + style: TextStyle(color: Colors.red), + child: Text( + '老孟', + style: TextStyle(color: Colors.blue), + ), + ), + DefaultTextStyle( + style: TextStyle(color: Colors.red), + child: Text('老孟'), + ), + ], + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a058_widgets.dart b/FlutterHelper/flutter_helper/lib/widgets/a058_widgets.dart new file mode 100644 index 00000000..25753bdc --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a058_widgets.dart @@ -0,0 +1,258 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class Widgets2App extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + ); + } + + var _dragData; + + _buildDraggable() { + return Draggable( + data: Color(0x000000FF), + child: Container( + height: 100, + width: 100, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(10), + ), + child: Text( + '梦', + style: TextStyle(color: Colors.white, fontSize: 18), + ), + ), + feedback: Container( + height: 100, + width: 100, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(10), + ), + child: DefaultTextStyle.merge( + child: Text('梦'), + style: TextStyle(color: Colors.white, fontSize: 18), + ), + ), + childWhenDragging: Container( + height: 100, + width: 100, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.grey, + borderRadius: BorderRadius.circular(10)), + child: Text( + '梦', + style: TextStyle(color: Colors.white, fontSize: 18), + ), + ), + ); + } + + buildBody() => SingleChildScrollView( + child: Column( + children: [ + _buildDraggable(), + SizedBox( + height: 100, + ), + DragTarget( + builder: (BuildContext context, List candidateData, + List rejectedData) { + print( + 'candidateData:$candidateData,rejectedData:$rejectedData'); + return _dragData == null + ? Container( + height: 100, + width: 100, + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all(color: Colors.red), + ), + ) + : Container( + height: 100, + width: 100, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(10), + ), + child: Text('梦', + style: + TextStyle(color: Colors.white, fontSize: 18)), + ); + }, + onWillAccept: (Color color) { + print('onWillAccept:$color'); + return true; + }, + onAccept: (Color color) { + setState(() { + _dragData = color; + }); + print('onAccept:$color'); + }, + onLeave: (color) { + print('onLeave:$color'); + }, + ), + SizedBox( + height: 10, + ), + Draggable( + onDragStarted: () {}, + onDragEnd: (details) {}, + onDraggableCanceled: (velocity, offset) {}, + onDragCompleted: () {}, + // axis: Axis.vertical, //拖动的方向 + child: Container( + width: 100, + height: 100, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(10), + ), + child: Text( + '梦', + style: TextStyle(color: Colors.white, fontSize: 18), + ), + ), + feedback: Container( + height: 100, + width: 100, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(10), + ), + child: Text( + '梦', + style: TextStyle(color: Colors.white, fontSize: 18), + ), + ), + childWhenDragging: Container( + height: 100, + width: 100, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.grey, + borderRadius: BorderRadius.circular(10)), + child: Text( + '梦', + style: TextStyle(color: Colors.white, fontSize: 18), + ), + ), + ), + SizedBox( + height: 10, + ), + Container( + height: 100, + color: Colors.green, + child: VerticalDivider( + width: 20, + thickness: 2, + color: Colors.blue, + indent: 10, + endIndent: 30, + ), + ), + SizedBox( + height: 10, + ), + SizedBox( + height: 10, + ), + Divider( + height: 10, + thickness: 5, + color: Colors.red, + indent: 10, + endIndent: 10, + ), + SizedBox( + height: 10, + ), + Dismissible( + crossAxisEndOffset: 0.5, + movementDuration: Duration(seconds: 3), + dismissThresholds: { + DismissDirection.endToStart: 0.8, + }, + resizeDuration: Duration(seconds: 2), + direction: DismissDirection.horizontal, + onResize: () { + print('onResize'); + }, + onDismissed: (direction) { + print('onDissed:$direction'); + }, + confirmDismiss: (DismissDirection direction) async { + return true; + }, + key: ValueKey('key2'), + child: Container( + height: 80, + color: Colors.red, + ), + ), + Dismissible( + confirmDismiss: (DismissDirection direction) async { + return false; + }, + key: ValueKey('key'), + child: Container( + height: 80, + color: Colors.red, + ), + ), + ], + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a059_draggablescrollableactuator.dart b/FlutterHelper/flutter_helper/lib/widgets/a059_draggablescrollableactuator.dart new file mode 100644 index 00000000..9c758f39 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a059_draggablescrollableactuator.dart @@ -0,0 +1,76 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class ScraaggableScrollableActuatorApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + ); + } + + buildBody2() => SingleChildScrollView( + child: Column( + children: [], + ), + ); + + buildBody() => DraggableScrollableActuator( + child: DraggableScrollableSheet( + builder: (BuildContext context, ScrollController scrollController) { + return Container( + color: Colors.blue[100], + child: ListView.builder( + controller: scrollController, + itemCount: 100, + itemBuilder: (BuildContext context, int index) { + return ListTile( + title: Text('评论 $index'), + onTap: () { + DraggableScrollableActuator.reset(context); + }, + ); + }, + ), + ); + }, + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a059_draggablescrollablesheet.dart b/FlutterHelper/flutter_helper/lib/widgets/a059_draggablescrollablesheet.dart new file mode 100644 index 00000000..34d8e411 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a059_draggablescrollablesheet.dart @@ -0,0 +1,172 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class DraggableScrollableSheetApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + drawer: buildDrawer(), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + Scaffold.of(context).openDrawer(); + }, + ), + ); + } + + var _color = Colors.blue.withOpacity(.1); + + buildDrawer() => Drawer( + child: ListView( + children: [ + DrawerHeader( + decoration: BoxDecoration(color: _color), + duration: Duration(seconds: 1), + child: Row( + children: [ + CircleAvatar( + child: Text('梦'), + ), + SizedBox( + width: 10, + ), + ActionChip( + label: Text('老孟33333'), + onPressed: () { + setState(() { + _color = Colors.red.withOpacity(.5); + }); + }, + ), + ], + ), + ), + // ListTile(), + // ListTile(), + // ListTile(), + // ListTile(), + // ListTile(), + ], + ), + ); + + buildBody() => DraggableScrollableSheet( + initialChildSize: 0.4, + minChildSize: 0.4, + maxChildSize: 1, + expand: true, + builder: (BuildContext context, ScrollController scrollController) { + return Container( + color: Colors.blue[100], + child: ListView.builder( + controller: scrollController, + itemCount: 100, + itemBuilder: (BuildContext context, int index) { + return ListTile( + title: Text('xx评论 $index'), + onTap: () { + Navigator.of(context) + .push(CupertinoPageRoute(builder: (context) { + return _SecondPage(); + })); + print('${this.toStringShort()}'); + }, + ); + }), + ); + }); +} + +class _SecondPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var stack = Stack( + children: [ + Column( + children: [ + Image.network( + 'https://flutter.github' + '.io/assets-for-api-docs/assets/widgets/owl-2.jpg', + height: 200, + ), + Container( + height: 200, + color: Colors.grey, + alignment: Alignment.center, + child: Text('电影介绍'), + ) + ], + ), + Positioned.fill( + child: DraggableScrollableSheet( + expand: false, + initialChildSize: 0.4, + minChildSize: 0.4, + maxChildSize: 1, + builder: (BuildContext context, ScrollController scrollController) { + return Container( + color: Colors.blue[100], + child: ListView.builder( + controller: scrollController, + itemCount: 100, + itemBuilder: (BuildContext context, int index) { + return ListTile( + title: Text('评评论 $index'), + ); + }), + ); + }, + )) + ], + ); + + return Scaffold( + appBar: AppBar( + title: Text('SecondPage'), + ), + body: stack, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a060_dropdownbuttonfromfield.dart b/FlutterHelper/flutter_helper/lib/widgets/a060_dropdownbuttonfromfield.dart new file mode 100644 index 00000000..a7ef8fb1 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a060_dropdownbuttonfromfield.dart @@ -0,0 +1,137 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class DropdownButtonFromFieldApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + Scaffold.of(context).openDrawer(); + }, + ), + ); + } + + var _color = Colors.blue.withOpacity(.1); + + String _value = null; + + // buildBody() => DropdownButtonHideUnderline(child: DropdownButton()); + + buildBody() => DropdownButtonFormField( + hint: Text('请选择'), + value: _value, + items: [ + DropdownMenuItem(child: Text('语文'), value: '语文'), + DropdownMenuItem(child: Text('数学'), value: '数学'), + DropdownMenuItem(child: Text('英语'), value: '英语') + ], + selectedItemBuilder: (context) { + return [ + OutlineButton(onPressed: () {}, child: Text('语文')), + OutlineButton(onPressed: () {}, child: Text('数学')), + OutlineButton(onPressed: () {}, child: Text('英语')), + ]; + }, + onChanged: (String value) { + setState(() { + _value = value; + }); + }, + ); +} + +class _SecondPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + var stack = Stack( + children: [ + Column( + children: [ + Image.network( + 'https://flutter.github' + '.io/assets-for-api-docs/assets/widgets/owl-2.jpg', + height: 200, + ), + Container( + height: 200, + color: Colors.grey, + alignment: Alignment.center, + child: Text('电影介绍'), + ) + ], + ), + Positioned.fill( + child: DraggableScrollableSheet( + expand: false, + initialChildSize: 0.4, + minChildSize: 0.4, + maxChildSize: 1, + builder: (BuildContext context, ScrollController scrollController) { + return Container( + color: Colors.blue[100], + child: ListView.builder( + controller: scrollController, + itemCount: 100, + itemBuilder: (BuildContext context, int index) { + return ListTile( + title: Text('评评论 $index'), + ); + }), + ); + }, + )) + ], + ); + + return Scaffold( + appBar: AppBar( + title: Text('SecondPage'), + ), + body: stack, + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a061_expansiontile.dart b/FlutterHelper/flutter_helper/lib/widgets/a061_expansiontile.dart new file mode 100644 index 00000000..a5a65a6f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a061_expansiontile.dart @@ -0,0 +1,324 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class FlexiableApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } + + @override + High getHigh() => High(toStringShort(), """ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class FlexiableApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + print('{context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } + + @override + High getHigh() => High(toStringShort(), """ + + """); +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + Scaffold.of(context).openDrawer(); + }, + ), + ); + } + + var _color = Colors.blue.withOpacity(.1); + + String _value = null; + + // buildBody() => DropdownButtonHideUnderline(child: DropdownButton()); + + bool _expanded = false; + + List dataList = List.generate(20, (index) => false).toList(); + + _buildExpansionPanelList() { + return SingleChildScrollView( + child: Container( + child: ExpansionPanelList( + expansionCallback: (index, isExpaned) { + setState(() { + dataList[index] = !isExpaned; + }); + }, + children: dataList + .map((value) => ExpansionPanel( + isExpanded: value, + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text(''), + ); + }, + body: Container( + height: 100, + color: Colors.greenAccent, + child: Text('HelloWorl!'), + ), + )) + .toList(), + ), + ), + ); + } + + buildBody() => SingleChildScrollView( + child: Column( + children: [ + Row( + children: [ + Container( + color: Colors.blue, + height: 50, + width: 50, + child: ExpandIcon( + isExpanded: _expanded, + onPressed: (value) { + setState(() { + _expanded = !_expanded; + }); + }), + ), + Container( + color: Colors.blue, + height: 50, + width: 50, + child: ExpandIcon( + size: 48, + color: Colors.red, + isExpanded: _expanded, + onPressed: (value) { + setState(() { + _expanded = !_expanded; + }); + }), + ), + Flexible( + child: Container( + color: Colors.red, + height: 50, + ), + ), + Container( + color: Colors.blue, + height: 50, + width: 100, + child: ExpandIcon( + disabledColor: Colors.green, + expandedColor: Colors.red, + color: Colors.yellow, + onPressed: (value) { + setState(() { + _expanded = !_expanded; + }); + }, + isExpanded: _expanded, + ), + ), + ], + ), + _buildExpansionPanelList(), + ], + ), + ); +} + + """); +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + Scaffold.of(context).openDrawer(); + }, + ), + ); + } + + var _color = Colors.blue.withOpacity(.1); + + String _value = null; + + // buildBody() => DropdownButtonHideUnderline(child: DropdownButton()); + + bool _expanded = false; + + List dataList = List.generate(20, (index) => false).toList(); + + _buildExpansionPanelList() { + return SingleChildScrollView( + child: Container( + child: ExpansionPanelList( + expansionCallback: (index, isExpaned) { + setState(() { + dataList[index] = !isExpaned; + }); + }, + children: dataList + .map((value) => ExpansionPanel( + isExpanded: value, + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text('老孟 $isExpanded'), + ); + }, + body: Container( + height: 100, + color: Colors.greenAccent, + child: Text('HelloWorl!'), + ), + )) + .toList(), + ), + ), + ); + } + + buildBody() => SingleChildScrollView( + child: Column( + children: [ + Row( + children: [ + Container( + color: Colors.blue, + height: 50, + width: 50, + child: ExpandIcon( + isExpanded: _expanded, + onPressed: (value) { + setState(() { + _expanded = !_expanded; + }); + }), + ), + Container( + color: Colors.blue, + height: 50, + width: 50, + child: ExpandIcon( + size: 48, + color: Colors.red, + isExpanded: _expanded, + onPressed: (value) { + setState(() { + _expanded = !_expanded; + }); + }), + ), + Flexible( + child: Container( + color: Colors.red, + height: 50, + ), + ), + Container( + color: Colors.blue, + height: 50, + width: 100, + child: ExpandIcon( + disabledColor: Colors.green, + expandedColor: Colors.red, + color: Colors.yellow, + onPressed: (value) { + setState(() { + _expanded = !_expanded; + }); + }, + isExpanded: _expanded, + ), + ), + ], + ), + _buildExpansionPanelList(), + ], + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a062_flexiable.dart b/FlutterHelper/flutter_helper/lib/widgets/a062_flexiable.dart new file mode 100644 index 00000000..45eae6b6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a062_flexiable.dart @@ -0,0 +1,130 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class ExpansionTileApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + Scaffold.of(context).openDrawer(); + }, + ), + ); + } + + var _color = Colors.blue.withOpacity(.1); + + String _value = null; + + // buildBody() => DropdownButtonHideUnderline(child: DropdownButton()); + + bool _expanded = false; + + List dataList = List.generate(20, (index) => false).toList(); + + _buildExpansionPanelList() { + return SingleChildScrollView( + child: Container( + child: ExpansionPanelList( + expansionCallback: (index, isExpaned) { + setState(() { + dataList[index] = !isExpaned; + }); + }, + children: dataList + .map((value) => ExpansionPanel( + isExpanded: value, + headerBuilder: (context, isExpanded) { + return ListTile( + title: Text('老孟 $isExpanded'), + ); + }, + body: Container( + height: 100, + color: Colors.greenAccent, + child: Text('HelloWorl!'), + ), + )) + .toList(), + ), + ), + ); + } + + _buildExpansionTile() => ExpansionTile( + title: Text('学科'), + children: [ + Text('英语'), + Text('数学'), + Text('语文'), + ], + ); + + _buildExpansionTile2() => ExpansionTile( + leading: Icon(Icons.home), + subtitle: Text('各种学科'), + backgroundColor: Colors.greenAccent, + initiallyExpanded: true, + title: Text('学科'), + onExpansionChanged: (bool value) { + print('onChanged!'); + }, + children: [ + Text('英语'), + Text('数学'), + Text('语文'), + ], + ); + + buildBody() => SingleChildScrollView( + child: Column( + children: [ + _buildExpansionTile(), + _buildExpansionTile2(), + ], + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a063_fadetransition.dart b/FlutterHelper/flutter_helper/lib/widgets/a063_fadetransition.dart new file mode 100644 index 00000000..b161dd92 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a063_fadetransition.dart @@ -0,0 +1,84 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class FadeTransitionApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + Animation animation; + AnimationController controller; + + @override + void initState() { + controller = + AnimationController(vsync: this, duration: Duration(seconds: 1)) + ..repeat(); + animation = Tween(begin: 0.0, end: 1.0).animate(controller); + controller.forward(); + + super.initState(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + if (controller.status == AnimationStatus.completed) { + controller.reverse(); + } else if (controller.status == AnimationStatus.dismissed) { + controller.forward(); + } + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => Center( + child: FadeTransition( + opacity: animation, + child: Container( + color: Colors.red, + width: 100, + height: 100, + ), + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a064_dialog.dart b/FlutterHelper/flutter_helper/lib/widgets/a064_dialog.dart new file mode 100644 index 00000000..95087ea6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a064_dialog.dart @@ -0,0 +1,227 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class DialogsApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + // localizationsDelegates: [ + // GlobalMaterialLocalizations.delegate, + // GlobalMaterialLocalizations.delegate, + // ], + // supportedLocales: [ + // const Locale('zh', 'CH'), + // const Locale('en', 'US'), + // ], + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + Animation animation; + AnimationController controller; + + @override + void initState() { + controller = + AnimationController(vsync: this, duration: Duration(seconds: 1)) + ..repeat(); + animation = Tween(begin: 0.0, end: 1.0).animate(controller); + controller.forward(); + + super.initState(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => SingleChildScrollView( + child: Column( + children: [ + RaisedButton(onPressed: () { + showGeneralDialog( + context: context, + barrierDismissible: true, + barrierLabel: '', + transitionDuration: Duration(milliseconds: 200), + pageBuilder: (BuildContext context, + Animation animation, + Animation secondaryAnimation) { + return Center( + child: Container( + height: 300, + width: 250, + color: Colors.lightGreenAccent, + ), + ); + }, + transitionBuilder: (BuildContext context, + Animation animation, + Animation secodaryAnimation, + Widget child) { + return ScaleTransition( + scale: animation, + child: child, + ); + }); + }), + RaisedButton(onPressed: () { + showAboutDialog( + context: context, + applicationIcon: Image.asset( + 'images/bird.png', + width: 100, + height: 100, + ), + applicationName: '应用程序', + applicationVersion: '1.0.0', + applicationLegalese: 'copyright 老孟,一枚有态度的程序员', + children: [ + Container( + height: 30, + color: Colors.red, + ), + Container( + height: 30, + color: Colors.blue, + ), + Container( + height: 30, + color: Colors.green, + ) + ]); + }), + RaisedButton(onPressed: () { + showMenu( + initialValue: PopupMenuItem(child: Text('语文')), + context: context, + position: RelativeRect.fill, + items: [ + PopupMenuItem(child: Text('语文')), + PopupMenuDivider(), + CheckedPopupMenuItem( + child: Text('数学'), + checked: true, + ), + PopupMenuDivider(), + PopupMenuItem(child: Text('英语')), + ]); + }), + RaisedButton(onPressed: () { + showSearch(context: context, delegate: CustomSearchDelegate()); + }), + RaisedButton(onPressed: () {}), + ], + ), + ); +} + +class CustomSearchDelegate extends SearchDelegate { + @override + List buildActions(BuildContext context) { + return null; + } + + @override + Widget buildLeading(BuildContext context) { + return IconButton( + icon: Icon(Icons.arrow_back,color: Colors.blue,), + onPressed: (){ + close(context, ''); + }, + ); + } + @override + Widget buildResults(BuildContext context) { + return ListView.separated( + itemBuilder: (context, index) { + return Container( + height: 60, + alignment: Alignment.center, + child: Text( + '$index', + style: TextStyle(fontSize: 20), + ), + ); + }, + separatorBuilder: (context, index) { + return Divider(); + }, + itemCount: 10, + ); + } + + + @override + Widget buildSuggestions(BuildContext context) { + return ListView.separated( + itemBuilder: (context, index) { + return ListTile( + title: Text('老孟 $index'), + onTap: () { + query = '老孟 $index'; + }, + ); + }, + separatorBuilder: (context, index) { + return Divider(); + }, + itemCount: Random().nextInt(5), + ); + } + +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a065_wrap.dart b/FlutterHelper/flutter_helper/lib/widgets/a065_wrap.dart new file mode 100644 index 00000000..301e1a5b --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a065_wrap.dart @@ -0,0 +1,183 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class WrapApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + // localizationsDelegates: [ + // GlobalMaterialLocalizations.delegate, + // GlobalMaterialLocalizations.delegate, + // ], + // supportedLocales: [ + // const Locale('zh', 'CH'), + // const Locale('en', 'US'), + // ], + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + Animation animation; + AnimationController controller; + + @override + void initState() { + controller = + AnimationController(vsync: this, duration: Duration(seconds: 1)) + ..repeat(); + animation = Tween(begin: 0.0, end: 1.0).animate(controller); + controller.forward(); + + super.initState(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => SingleChildScrollView( + child: Column( + children: [ + Wrap( + children: List.generate(10, (i) { + double w = 50.0 + 10 * i; + return Container( + color: Colors.primaries[i], + height: 50, + width: w, + child: Text('$i'), + ); + }), + ), + Wrap( + spacing: 5, + runSpacing: 3, + crossAxisAlignment: WrapCrossAlignment.center, + children: List.generate(10, (i) { + double w = 50.0 + 10 * i; + double h = 50.0 + 5 * i; + return Container( + color: Colors.primaries[i], + height: h, + alignment: Alignment.center, + width: w, + child: Text('$i'), + ); + }), + ) + ], + ), + ); +} + +class CustomSearchDelegate extends SearchDelegate { + @override + List buildActions(BuildContext context) { + return null; + } + + @override + Widget buildLeading(BuildContext context) { + return IconButton( + icon: Icon( + Icons.arrow_back, + color: Colors.blue, + ), + onPressed: () { + close(context, ''); + }, + ); + } + + @override + Widget buildResults(BuildContext context) { + return ListView.separated( + itemBuilder: (context, index) { + return Container( + height: 60, + alignment: Alignment.center, + child: Text( + '$index', + style: TextStyle(fontSize: 20), + ), + ); + }, + separatorBuilder: (context, index) { + return Divider(); + }, + itemCount: 10, + ); + } + + @override + Widget buildSuggestions(BuildContext context) { + return ListView.separated( + itemBuilder: (context, index) { + return ListTile( + title: Text('老孟 $index'), + onTap: () { + query = '老孟 $index'; + }, + ); + }, + separatorBuilder: (context, index) { + return Divider(); + }, + itemCount: Random().nextInt(5), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a066_fittedbox.dart b/FlutterHelper/flutter_helper/lib/widgets/a066_fittedbox.dart new file mode 100644 index 00000000..3f65d1de --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a066_fittedbox.dart @@ -0,0 +1,104 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class FittedBoxApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + // localizationsDelegates: [ + // GlobalMaterialLocalizations.delegate, + // GlobalMaterialLocalizations.delegate, + // ], + // supportedLocales: [ + // const Locale('zh', 'CH'), + // const Locale('en', 'US'), + // ], + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + Animation animation; + AnimationController controller; + + @override + void initState() { + controller = + AnimationController(vsync: this, duration: Duration(seconds: 1)) + ..repeat(); + animation = Tween(begin: 0.0, end: 1.0).animate(controller); + controller.forward(); + + super.initState(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => Container( + height: 300, + width: 200, + color: Colors.green, + child: FittedBox( + child: Container( + height: 80, + width: 80, + color: Colors.red, + ), + ), + ); +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/widgets/a067_flexible.dart b/FlutterHelper/flutter_helper/lib/widgets/a067_flexible.dart new file mode 100644 index 00000000..9c3c79f7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a067_flexible.dart @@ -0,0 +1,416 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class FlexibleApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } + + @override + High getHigh() => High(toStringShort(), """ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +class FlexibleApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + print('{context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } + + @override + High getHigh() => High(toStringShort(), """ + + """); +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => Column( + children: [ + Row( + children: [ + Container( + width: 100, + height: 50, + color: Colors.green, + ), + Spacer( + flex: 2, + ), + Container( + width: 100, + height: 50, + color: Colors.blue, + ), + Spacer(), + Container( + width: 100, + height: 50, + color: Colors.green, + ), + ], + ), + Row( + children: [ + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + Expanded( + child: OutlineButton( + child: Text('OutlineButton'), + ), + ), + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + ], + ), + Row( + children: [ + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + Flexible( + fit: FlexFit.loose, + child: OutlineButton( + child: Text('OutlineButton'), + ), + ), + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + ], + ), + Row( + children: [ + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + Flexible( + fit: FlexFit.loose, + child: Container( + color: Colors.red, + height: 50, + alignment: Alignment.center, + child: Text( + 'Container', + style: TextStyle(color: Colors.white), + ), + ), + ), + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + ], + ), + SizedBox( + height: 4, + ), + Flexible( + flex: 1, + child: Container( + color: Colors.blue, + alignment: Alignment.center, + child: Text( + '1 Flex / 6 Total', + style: TextStyle(color: Colors.white), + ), + ), + ), + Flexible( + flex: 2, + child: Container( + color: Colors.red, + alignment: Alignment.center, + child: Text( + '1 Flex / 6 Total', + style: TextStyle(color: Colors.white), + ), + ), + ), + Flexible( + flex: 3, + child: Container( + color: Colors.green, + alignment: Alignment.center, + child: Text( + '1 Flex / 6 Total', + style: TextStyle(color: Colors.white), + ), + ), + ), + ], + ); +} + + """); +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => Column( + children: [ + Row( + children: [ + Container( + width: 100, + height: 50, + color: Colors.green, + ), + Spacer( + flex: 2, + ), + Container( + width: 100, + height: 50, + color: Colors.blue, + ), + Spacer(), + Container( + width: 100, + height: 50, + color: Colors.green, + ), + ], + ), + Row( + children: [ + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + Expanded( + child: OutlineButton( + child: Text('OutlineButton'), + ), + ), + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + ], + ), + Row( + children: [ + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + Flexible( + fit: FlexFit.loose, + child: OutlineButton( + child: Text('OutlineButton'), + ), + ), + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + ], + ), + Row( + children: [ + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + Flexible( + fit: FlexFit.loose, + child: Container( + color: Colors.red, + height: 50, + alignment: Alignment.center, + child: Text( + 'Container', + style: TextStyle(color: Colors.white), + ), + ), + ), + Container( + color: Colors.blue, + height: 50, + width: 50, + ), + ], + ), + SizedBox( + height: 4, + ), + Flexible( + flex: 1, + child: Container( + color: Colors.blue, + alignment: Alignment.center, + child: Text( + '1 Flex / 6 Total', + style: TextStyle(color: Colors.white), + ), + ), + ), + Flexible( + flex: 2, + child: Container( + color: Colors.red, + alignment: Alignment.center, + child: Text( + '1 Flex / 6 Total', + style: TextStyle(color: Colors.white), + ), + ), + ), + Flexible( + flex: 3, + child: Container( + color: Colors.green, + alignment: Alignment.center, + child: Text( + '1 Flex / 6 Total', + style: TextStyle(color: Colors.white), + ), + ), + ), + ], + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a068_flexiblespacebar.dart b/FlutterHelper/flutter_helper/lib/widgets/a068_flexiblespacebar.dart new file mode 100644 index 00000000..3fbe246d --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a068_flexiblespacebar.dart @@ -0,0 +1,99 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class FlexibleSpaceBarApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => CustomScrollView( + slivers: [ + SliverAppBar( + pinned: true, + expandedHeight: 200.0, + stretch: true, + flexibleSpace: FlexibleSpaceBar( + stretchModes: [StretchMode.zoomBackground,StretchMode.blurBackground], + title: Text('复仇者联盟'), + background: Image.network( + 'http://img.haote.com/upload/20180918/2018091815372344164.jpg', + fit: BoxFit.fitHeight, + ), + ), + ), + SliverList( + delegate: SliverChildBuilderDelegate((context, index) { + return Container( + height: 65, + color: Colors.primaries[index % Colors.primaries.length], + ); + }, childCount: 50), + ), + ], + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a069_flow.dart b/FlutterHelper/flutter_helper/lib/widgets/a069_flow.dart new file mode 100644 index 00000000..a1dc2aa6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a069_flow.dart @@ -0,0 +1,407 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class FlowApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => CustomScrollView( + slivers: [ + SliverAppBar( + pinned: true, + expandedHeight: 200.0, + stretch: true, + flexibleSpace: FlexibleSpaceBar( + stretchModes: [ + StretchMode.zoomBackground, + StretchMode.blurBackground + ], + title: Text('复仇者联盟'), + background: Image.network( + 'http://img.haote.com/upload/20180918/2018091815372344164.jpg', + fit: BoxFit.fitHeight, + ), + ), + ), + SliverList( + delegate: SliverChildBuilderDelegate((context, index) { + return Container( + height: 65, + color: Colors.primaries[index % Colors.primaries.length], + ); + }, childCount: 50), + ), + ], + ); +} + +class DemoFlowPopMenuApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + home: DemoFlowPopMenu(), + ); + } +} + +class DemoFlowPopMenu extends StatefulWidget { + @override + State createState() => _DemoFlowPopMenuState(); +} + +class _DemoFlowPopMenuState extends State + with SingleTickerProviderStateMixin { + // 动画必须要with这个类 + AnimationController _ctrlAnimationPopMenu; //自定义动画的变量 + IconData lastTapped = Icons.notifications; + final List menuItems = [ + //菜单的icon + Icons.home, + Icons.new_releases, + Icons.notifications, + Icons.settings, + Icons.menu, + ]; + + void _updateMenu(IconData icon) { + if (icon != Icons.menu) { + setState(() { + lastTapped = icon; + }); + } else { + if (_ctrlAnimationPopMenu.status == AnimationStatus.completed) { + _ctrlAnimationPopMenu.reverse(); + } else { + _ctrlAnimationPopMenu.forward(); + } + } + } + + @override + void initState() { + _ctrlAnimationPopMenu = AnimationController( + //必须初始化动画变量 + duration: const Duration(milliseconds: 250), + vsync: this, + ); + super.initState(); + } + + // 生成Popmenu数据 + Widget flowMenuItem(IconData icon) { + final double buttonDiameter = + MediaQuery.of(context).size.width * 2 / (menuItems.length * 3); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: RawMaterialButton( + fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue, + splashColor: Colors.amber[100], + shape: CircleBorder(), + constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)), + onPressed: () { + _updateMenu(icon); + }, + child: Icon( + icon, + color: Colors.white, + size: 30.0, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Center( + child: Flow( + delegate: FlowMenuDelegate(animation: _ctrlAnimationPopMenu), + children: menuItems.map((e) => flowMenuItem(e)).toList(), + ), + ); + } +} + +class FlowMenuDelegate extends FlowDelegate { + final Animation animation; + + FlowMenuDelegate({this.animation}) : super(repaint: animation); + + @override + void paintChildren(FlowPaintingContext context) { + double x = 50.0; + double y = 50.0; + for (int i = 0; i < context.childCount; i++) { + x = context.getChildSize(i).width * i * animation.value; + context.paintChild(i, transform: Matrix4.translationValues(x, y, 0)); + } + } + + @override + bool shouldRepaint(covariant FlowMenuDelegate oldDelegate) { + return animation != oldDelegate.animation; + } +} + +class DemoFlowCircelApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + home: DemoFlowCircle(), + ); + } +} + +class DemoFlowCircle extends StatefulWidget { + @override + _DemoFlowCircleState createState() => _DemoFlowCircleState(); +} + +class _DemoFlowCircleState extends State + with TickerProviderStateMixin { + //动画需要这个类来混合 + //动画变量,以及初始化和销毁 + AnimationController _ctrlAnimationCircle; + + @override + void initState() { + super.initState(); + _ctrlAnimationCircle = AnimationController( + //初始化动画变量 + lowerBound: 0, + upperBound: 80, + duration: Duration(seconds: 3), + vsync: this); + _ctrlAnimationCircle.addListener(() => setState(() {})); + } + + @override + void dispose() { + _ctrlAnimationCircle.dispose(); //销毁变量,释放资源 + super.dispose(); + } + + //生成Flow的数据 + List _buildFlowChildren() { + return List.generate( + 15, + (index) => Container( + child: Icon( + index.isEven ? Icons.timer : Icons.ac_unit, + color: Colors.primaries[index % Colors.primaries.length], + ), + )); + } + +//系统生成页面 + @override + Widget build(BuildContext context) { + return Center( + child: GestureDetector( + onTap: () { + setState(() { + //点击后让动画可前行或回退 + _ctrlAnimationCircle.status == AnimationStatus.completed + ? _ctrlAnimationCircle.reverse() + : _ctrlAnimationCircle.forward(); + }); + }, + child: Container( + color: Colors.blueAccent.withOpacity(0.4), + width: 200, + height: 200, + child: Flow( + delegate: FlowAnimatedCircle(_ctrlAnimationCircle.value), + children: _buildFlowChildren(), + ), + ), + ), + ); + } +} + +class FlowAnimatedCircle extends FlowDelegate { + final double radius; //绑定半径,让圆动起来 + FlowAnimatedCircle(this.radius); + + @override + void paintChildren(FlowPaintingContext context) { + double x = 0; //开始(0,0)在父组件的中心 + double y = 0; + for (int i = 0; i < context.childCount; i++) { + x = radius * cos(i * 2 * pi / (context.childCount - 1)); //根据数学得出坐标 + y = radius * sin(i * 2 * pi / (context.childCount - 1)); //根据数学得出坐标 + context.paintChild(i, transform: Matrix4.translationValues(x, y, 0)); + } //使用Matrix定位每个子组件 + } + + @override + bool shouldRepaint(FlowDelegate oldDelegate) => true; +} + +class DemoFlowMenuApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + MaterialApp( + home: Scaffold( + body: DemoFlowMenu(), + ), + ); + } +} + +class DemoFlowMenu extends StatefulWidget { + @override + _DemoFlowMenuState createState() => _DemoFlowMenuState(); +} + +class _DemoFlowMenuState extends State + with TickerProviderStateMixin { + //动画需要这个类来混合 + //动画变量,以及初始化和销毁 + AnimationController _ctrlAnimationCircle; + + @override + void initState() { + super.initState(); + _ctrlAnimationCircle = AnimationController( + //初始化动画变量 + lowerBound: 0, + upperBound: 80, + duration: Duration(milliseconds: 300), + vsync: this); + _ctrlAnimationCircle.addListener(() => setState(() {})); + } + + @override + void dispose() { + _ctrlAnimationCircle.dispose(); //销毁变量,释放资源 + super.dispose(); + } + + //生成Flow的数据 + List _buildFlowChildren() { + return List.generate( + 5, + (index) => Container( + child: Icon( + index.isEven ? Icons.timer : Icons.ac_unit, + color: Colors.primaries[index % Colors.primaries.length], + ), + )); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Positioned.fill( + child: Flow( + delegate: FlowAnimatedCircle2(_ctrlAnimationCircle.value), + children: _buildFlowChildren(), + ), + ), + Positioned.fill( + child: IconButton( + icon: Icon(Icons.menu), + onPressed: () { + setState(() { + //点击后让动画可前行或回退 + _ctrlAnimationCircle.status == AnimationStatus.completed + ? _ctrlAnimationCircle.reverse() + : _ctrlAnimationCircle.forward(); + }); + }, + ), + ), + ], + ); + } +} + +class FlowAnimatedCircle2 extends FlowDelegate { + final double radius; //绑定半径,让圆动起来 + FlowAnimatedCircle2(this.radius); + + @override + void paintChildren(FlowPaintingContext context) { + if (radius == 0) { + return; + } + double x = 0; //开始(0,0)在父组件的中心 + double y = 0; + for (int i = 0; i < context.childCount; i++) { + x = radius * cos(i * pi / (context.childCount - 1)); //根据数学得出坐标 + y = radius * sin(i * pi / (context.childCount - 1)); //根据数学得出坐标 + context.paintChild(i, transform: Matrix4.translationValues(x, -y, 0)); + } //使用Matrix定位每个子组件 + } + + @override + bool shouldRepaint(FlowDelegate oldDelegate) => true; +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a070_textfield.dart b/FlutterHelper/flutter_helper/lib/widgets/a070_textfield.dart new file mode 100644 index 00000000..a3eaca6a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a070_textfield.dart @@ -0,0 +1,89 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class TextField222App extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => SingleChildScrollView( + child: Column( + children: [ + TextFormField( + onSaved: (value) { + print('$value'); + }, + autovalidate: false, + validator: (String value) { + return value.length >= 6 ? null : '账号最少6个字符'; + }, + ), + ], + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a071_futurebuilder.dart b/FlutterHelper/flutter_helper/lib/widgets/a071_futurebuilder.dart new file mode 100644 index 00000000..513c7ff5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a071_futurebuilder.dart @@ -0,0 +1,180 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class FutureBuilderApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody2() => FutureBuilder( + future: _future, + builder: (context, snapshot) { + var widget; + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + widget = Icon( + Icons.error, + color: Colors.red, + size: 48, + ); + } else { + widget = Icon( + Icons.check_circle, + color: Colors.green, + size: 36, + ); + } + } else { + widget = Padding( + padding: EdgeInsets.all(20), + child: CircularProgressIndicator(), + ); + } + + return Center( + child: Container( + height: 100, + width: 100, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.all(Radius.circular(10))), + child: widget, + ), + ); + }, + ); + // var _future = Future.delayed(Duration(seconds: 3), () { + // return "老孟,一个有态度的程序员"; + // }); + + // var _future = Future.delayed(Duration(seconds: 3), () { + // return Future.error(''); + // }); + + buildBody() => FutureBuilder( + future: _future, + builder: (context, snapshot) { + var widget; + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + widget = _loadingErrorWidget(); + } else { + widget = _dataWidget(snapshot.data); + } + } else { + widget = _loadingWidget(); + } + return widget; + }, + ); + + _loadingWidget() { + return Center( + child: Padding( + padding: EdgeInsets.all(20), + child: CircularProgressIndicator(), + ), + ); + } + + + _loadingErrorWidget() { + return Center( + child: Text('数据加载失败,请重试。'), + ); + } + + _dataWidget(data) { + return ListView.separated( + itemBuilder: (context, index) { + return Container( + height: 60, + alignment: Alignment.center, + child: Text( + '$index', + style: TextStyle(fontSize: 20), + ), + ); + }, + separatorBuilder: (context, index) { + return Divider(); + }, + itemCount: 10, + ); + } + + var _future = Future.delayed(Duration(seconds: 3), () { + return Future.error(''); + }); + + +// var _future = Future.delayed(Duration(seconds: 3), () { + // return 'json 字符串'; + // }); + +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a072_gesturedetector.dart b/FlutterHelper/flutter_helper/lib/widgets/a072_gesturedetector.dart new file mode 100644 index 00000000..43c352c6 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a072_gesturedetector.dart @@ -0,0 +1,108 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class GestureDetectorApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Test(), + ); + } +} + +class _Test extends StatefulWidget { + @override + State createState() { + return _TestState(); + } +} + +class _TestState extends State<_Test> with SingleTickerProviderStateMixin { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ZhaoJian'), + ), + body: Builder(builder: (context) { + return buildBody(); + }), + // body: buildDataTable(), + floatingActionButton: RaisedButton( + child: CircleAvatar( + child: Text('点'), + ), + onPressed: () { + showBottomSheet( + context: context, + backgroundColor: Colors.lightGreenAccent, + elevation: 20, + shape: CircleBorder(), + builder: (context) { + return Container( + height: 200, + color: Colors.lightBlue, + ); + }, + ); + }, + ), + ); + } + + List dataList = List.generate(20, (index) => false).toList(); + + buildBody() => GestureDetector( + // onTapDown: (tapDown) { + // print('onTapDown'); + // }, + // onTapUp: (tapUp) { + // print('onTapUp'); + // }, + // onTap: () { + // print('onTap'); + // }, + // onTapCancel: () { + // print('onTapCancel'); + // }, + // onDoubleTap: () { + // print('onDoubleTap'); + // }, + onLongPressStart: (v) => print('onLongPressStart'), + onLongPressMoveUpdate: (v) => print('onLongPressMoveUpdate'), + onLongPressUp: () => print('onLongPressUp'), + onLongPressEnd: (v) => print('onLongPressEnd'), + onLongPress: () => print('onLongPress'), + onVerticalDragStart: (v) => print('onVerticalDragStart'), + onVerticalDragDown: (v) => print('onVerticalDragDown'), + onVerticalDragUpdate: (v) => print('onVerticalDragUpdate'), + onVerticalDragCancel: () => print('onVerticalDragCancel'), + onVerticalDragEnd: (v) => print('onVerticalDragEnd'), + child: Center( + child: Container( + width: 200, + height: 200, + color: Colors.red, + ), + ), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a073_hero.dart b/FlutterHelper/flutter_helper/lib/widgets/a073_hero.dart new file mode 100644 index 00000000..f5f5231f --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a073_hero.dart @@ -0,0 +1,80 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class HeroApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: HeroDemo(), + ); + } +} + +class HeroDemo extends StatefulWidget { + @override + State createState() => _HeroDemo(); +} + +class _HeroDemo extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + body: GridView( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, crossAxisSpacing: 5, mainAxisSpacing: 3), + children: List.generate(10, (index) { + if (index == 6) { + return InkWell( + onTap: () { + Navigator.push( + context, + new MaterialPageRoute( + builder: (context) => new _Hero1Demo())); + }, + child: Hero( + tag: 'hero', + child: Container( + child: Image.asset( + 'images/bird.png', + fit: BoxFit.fitWidth, + ), + ), + ), + ); + } + return Container( + color: Colors.red, + ); + }), + ), + ); + } +} + +class _Hero1Demo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Container( + alignment: Alignment.topCenter, + child: Hero( + tag: 'hero', + child: Container( + child: Image.asset( + 'images/bird.png', + ), + ), + )), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a074_intrinsicheight.dart b/FlutterHelper/flutter_helper/lib/widgets/a074_intrinsicheight.dart new file mode 100644 index 00000000..9d70e0a7 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a074_intrinsicheight.dart @@ -0,0 +1,71 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class IntrinsicHeightApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: HeroDemo(), + ); + } +} + +class HeroDemo extends StatefulWidget { + @override + State createState() => _HeroDemo(); +} + +class _HeroDemo extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + // body: buildBody(), + // body: buildBody(), + // body: buildColumn(), + body: buildBody2(), + ); + } + + buildRow() => Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Container(color: Colors.blue, width: 100.0), + new Container( + color: Colors.red, + width: 50.0, + height: 50.0, + ), + new Container(color: Colors.yellow, width: 150.0), + ], + ); + + buildBody() => IntrinsicHeight( + child: buildRow(), + ); + + buildColumn() => Column( + children: [ + new Container(color: Colors.blue, height: 100.0), + new Container(color: Colors.red, width: 150.0, height: 100.0), + new Container( + color: Colors.yellow, + height: 150.0, + ), + ], + ); + + buildBody2() => IntrinsicWidth( + stepHeight: 450.0, + stepWidth: 300.0, + child: buildColumn(), + ); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a075_nestedscrollview.dart b/FlutterHelper/flutter_helper/lib/widgets/a075_nestedscrollview.dart new file mode 100644 index 00000000..9f342881 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a075_nestedscrollview.dart @@ -0,0 +1,137 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/NestedScrollView.html#%E6%BB%9A%E5%8A%A8%E9%9A%90%E8%97%8Fappbar +class NestedScrollViewApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: HeroDemo(), + ); + } +} + +class HeroDemo extends StatefulWidget { + @override + State createState() => _HeroDemo(); +} + +class _HeroDemo extends State with SingleTickerProviderStateMixin { + ScrollController _scrollController; + TabController _tabController; + var tabs = [ + Tab(text: '资讯'), + Tab(text: '技术'), + ]; + + @override + void initState() { + _scrollController = ScrollController(); + +//监听滚动位置 + _scrollController.addListener(() { + print('${_scrollController.position}'); + }); + //滚动到指定位置 + // _scrollController.animateTo(20.0); + _tabController = TabController(vsync: this, length: tabs.length); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: buildBody(), + ); + } + + buildBody() => NestedScrollView( + headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { + return [ + SliverAppBar( + expandedHeight: 230.0, + pinned: true, + flexibleSpace: Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: PageView(), + ), + ), + SliverPersistentHeader( + pinned: true, + delegate: StickyTabBarDelegate( + child: TabBar( + labelColor: Colors.black, + controller: this._tabController, + tabs: tabs, + ), + ), + ), + ]; + }, + body: TabBarView( + controller: this._tabController, + children: [ + RefreshIndicator( + onRefresh: () async { + print(('onRefresh')); + }, + child: _buildTabNewsList(), + ), + _buildTabNewsList(), + ], + ), + ); + + _buildTabNewsList() { + return ListView.builder( + itemBuilder: (BuildContext context, int index) { + return Container( + height: 80, + color: Colors.primaries[index % Colors.primaries.length], + alignment: Alignment.center, + child: Text( + '$index', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + ); + }, + itemCount: 20, + ); + } +} + +class StickyTabBarDelegate extends SliverPersistentHeaderDelegate { + final TabBar child; + + StickyTabBarDelegate({@required this.child}); + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return Container( + color: Theme.of(context).backgroundColor, + child: this.child, + ); + } + + @override + double get maxExtent => this.child.preferredSize.height; + + @override + double get minExtent => this.child.preferredSize.height; + + @override + bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) { + return true; + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a076_notificationlistener.dart b/FlutterHelper/flutter_helper/lib/widgets/a076_notificationlistener.dart new file mode 100644 index 00000000..40052fc9 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a076_notificationlistener.dart @@ -0,0 +1,145 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/NestedScrollView.html#%E6%BB%9A%E5%8A%A8%E9%9A%90%E8%97%8Fappbar +class NotificationListenerApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: HeroDemo(), + ); + } +} + +class HeroDemo extends StatefulWidget { + @override + State createState() => _HeroDemo(); +} + +class _HeroDemo extends State with SingleTickerProviderStateMixin { + ScrollController _scrollController; + TabController _tabController; + var tabs = [ + Tab(text: '资讯'), + Tab(text: '技术'), + ]; + + @override + void initState() { + _scrollController = ScrollController(); + +//监听滚动位置 + _scrollController.addListener(() { + print('${_scrollController.position}'); + }); + //滚动到指定位置 + // _scrollController.animateTo(20.0); + _tabController = TabController(vsync: this, length: tabs.length); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: buildBody(), + ); + } + + buildBody() => NotificationListener( + onNotification: (CustomNotification notification) { + print('介绍事件——1:${notification.value}'); + return true; + }, + child: NotificationListener( + onNotification: (CustomNotification notification) { + print('介绍事件——2:${notification.value}'); + return false; + }, + child: Center( + child: Builder( + builder: (context) { + return RaisedButton( + child: Text('发送'), + onPressed: () { + CustomNotification('自定义事件').dispatch(context); + }, + ); + }, + ), + ), + )); + + buildBody2() => NotificationListener( + onNotification: (notification) { + print('$notification'); + return true; + }, + child: ListView.builder( + itemBuilder: (context, index) { + return ListTile( + title: Text('index:$index'), + ); + }, + itemCount: 50, + ), + ); + + _buildTabNewsList() { + return ListView.builder( + itemBuilder: (BuildContext context, int index) { + return Container( + height: 80, + color: Colors.primaries[index % Colors.primaries.length], + alignment: Alignment.center, + child: Text( + '$index', + style: TextStyle(color: Colors.white, fontSize: 20), + ), + ); + }, + itemCount: 20, + ); + } +} + +class StickyTabBarDelegate extends SliverPersistentHeaderDelegate { + final TabBar child; + + StickyTabBarDelegate({@required this.child}); + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return Container( + color: Theme.of(context).backgroundColor, + child: this.child, + ); + } + + @override + double get maxExtent => this.child.preferredSize.height; + + @override + double get minExtent => this.child.preferredSize.height; + + @override + bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) { + return true; + } +} + +class CustomNotification extends Notification { + CustomNotification(this.value); + + final String value; +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a077_pageview.dart b/FlutterHelper/flutter_helper/lib/widgets/a077_pageview.dart new file mode 100644 index 00000000..eb747e30 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a077_pageview.dart @@ -0,0 +1,131 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +///http://laomengit.com/flutter/widgets/NestedScrollView.html#%E6%BB%9A%E5%8A%A8%E9%9A%90%E8%97%8Fappbar +class PageViewApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: _Home(), + ); + } +} + +class _Home extends StatelessWidget { + @override + Widget build(BuildContext context) => Scaffold( + appBar: AppBar( + bottom: PreferredSize( + preferredSize: Size.fromHeight(148), + child: Container( + height: 48, + color: Colors.red, + ), + ), + ), + body: ViewPage(), + ); +} + +class ViewPage extends StatefulWidget { + @override + State createState() => _ViewPageState(); +} + +class _ViewPageState extends State { + var imgList = [ + 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2877516247,37083492&fm=26&gp=0.jpg', + 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2877516247,37083492&fm=26&gp=0.jpg', + ]; + PageController _pageController; + + var _currPageValue = 0.0; + + //缩放系数 + double _scaleFactor = .8; + + //view page height + double _height = 230.0; + + @override + void initState() { + super.initState(); + _pageController = PageController(viewportFraction: 0.9); + _pageController.addListener(() { + setState(() { + _currPageValue = _pageController.page; + }); + }); + } + + @override + void dispose() { + super.dispose(); + _pageController.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + height: _height, + child: PageView.builder( + itemBuilder: (context, index) => _buildPageItem(index), + itemCount: 10, + controller: _pageController, + )); + } + + _buildPageItem(int index) { + Matrix4 matrix4 = Matrix4.identity(); + if (index == _currPageValue.floor()) { + //当前的item + var currScale = 1 - (_currPageValue - index) * (1 - _scaleFactor); + var currTrans = _height * (1 - currScale) / 2; + + matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) + ..setTranslationRaw(0.0, currTrans, 0.0); + } else if (index == _currPageValue.floor() + 1) { + //右边的item + var currScale = + _scaleFactor + (_currPageValue - index + 1) * (1 - _scaleFactor); + var currTrans = _height * (1 - currScale) / 2; + + matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) + ..setTranslationRaw(0.0, currTrans, 0.0); + } else if (index == _currPageValue.floor() - 1) { + //左边 + var currScale = 1 - (_currPageValue - index) * (1 - _scaleFactor); + var currTrans = _height * (1 - currScale) / 2; + + matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0) + ..setTranslationRaw(0.0, currTrans, 0.0); + } else { + //其他,不在屏幕显示的item + matrix4 = Matrix4.diagonal3Values(1.0, _scaleFactor, 1.0) + ..setTranslationRaw(0.0, _height * (1 - _scaleFactor) / 2, 0.0); + } + + return Transform( + transform: matrix4, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + image: DecorationImage( + image: NetworkImage(imgList[index % 2]), fit: BoxFit.fill), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a078_fractionallysizedbox.dart b/FlutterHelper/flutter_helper/lib/widgets/a078_fractionallysizedbox.dart new file mode 100644 index 00000000..d15aaeb5 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a078_fractionallysizedbox.dart @@ -0,0 +1,50 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/utils.dart'; + +///http://laomengit.com/flutter/widgets/NestedScrollView.html#%E6%BB%9A%E5%8A%A8%E9%9A%90%E8%97%8Fappbar +class FractionallySizedBoxApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: Scaffold( + appBar: AppBar( + title: Text( + 'FractionallySizedBox百分比布局示例', + style: TextStyle(color: Colors.white), + ), + leading: GestureDetector( + child: Icon(Icons.close), + onTap: (){ + showToast("Close"); + Navigator.pop(context); + }, + ), + bottom: PreferredSize( + child: Container(height: 48, color: Colors.red), + preferredSize: Size.fromHeight(148), + ), + ), + body: FractionallySizedBox( + alignment: Alignment.center, + widthFactor: 0.4, + heightFactor: 0.5, + child: Center( + child: Container( + color: Colors.green, + ), + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/a078_media_query.dart b/FlutterHelper/flutter_helper/lib/widgets/a078_media_query.dart new file mode 100644 index 00000000..362093ed --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/a078_media_query.dart @@ -0,0 +1,78 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_helper/boss/utils.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; + +///http://laomengit.com/flutter/widgets/NestedScrollView.html#%E6%BB%9A%E5%8A%A8%E9%9A%90%E8%97%8Fappbar +class MediaQueryApp extends StatelessWidget with HighMixin{ + @override + Widget build(BuildContext context) { + print('${context.toString()}'); + return MaterialApp( + title: "Flutter DEMO APP", + locale: Locale('zh'), + theme: ThemeData( + primarySwatch: Colors.orange, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + home: Scaffold( + appBar: AppBar( + title: Text( + 'FractionallySizedBox百分比布局示例', + style: TextStyle(color: Colors.white), + ), + leading: GestureDetector( + child: Icon(Icons.close), + onTap: () { + showToast("Close"); + Navigator.pop(context); + }, + ), + bottom: PreferredSize( + child: Container(height: 48, color: Colors.red), + preferredSize: Size.fromHeight(148), + ), + ), + body: GestureDetector( + onTap: _handleClick, + child: FractionallySizedBox( + alignment: Alignment.center, + widthFactor: 0.4, + heightFactor: 0.5, + child: Expanded( + child: Container( + alignment: Alignment.center, + color: Colors.green, + child: Text('点击我'), + ), + ), + ), + ), + ), + ); + } + + _handleClick() { + // 1. + // MediaQuery.removePadding(context: context, child: child, removeTop: true,) + // 2. + // import 'dart:ui'; + var p = MediaQueryData.fromWindow(window).padding;// + showToast("${p.left} ${p.top} ${p.right} ${p.bottom}"); + } + + @override + High getHigh() => High(toStringShort(), """ + _handleClick() { + // 1. + // MediaQuery.removePadding(context: context, child: child, removeTop: true,) + // 2. + // import 'dart:ui'; + var p = MediaQueryData.fromWindow(window).padding;// + showToast("{p.left} {p.top} {p.right} {p.bottom}"); + } + """); +} diff --git a/FlutterHelper/flutter_helper/lib/widgets/widgets_page.dart b/FlutterHelper/flutter_helper/lib/widgets/widgets_page.dart new file mode 100644 index 00000000..088271b8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets/widgets_page.dart @@ -0,0 +1,348 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/boss/utils.dart'; +import 'package:flutter_helper/hightlight/mixin_highlight.dart'; +import 'package:flutter_helper/hightlight/syntax_highlight.dart'; +import 'package:flutter_helper/utils/util_log.dart'; +import 'package:flutter_helper/widgets/a002_about_list_tile.dart'; +import 'package:flutter_helper/widgets/a003_absorbpointer.dart'; +import 'package:flutter_helper/widgets/a004_actionchip.dart'; +import 'package:flutter_helper/widgets/a005_alertdialog.dart'; +import 'package:flutter_helper/widgets/a006_align.dart'; +import 'package:flutter_helper/widgets/a007_aniatedbuilder.dart'; +import 'package:flutter_helper/widgets/a008_animated_container.dart'; +import 'package:flutter_helper/widgets/a009_animated_crossfade.dart'; +import 'package:flutter_helper/widgets/a010_animate_default_textstyle.dart'; +import 'package:flutter_helper/widgets/a011_animate_icon.dart'; +import 'package:flutter_helper/widgets/a012_animate_list.dart'; +import 'package:flutter_helper/widgets/a013_animate_modalbarrier.dart'; +import 'package:flutter_helper/widgets/a014_animate_opacity.dart'; +import 'package:flutter_helper/widgets/a015_animate_padding.dart'; +import 'package:flutter_helper/widgets/a016_animate_physicalmodel.dart'; +import 'package:flutter_helper/widgets/a017_animate_positioned.dart'; +import 'package:flutter_helper/widgets/a018_animate_positioned_directional.dart'; +import 'package:flutter_helper/widgets/a019_animate_size.dart'; +import 'package:flutter_helper/widgets/a020_animate_switcher.dart'; +import 'package:flutter_helper/widgets/a021_appbar.dart'; +import 'package:flutter_helper/widgets/a023_buttons.dart'; +import 'package:flutter_helper/widgets/a024_backdropfilter.dart'; +import 'package:flutter_helper/widgets/a025_banner.dart'; +import 'package:flutter_helper/widgets/a026_baseline.dart'; +import 'package:flutter_helper/widgets/a027_border.dart'; +import 'package:flutter_helper/widgets/a028_bottomappbar.dart'; +import 'package:flutter_helper/widgets/a029_bottomnavigationbar.dart'; +import 'package:flutter_helper/widgets/a031_builder.dart'; +import 'package:flutter_helper/widgets/a032_card.dart'; +import 'package:flutter_helper/widgets/a033_circleavator.dart'; +import 'package:flutter_helper/widgets/a034_cpertinoactionsheet.dart'; +import 'package:flutter_helper/widgets/a035_indicator.dart'; +import 'package:flutter_helper/widgets/a036_cupertinocontextmenu.dart'; +import 'package:flutter_helper/widgets/a037_cupertinodatepicker.dart'; +import 'package:flutter_helper/widgets/a038_cupertinofullscrendialogtransitionr.dart'; +import 'package:flutter_helper/widgets/a039_cupertinonavigationnar.dart'; +import 'package:flutter_helper/widgets/a040_cupertinopicker.dart'; +import 'package:flutter_helper/widgets/a041_scrollbar.dart'; +import 'package:flutter_helper/widgets/a042_slider.dart'; +import 'package:flutter_helper/widgets/a043_refreshindicator.dart'; +import 'package:flutter_helper/widgets/a044_switch.dart'; +import 'package:flutter_helper/widgets/a045_cupertinotab.dart'; +import 'package:flutter_helper/widgets/a046_textfield.dart'; +import 'package:flutter_helper/widgets/a047_cliprect.dart'; +import 'package:flutter_helper/widgets/a048_custommultichildlayout.dart'; +import 'package:flutter_helper/widgets/a050_custompaint.dart'; +import 'package:flutter_helper/widgets/a051_customscrollview.dart'; +import 'package:flutter_helper/widgets/a052_customsinglechildlayout.dart'; +import 'package:flutter_helper/widgets/a053_datatable.dart'; +import 'package:flutter_helper/widgets/a054_decoratedbox.dart'; +import 'package:flutter_helper/widgets/a055decoratedboxtransition.dart'; +import 'package:flutter_helper/widgets/a056_teststyle.dart'; +import 'package:flutter_helper/widgets/a057_directionly.dart'; +import 'package:flutter_helper/widgets/a058_widgets.dart'; +import 'package:flutter_helper/widgets/a059_draggablescrollableactuator.dart'; +import 'package:flutter_helper/widgets/a059_draggablescrollablesheet.dart'; +import 'package:flutter_helper/widgets/a060_dropdownbuttonfromfield.dart'; +import 'package:flutter_helper/widgets/a061_expansiontile.dart'; +import 'package:flutter_helper/widgets/a062_flexiable.dart'; +import 'package:flutter_helper/widgets/a063_fadetransition.dart'; +import 'package:flutter_helper/widgets/a064_dialog.dart'; +import 'package:flutter_helper/widgets/a065_wrap.dart'; +import 'package:flutter_helper/widgets/a066_fittedbox.dart'; +import 'package:flutter_helper/widgets/a067_flexible.dart'; +import 'package:flutter_helper/widgets/a068_flexiblespacebar.dart'; +import 'package:flutter_helper/widgets/a069_flow.dart'; +import 'package:flutter_helper/widgets/a070_textfield.dart'; +import 'package:flutter_helper/widgets/a071_futurebuilder.dart'; +import 'package:flutter_helper/widgets/a072_gesturedetector.dart'; +import 'package:flutter_helper/widgets/a073_hero.dart'; +import 'package:flutter_helper/widgets/a074_intrinsicheight.dart'; +import 'package:flutter_helper/widgets/a075_nestedscrollview.dart'; +import 'package:flutter_helper/widgets/a076_notificationlistener.dart'; +import 'package:flutter_helper/widgets/a077_pageview.dart'; +import 'package:flutter_helper/widgets/a078_fractionallysizedbox.dart'; +import 'package:flutter_helper/widgets/a078_media_query.dart'; +import 'package:flutter_helper/widgets2/search_appbar.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +class WidgetPage extends StatefulWidget { + @override + _WidgetPageState createState() => _WidgetPageState(); +} + +class _WidgetPageState extends State { + var list = [ + MediaQueryApp(), + HighLight(), + AboutListTileApp(), + AbsorbPointerApp(), + ActionChipApp(), + AlertDialogApp(), + AlignApp(), + AnimatedBuilderApp(), + AnimatedContainerApp(), + AnimatedCrossFadeApp(), + AnimatedDefaultTextStyleApp(), + AnimatedIconApp(), + AnimatedListApp(), + AnimatedModalBarrierApp(), + AnimatedOpacityApp(), + AnimatedPaddingApp(), + AnimatedPhysicalModelApp(), + AnimatedPositionedApp(), + AnimatedPositionedDirectionalApp(), + AnimatedSizeApp(), + AnimatedSwitcherApp(), + AppbarApp(), + ButtonsApp(), + BackdropFilterApp(), + BannerApp(), + BaselineApp(), + BorderApp(), + BottomAppBarApp(), + BottomNavigationBarApp(), + BuildApp(), + CardApp(), + CircleAvatorApp(), + CupertinoActionSheetApp(), + IndicatorApp(), + CupertinoContextMenuApp(), + CupertinoDatePickeruApp(), + CupertinoFullscreenDialogTransitionApp(), + CupertinoPageScaffoldApp(), + CupertinoPickerApp(), + ScrollbarApp(), + SliderApp(), + RefreshIndicatorApp(), + SwitchApp(), + CupertinoTabBarApp(), + TextFieldApp(), + ClipRectApp(), + CustomMultiChildLayoutApp(), + CustomPaintApp(), + CustomScrollViewApp(), + CustomSingleChildLayoutApp(), + DataTableApp(), + DecoratedBoxApp(), + DecoratedBoxTransitionApp(), + TextStyleApp(), + DirectionlyApp(), + Widgets2App(), + ScraaggableScrollableActuatorApp(), + DraggableScrollableSheetApp(), + DropdownButtonFromFieldApp(), + FlexiableApp(), + ExpansionTileApp(), + FadeTransitionApp(), + DialogsApp(), + WrapApp(), + FittedBoxApp(), + FlexibleApp(), + FlexibleSpaceBarApp(), + DemoFlowPopMenuApp(), + DemoFlowCircelApp(), + DemoFlowMenuApp(), + TextField222App(), + FutureBuilderApp(), + GestureDetectorApp(), + HeroApp(), + IntrinsicHeightApp(), + NestedScrollViewApp(), + NotificationListenerApp(), + PageViewApp(), + FractionallySizedBoxApp(), + ]; + + var _listDisplay = null; + + @override + Widget build(BuildContext context) => Scaffold( + backgroundColor: Colors.white, + primary: true, + appBar: _searchAppBarWidget, + body: SafeArea(child: buildList(context)), + ); + + FocusNode _focusNode = new FocusNode(); + TextEditingController _controller = TextEditingController(); + + PreferredSizeWidget get _searchAppBarWidget => SearchAppBarWidget( + focusNode: _focusNode, + controller: _controller, + elevation: 2.0, + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: Icon(Icons.arrow_back), + ), + inputFormatters: [LengthLimitingTextInputFormatter(50)], + onChangedCallback: (str) { + if(str.isNotEmpty) { + setState(() { + // double _items.clear() + LogUtil.e('onChangeCallBack -> $str'); + var tmp = list + .where((e) => + e.toStringShort().toLowerCase().contains(str.toLowerCase())) + .toList(); + _listDisplay = tmp; + }); + } else { + setState(() { + _listDisplay = null; + }); + } + }, + onEditingComplete: () { + showToast('onEditingComplete!'); + setState(() { + _listDisplay = null; + }); + }, + ); + + Widget buildList(BuildContext context) { + if (_listDisplay == null) { + list.sort((a, b) { + var aName = a.toStringShort().toLowerCase(); + var bName = b.toStringShort().toLowerCase(); + return aName.compareTo(bName); + }); + _listDisplay = list; + } + return _buildListView(_listDisplay); + } + + _buildListView(_list) { + return ListView.builder( + // itemBuilder: (BuildContext context, int index) => buildSizeBox(context, index, _listDisplay[index]), + itemBuilder: (BuildContext context, int index) => SizedBox( + height: 30, + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 10, bottom: 2), + child: ElevatedButton( + child: Text('IN'), + onPressed: () { + LogUtil.d(_list[index]); + Navigator.push(context, MaterialPageRoute(builder: (context) { + return _list[index]; + })); + }, + ), + ), + SizedBox( + width: 10, + ), + Expanded(child: Text(_list[index].toStringShort())), + Padding( + padding: EdgeInsets.only(right: 10, bottom: 2), + child: ElevatedButton( + child: Text('源'), + onPressed: () { + LogUtil.d(_list[index]); + if (_list[index] is HighMixin) { + var h = (_list[index] as HighMixin).getHigh(); + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return HighLight( + title: h.title, + text: h.text, + outWidget: _list[index], + ); + })); + } else { + showToast("未实现mixin HighMixin"); + } + }, + ), + ), + ], + ), + ), + itemCount: _list.length, + ); + } + + buildSizeBox(BuildContext context, int index, Widget app) => SizedBox( + height: 30, + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 10, bottom: 2), + child: ElevatedButton( + child: Text('IN'), + onPressed: () { + LogUtil.d(app); + Navigator.push(context, MaterialPageRoute(builder: (context) { + return app; + })); + }, + ), + ), + SizedBox( + width: 10, + ), + Expanded(child: Text(app.toStringShort())), + Padding( + padding: EdgeInsets.only(right: 10, bottom: 2), + child: ElevatedButton( + child: Text('源'), + onPressed: () { + LogUtil.d(app); + if (app is HighMixin) { + var h = (app as HighMixin).getHigh(); + Navigator.push(context, + MaterialPageRoute(builder: (context) { + return HighLight( + title: h.title, + text: h.text, + outWidget: app, + ); + })); + } else { + showToast("未实现mixin HighMixin"); + } + }, + ), + ), + ], + ), + ); +} + +class CardItem extends StatelessWidget { + final Widget outWidget; // 从外面传进来的widget,要显示 + + const CardItem({Key key, this.outWidget}) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + showToast(outWidget.toStringShort()); + }, + child: Text(outWidget.toStringShort()), + ); + } +} diff --git a/FlutterHelper/flutter_helper/lib/widgets2/functions.dart b/FlutterHelper/flutter_helper/lib/widgets2/functions.dart new file mode 100644 index 00000000..b60bd35a --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets2/functions.dart @@ -0,0 +1,22 @@ + +class Functions {} + +// typedef BackPressCallback = Future Function(BackPressType); //按返回键时触发 + +typedef OnChangedCallback = Future Function(); //输入内容变化时触发 +// +// typedef OnSubmitCallback = Future Function( +// Object, Operation, BuildContext); //输入完成时触发 + +typedef OnItemClick = Future Function(Object); //控件点击时触发 + +typedef OnItemDoubleClick = Future Function(Object); //控件点击时触发 + +typedef OnItemLongClick = Future Function(Object); //控件点击时触发 + +typedef OnCallBack = Future Function(Object); + +typedef OnCallBackWithType = Future Function(int, Object); + +// typedef OnUpdateCallback = Future Function( +// Object, int, MessageEntity); //数据更新时触发 diff --git a/FlutterHelper/flutter_helper/lib/widgets2/more_widgets.dart b/FlutterHelper/flutter_helper/lib/widgets2/more_widgets.dart new file mode 100644 index 00000000..2b1d2600 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets2/more_widgets.dart @@ -0,0 +1,35 @@ +import 'package:flutter_helper/samples/flutter_neumorphic/lib/flutter_neumorphic.dart'; + +import 'functions.dart'; + +class MoreWidgets { + + /* + * 生成常用的AppBar + */ + static Widget buildAppBar(BuildContext context, String text, + {double fontSize: 18.0, + double height: 50.0, + double elevation: 0.5, + Widget leading, + bool centerTitle: false, + List actions, + OnItemDoubleClick onItemDoubleClick}) { + return PreferredSize( + child: GestureDetector( + onDoubleTap: () { + if (null != onItemDoubleClick) { + onItemDoubleClick(null); + } + }, + child: AppBar( + elevation: elevation, //阴影 + centerTitle: centerTitle, + title: Text(text, style: TextStyle(fontSize: fontSize)), + leading: leading, + actions: actions, + )), + preferredSize: Size.fromHeight(height)); + } + +} \ No newline at end of file diff --git a/FlutterHelper/flutter_helper/lib/widgets2/search_appbar.dart b/FlutterHelper/flutter_helper/lib/widgets2/search_appbar.dart new file mode 100644 index 00000000..a5abeea8 --- /dev/null +++ b/FlutterHelper/flutter_helper/lib/widgets2/search_appbar.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_helper/flutter_tags/lib/flutter_tags.dart'; + +import 'more_widgets.dart'; + +class SearchAppBarWidget extends StatefulWidget implements PreferredSizeWidget { + final double height; + final double elevation; //阴影 + final Widget leading; + final String hintText; + final FocusNode focusNode; + final TextEditingController controller; + final IconData prefixIcon; + final List inputFormatters; + final VoidCallback onEditingComplete; + final OnChangedCallback onChangedCallback; + + const SearchAppBarWidget( + {Key key, + this.height: 46.0, + this.elevation: 0.5, + this.leading, + this.hintText = '请输入关键词', + this.focusNode, + this.controller, + this.prefixIcon = Icons.search, + this.inputFormatters, + this.onEditingComplete, + this.onChangedCallback}) + : super(key: key); + + @override + State createState() => SearchAppBarState(); + + @override + Size get preferredSize => Size.fromHeight(height); +} + +class SearchAppBarState extends State { + bool _hasdeleteIocn = false; + + @override + Widget build(BuildContext context) => PreferredSize( + child: Stack( + children: [ + Offstage( + offstage: false, + child: MoreWidgets.buildAppBar( + context, + '', + elevation: 2.0, + leading: widget.leading, + ), + ), + Offstage( + offstage: false, + child: Container( + padding: const EdgeInsets.only(left: 30.0, top: 26.0), + child: TextField( + focusNode: widget.focusNode, + keyboardType: TextInputType.text, + textInputAction: TextInputAction.done, + controller: widget.controller, + maxLines: 1, + inputFormatters: widget.inputFormatters, + decoration: _inputDecoration(), + onChanged: (str) { + if (null != widget.onChangedCallback) { + widget.onChangedCallback(str); + } + setState(() { + if (str.isEmpty) { + _hasdeleteIocn = false; + } else { + _hasdeleteIocn = true; + } + }); + }, + onEditingComplete: widget.onEditingComplete, + ), + ), + ), + ], + ), + preferredSize: Size.fromHeight(widget.height), + ); + + InputDecoration _inputDecoration() => InputDecoration( + hintText: widget.hintText, + hintStyle: TextStyle(color: Colors.black, fontSize: 16.5), + prefixIcon: Padding( + padding: EdgeInsetsDirectional.only(start: 24.0), + child: Icon(widget.prefixIcon, color: Colors.black), + ), + suffixIcon: Padding( + padding: EdgeInsetsDirectional.only( + start: 2.0, + end: _hasdeleteIocn ? 20.0 : 0, + ), + child: !_hasdeleteIocn + ? Text('') + : InkWell( + onTap: () { + if (null != widget.onChangedCallback) { + widget.onChangedCallback(''); + } + setState(() { + widget.controller.text = ''; + _hasdeleteIocn = false; + }); + }, + child: Icon(Icons.clear, size: 18.9, color: Colors.black), + ), + ), + contentPadding: EdgeInsets.fromLTRB(0, 10, 0, 0), + filled: true, + fillColor: Colors.transparent, + border: InputBorder.none, + ); +} diff --git a/FlutterHelper/flutter_helper/locale/i18n_en.json b/FlutterHelper/flutter_helper/locale/i18n_en.json new file mode 100644 index 00000000..9e884000 --- /dev/null +++ b/FlutterHelper/flutter_helper/locale/i18n_en.json @@ -0,0 +1,12 @@ +{ +"app_name":"Flutter UI-Kit ", +"enter_code_label":"Phone Number", +"enter_code_hint":"10 Digit Phone Number", +"enter_otp_label":"OTP", +"enter_otp_hint":"4 Digit OTP", +"get_otp":"Get OTP", +"resend_otp":"Resend OTP", +"login":"Login", +"enter_valid_number":"Enter 10 digit phone number", +"enter_valid_otp":"Enter 4 digit otp" +} diff --git a/FlutterHelper/flutter_helper/locale/i18n_hi.json b/FlutterHelper/flutter_helper/locale/i18n_hi.json new file mode 100644 index 00000000..3a298535 --- /dev/null +++ b/FlutterHelper/flutter_helper/locale/i18n_hi.json @@ -0,0 +1,12 @@ +{ + "app_name":"फ़्लटर यूआई-किट ", + "enter_code_label":"फ़ोन नम्बर", + "enter_code_hint":"10 डिजिट का फ़ोन नम्बर ", + "enter_otp_label":"ओ टी पी", + "enter_otp_hint":"4 डिजिट ओ टी पी", + "get_otp":"ओ टी पी मँगायें ", + "resend_otp":"ओ टी पी दुबारा मँगायें", + "login":"लॉगिन", + "enter_valid_number":"10 डिजिट का ही नम्बर डालें", + "enter_valid_otp":"4 डिजिट का ही ओ टी पी डालें" +} diff --git a/FlutterHelper/flutter_helper/pubspec.lock b/FlutterHelper/flutter_helper/pubspec.lock new file mode 100644 index 00000000..5cf62460 --- /dev/null +++ b/FlutterHelper/flutter_helper/pubspec.lock @@ -0,0 +1,1123 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.flutter-io.cn" + source: hosted + version: "22.0.0" + adaptive_theme: + dependency: "direct main" + description: + name: adaptive_theme + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.7.1" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.2" + args: + dependency: transitive + description: + name: args + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0" + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.6.1" + audioplayers: + dependency: "direct main" + description: + name: audioplayers + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.19.1" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0-nullsafety.0" + base58check: + dependency: transitive + description: + name: base58check + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + bech32: + dependency: transitive + description: + name: bech32 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.3.2" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.flutter-io.cn" + source: hosted + version: "7.1.0" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.0" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.3" + clock: + dependency: "direct main" + description: + name: clock + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.7.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.15.0" + connectivity: + dependency: "direct main" + description: + name: connectivity + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.6" + connectivity_for_web: + dependency: transitive + description: + name: connectivity_for_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.4.0" + connectivity_macos: + dependency: transitive + description: + name: connectivity_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.0" + connectivity_platform_interface: + dependency: transitive + description: + name: connectivity_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + convert: + dependency: "direct main" + description: + name: convert + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + coverage: + dependency: transitive + description: + name: coverage + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.3" + crypto: + dependency: "direct main" + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.3" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.3" + decimal: + dependency: "direct main" + description: + name: decimal + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + dotted_border: + dependency: "direct main" + description: + name: dotted_border + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.7" + equatable: + dependency: "direct main" + description: + name: equatable + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.3" + extended_masked_text: + dependency: "direct main" + description: + name: extended_masked_text + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.1" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.2" + file: + dependency: transitive + description: + name: file + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.1.2" + file_picker: + dependency: transitive + description: + name: file_picker + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.4" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.10.11" + flip_card: + dependency: "direct main" + description: + name: flip_card + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_blurhash: + dependency: transitive + description: + name: flutter_blurhash + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.2" + flutter_colorpicker: + dependency: "direct main" + description: + name: flutter_colorpicker + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.4.0" + flutter_cupertino_settings: + dependency: "direct main" + description: + name: flutter_cupertino_settings + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.0" + flutter_highlight: + dependency: "direct main" + description: + name: flutter_highlight + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.7.0" + flutter_keyboard_visibility: + dependency: "direct main" + description: + name: flutter_keyboard_visibility + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.3" + flutter_keyboard_visibility_platform_interface: + dependency: transitive + description: + name: flutter_keyboard_visibility_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_web: + dependency: transitive + description: + name: flutter_keyboard_visibility_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_masked_text: + dependency: "direct main" + description: + name: flutter_masked_text + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.8.0" + flutter_material_pickers: + dependency: "direct main" + description: + name: flutter_material_pickers + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.0" + flutter_multi_formatter: + dependency: "direct main" + description: + name: flutter_multi_formatter + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.2" + flutter_native_timezone: + dependency: "direct main" + description: + name: flutter_native_timezone + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + flutter_offline: + dependency: "direct main" + description: + name: flutter_offline + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + flutter_page_indicator: + dependency: transitive + description: + name: flutter_page_indicator + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.3" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + flutter_sequence_animation: + dependency: "direct main" + description: + name: flutter_sequence_animation + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + flutter_staggered_grid_view: + dependency: "direct main" + description: + name: flutter_staggered_grid_view + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.4" + flutter_swiper: + dependency: "direct main" + description: + name: flutter_swiper + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_webview_plugin: + dependency: "direct main" + description: + name: flutter_webview_plugin + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.11" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.1" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + url: "https://pub.flutter-io.cn" + source: hosted + version: "9.1.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + highlight: + dependency: transitive + description: + name: highlight + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.7.0" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.13.3" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.0" + image: + dependency: "direct main" + description: + name: image + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.2" + intl: + dependency: "direct main" + description: + name: intl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.3" + js: + dependency: transitive + description: + name: js + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.3" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.10" + meta: + dependency: "direct main" + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + mockito: + dependency: "direct dev" + description: + name: mockito + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.7" + mustache: + dependency: "direct dev" + description: + name: mustache + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.1" + nested: + dependency: transitive + description: + name: nested + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + octo_image: + dependency: transitive + description: + name: octo_image + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0+1" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.0" + path_drawing: + dependency: transitive + description: + name: path_drawing + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.4.1+1" + path_parsing: + dependency: transitive + description: + name: path_parsing + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.4" + path_provider: + dependency: "direct main" + description: + name: path_provider + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.3" + pattern_formatter: + dependency: "direct main" + description: + name: pattern_formatter + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + pedantic: + dependency: "direct dev" + description: + name: pedantic + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.11.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.1.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.5.0" + process: + dependency: transitive + description: + name: process + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.2.3" + protobuf: + dependency: "direct dev" + description: + name: protobuf + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.4" + provider: + dependency: "direct main" + description: + name: provider + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.5" + rational: + dependency: transitive + description: + name: rational + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.1" + rect_getter: + dependency: "direct main" + description: + name: rect_getter + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + rxdart: + dependency: "direct main" + description: + name: rxdart + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.26.0" + sensors: + dependency: "direct main" + description: + name: sensors + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.3" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.6" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + simple_gesture_detector: + dependency: "direct main" + description: + name: simple_gesture_detector + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.3" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + source_maps: + dependency: transitive + description: + name: source_maps + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.10.10" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.1" + spring_button: + dependency: "direct main" + description: + name: spring_button + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0+3" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0+2" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" + syntax_highlighter: + dependency: "direct main" + description: + name: syntax_highlighter + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + test: + dependency: "direct dev" + description: + name: test + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.16.8" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.0" + test_core: + dependency: transitive + description: + name: test_core + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.19" + timezone: + dependency: "direct main" + description: + name: timezone + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.7.0" + transformer_page_view: + dependency: transitive + description: + name: transformer_page_view + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.6" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + underline_indicator: + dependency: "direct main" + description: + name: underline_indicator + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.4" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.0.9" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.4" + url_launcher_web: + dependency: "direct main" + description: + name: url_launcher_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.4" + vector_math: + dependency: "direct main" + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + very_good_analysis: + dependency: "direct dev" + description: + name: very_good_analysis + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.0" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.2.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + wifi_info_flutter: + dependency: "direct main" + description: + name: wifi_info_flutter + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + wifi_info_flutter_platform_interface: + dependency: transitive + description: + name: wifi_info_flutter_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + win32: + dependency: transitive + description: + name: win32 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.5" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.1.2" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.0" +sdks: + dart: ">=2.13.0 <3.0.0" + flutter: ">=2.0.0" diff --git a/FlutterHelper/flutter_helper/pubspec.yaml b/FlutterHelper/flutter_helper/pubspec.yaml new file mode 100644 index 00000000..48935140 --- /dev/null +++ b/FlutterHelper/flutter_helper/pubspec.yaml @@ -0,0 +1,202 @@ +name: flutter_helper +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_localizations: # 国际化 + sdk: flutter + intl: ^0.17.0 # 国际化语言 + # https://github.com/a14n/dart-decimal + decimal: ">=1.0.0 <3.0.0" + # https://github.com/dart-lang/crypto + crypto: ">=3.0.0 <5.0.0" + # https://github.com/dart-lang/convert + convert: ">=3.0.0 <5.0.0" + fluttertoast: ^4.0.1 + flutter_webview_plugin: ^0.3.5 + http: ^0.13.1 + syntax_highlighter: ^0.1.1 # 语法高亮 + underline_indicator: ^0.0.2 + flutter_staggered_grid_view: ^0.3.0 + flutter_swiper: ^1.1.4 + audioplayers: ^0.19.0 + path_provider: ^2.0.1 + flutter_keyboard_visibility: ^5.0.0 + google_fonts: ^2.0.0 + rect_getter: ^1.0.0 + cached_network_image: ^3.0.0 + spring_button: ^2.0.0 + auto_size_text: ^3.0.0-nullsafety.0 + image: ^3.0.2 + flutter_colorpicker: ^0.4.0 + flutter_highlight: ^0.7.0 + url_launcher: ^6.0.7 + url_launcher_web: ^2.0.1 + provider: ^5.0.0 + flip_card: ^0.5.0 + dotted_border: ^1.0.4 + flutter_sequence_animation: ^3.0.1 + sensors: ^2.0.0 + equatable: ^2.0.0 + vector_math: ^2.1.0 + rxdart: ^0.26.0 + flutter_masked_text: ^0.8.0 + + extended_masked_text: ^2.1.0 + meta: ^1.2.4 + flutter_cupertino_settings: ^0.5.0 + flutter_material_pickers: ^3.0.0 + pattern_formatter: ^2.0.0 # used for localized doubles + flutter_multi_formatter: ^2.0.2 # used for localized phone numbers + adaptive_theme: ^2.0.0 + # google_fonts: ^2.0.0 + font_awesome_flutter: ^9.0.0 + simple_gesture_detector: ^0.2.0 + timezone: ^0.7.0-nullsafety.0 + clock: ^1.1.0 + flutter_native_timezone: ^1.0.4 + connectivity: ^3.0.2 + wifi_info_flutter: ^2.0.0 + cupertino_icons: ^1.0.0 + flutter_offline: ^2.0.0 +# uuid: ^2.0.4 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_localizations: + sdk: flutter + very_good_analysis: ^2.0.0 + test: + mockito: ^5.0.2 + pedantic: ^1.11.0 + mustache: ^1.1.1 + protobuf: ^1.0.1 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + generate: true # 国际化语言 + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - images/ + + - sounds/box_down.mp3 + - sounds/box_up.mp3 + - sounds/icon_choose.mp3 + - sounds/icon_focus.mp3 + - sounds/short_press_like.mp3 + + - readme_resources/ + + - img/ + - img/bg/ + - img/source/gift.ai + - res/portrait.jpeg + + - assets/ + - assets/images/ + - assets/timezone/2018c.tzf + - locale/i18n_en.json + - locale/i18n_hi.json + + - google_fonts/ + + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + fonts: + - family: OpenSans + fonts: + - asset: fonts/OpenSans-ExtraBold.ttf + weight: 800 + - family: U and I + fonts: + - asset: fonts/fontYouandiModernTR.ttf + - family: Satisfy + fonts: + - asset: fonts/Satisfy-Regular.ttf + - family: NeumorphicIcons + fonts: + - asset: fonts/NeumorphicIcons.ttf + - family: Samsung + fonts: + - asset: fonts/SamsungSans-Bold.ttf + - family: Themify + fonts: + - asset: assets/fonts/themify.ttf + - family: LineAwesome + fonts: + - asset: assets/fonts/line-awesome.ttf + - family: Timeburner + fonts: + - asset: assets/fonts/timeburnernormal.ttf + - asset: assets/fonts/timeburnerbold.ttf + weight: 700 + - family: Quicksand + fonts: + - asset: assets/fonts/Quicksand-Medium.ttf + style: normal + - asset: assets/fonts/Quicksand_Bold.otf + weight: 700 + + - family: Raleway + fonts: + - asset: assets/fonts/Raleway-Regular.ttf + style: normal + - asset: assets/fonts/Raleway-Medium.ttf + - family: CustomFont + fonts: + - asset: assets/CustomFont.ttf + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages +flutter_intl: + enabled: true diff --git a/FlutterHelper/flutter_helper/readme_resources/background_color_bar.png b/FlutterHelper/flutter_helper/readme_resources/background_color_bar.png new file mode 100644 index 00000000..3d63cb80 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/background_color_bar.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/basic_bar.png b/FlutterHelper/flutter_helper/readme_resources/basic_bar.png new file mode 100644 index 00000000..fa003fbe Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/basic_bar.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/complete_bar.png b/FlutterHelper/flutter_helper/readme_resources/complete_bar.png new file mode 100644 index 00000000..0e1a43de Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/complete_bar.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/floating_style.png b/FlutterHelper/flutter_helper/readme_resources/floating_style.png new file mode 100644 index 00000000..e5ced095 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/floating_style.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/flushbar_animated.gif b/FlutterHelper/flutter_helper/readme_resources/flushbar_animated.gif new file mode 100644 index 00000000..b392098d Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/flushbar_animated.gif differ diff --git a/FlutterHelper/flutter_helper/readme_resources/flushbar_logo.png b/FlutterHelper/flutter_helper/readme_resources/flushbar_logo.png new file mode 100644 index 00000000..cf2a2acf Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/flushbar_logo.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/gradient_bar.png b/FlutterHelper/flutter_helper/readme_resources/gradient_bar.png new file mode 100644 index 00000000..24dd5091 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/gradient_bar.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/grounded_style.png b/FlutterHelper/flutter_helper/readme_resources/grounded_style.png new file mode 100644 index 00000000..c018ab97 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/grounded_style.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/icon_and_button_bar.png b/FlutterHelper/flutter_helper/readme_resources/icon_and_button_bar.png new file mode 100644 index 00000000..4bc86c54 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/icon_and_button_bar.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/input_bar.png b/FlutterHelper/flutter_helper/readme_resources/input_bar.png new file mode 100644 index 00000000..1c3c5516 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/input_bar.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/left_bar_indicator.png b/FlutterHelper/flutter_helper/readme_resources/left_bar_indicator.png new file mode 100644 index 00000000..6cf627f2 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/left_bar_indicator.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/padding_and_radius.png b/FlutterHelper/flutter_helper/readme_resources/padding_and_radius.png new file mode 100644 index 00000000..77cbadd8 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/padding_and_radius.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/position_bar.png b/FlutterHelper/flutter_helper/readme_resources/position_bar.png new file mode 100644 index 00000000..35228db7 Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/position_bar.png differ diff --git a/FlutterHelper/flutter_helper/readme_resources/text_bar.png b/FlutterHelper/flutter_helper/readme_resources/text_bar.png new file mode 100644 index 00000000..fe3aea1b Binary files /dev/null and b/FlutterHelper/flutter_helper/readme_resources/text_bar.png differ diff --git a/FlutterHelper/flutter_helper/res/portrait.jpeg b/FlutterHelper/flutter_helper/res/portrait.jpeg new file mode 100644 index 00000000..9715c0c0 Binary files /dev/null and b/FlutterHelper/flutter_helper/res/portrait.jpeg differ diff --git a/FlutterHelper/flutter_helper/sounds/box_down.mp3 b/FlutterHelper/flutter_helper/sounds/box_down.mp3 new file mode 100644 index 00000000..6fa656b4 Binary files /dev/null and b/FlutterHelper/flutter_helper/sounds/box_down.mp3 differ diff --git a/FlutterHelper/flutter_helper/sounds/box_up.mp3 b/FlutterHelper/flutter_helper/sounds/box_up.mp3 new file mode 100644 index 00000000..255982ea Binary files /dev/null and b/FlutterHelper/flutter_helper/sounds/box_up.mp3 differ diff --git a/FlutterHelper/flutter_helper/sounds/icon_choose.mp3 b/FlutterHelper/flutter_helper/sounds/icon_choose.mp3 new file mode 100644 index 00000000..71d99b3f Binary files /dev/null and b/FlutterHelper/flutter_helper/sounds/icon_choose.mp3 differ diff --git a/FlutterHelper/flutter_helper/sounds/icon_focus.mp3 b/FlutterHelper/flutter_helper/sounds/icon_focus.mp3 new file mode 100644 index 00000000..ea55d424 Binary files /dev/null and b/FlutterHelper/flutter_helper/sounds/icon_focus.mp3 differ diff --git a/FlutterHelper/flutter_helper/sounds/short_press_like.mp3 b/FlutterHelper/flutter_helper/sounds/short_press_like.mp3 new file mode 100644 index 00000000..bff69545 Binary files /dev/null and b/FlutterHelper/flutter_helper/sounds/short_press_like.mp3 differ diff --git a/FlutterHelper/flutter_helper/test/widget_test.dart b/FlutterHelper/flutter_helper/test/widget_test.dart new file mode 100644 index 00000000..a635895b --- /dev/null +++ b/FlutterHelper/flutter_helper/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_helper/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + // await tester.pumpWidget(MyApp()); + // + // // Verify that our counter starts at 0. + // expect(find.text('0'), findsOneWidget); + // expect(find.text('1'), findsNothing); + // + // // Tap the '+' icon and trigger a frame. + // await tester.tap(find.byIcon(Icons.add)); + // await tester.pump(); + // + // // Verify that our counter has incremented. + // expect(find.text('0'), findsNothing); + // expect(find.text('1'), findsOneWidget); + }); +} diff --git a/FlutterHelper/flutter_helper/web/favicon.png b/FlutterHelper/flutter_helper/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/FlutterHelper/flutter_helper/web/favicon.png differ diff --git a/FlutterHelper/flutter_helper/web/icons/Icon-192.png b/FlutterHelper/flutter_helper/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/FlutterHelper/flutter_helper/web/icons/Icon-192.png differ diff --git a/FlutterHelper/flutter_helper/web/icons/Icon-512.png b/FlutterHelper/flutter_helper/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/FlutterHelper/flutter_helper/web/icons/Icon-512.png differ diff --git a/FlutterHelper/flutter_helper/web/index.html b/FlutterHelper/flutter_helper/web/index.html new file mode 100644 index 00000000..0081e189 --- /dev/null +++ b/FlutterHelper/flutter_helper/web/index.html @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + example + + + + + + + diff --git a/FlutterHelper/flutter_helper/web/manifest.json b/FlutterHelper/flutter_helper/web/manifest.json new file mode 100644 index 00000000..8c012917 --- /dev/null +++ b/FlutterHelper/flutter_helper/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git "a/FlutterHelper/flutter_helper/\350\265\204\346\226\231/routers.md" "b/FlutterHelper/flutter_helper/\350\265\204\346\226\231/routers.md" new file mode 100644 index 00000000..9b70b578 --- /dev/null +++ "b/FlutterHelper/flutter_helper/\350\265\204\346\226\231/routers.md" @@ -0,0 +1,218 @@ +``` +MaterialApp.router( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + visualDensity: VisualDensity.adaptivePlatformDensity, + ), + routeInformationParser: MyRouteParser(), + routerDelegate: delegate, +) +``` + +``` +class MyRouterDelegate extends RouterDelegate with PopNavigatorRouterDelegateMixin, ChangeNotifier{ + final _stack = []; + + static MyRouteDelegate of(BuildContext context) { + final delegate = Router.of(context).routerDelegate; + assert(delegate is MyRouteDelegate, 'Delegate type must match'); + return delegate as MyRouteDelegate; + } + + MyRouteDelegate({ + @required this.onGenerateRoute, + }); + + //... + Widget build(BuildContext context) { + print('${describeIdentiy(this)}.stack: $_stack'); + return Navigator( + key: navigatorKey, + onPopPage: _onPage, + pages: [ + for (final name in _stack) { + MyPage( + key: ValueKey(name), + name: name, + routeFactory: onGenerateRoute, + ), + } + ], + ); + } +} +``` + + +```dart +class MyRouteDelegate extends RouterDelegate + with PopNavigatorRouterDelegateMixin, ChangeNotifier { + final _stack = []; + + static MyRouteDelegate of(BuildContext context) { + final delegate = Router.of(context).routerDelegate; + assert(delegate is MyRouteDelegate, 'Delegate type must match'); + return delegate as MyRouteDelegate; + } + + MyRouteDelegate({ + @required this.onGenerateRoute, + }); + + final RouteFactory onGenerateRoute; + + @override + GlobalKey navigatorKey = GlobalKey(); + + @override + String get currentConfiguration => _stack.isNotEmpty ? _stack.last : null; + + List get stack => List.unmodifiable(_stack); + + void push(String newRoute) { + _stack.add(newRoute); + notifyListeners(); + } + + void pop() { + if (_stack.isNotEmpty) { + _stack.remove(_stack.last); + } + notifyListeners(); + } + + @override + Future setInitialRoutePath(String configuration) { + return setNewRoutePath(configuration); + } + + @override + Future setNewRoutePath(String configuration) { + print('setNewRoutePath $configuration'); + _stack + ..clear() + ..add(configuration); + return SynchronousFuture(null); + } + + bool _onPopPage(Route route, dynamic result) { + if (_stack.isNotEmpty) { + if (_stack.last == route.settings.name) { + _stack.remove(route.settings.name); + notifyListeners(); + } + } + return route.didPop(result); + } + + @override + Widget build(BuildContext context) { + print('${describeIdentity(this)}.stack: $_stack'); + return Navigator( + key: navigatorKey, + onPopPage: _onPopPage, + pages: [ + for (final name in _stack) + MyPage( + key: ValueKey(name), + name: name, + ), + ], + ); + } +} + +``` + + + +# RouterParser + +```dart +class MyRouteParse extends RouteInformationParser { + @override + Future parseRouteInformation(RouteInformation routeInformation){ + return synchronousFuture(routeInfomation.location); + } + + @override + RouteInformation restoreRouteInformation(String configuration) { + return RouteInfomation(location: configuration); + } +} +``` + + + +# VeggieRouteInformationParser + +```dart + class VeggieRouteInformationParser extends RouteInformationparser { + @override + Future parseRouteInformation(RouteInformation routeInformation) async { + print("parseRouteInformation"); + final uri = Uri.parse(routeInformation.location); + // Handle '/' + if (uri.pathSegments.length == 0) { + return VeggieRoutePath.home(); + } + // Handle '/vegggie/:id' + if (uri.pathSegments.length == 2) { + if (uri.pathSegments[0] != 'veggie') return VeggieRoutePath.unknown(); + var remainint = uri.pathSegments[1]; + var id = int.tryParse(remaining); + if (id == null) return VeggieRoutePath.unknown(); + return VeggieRoutePath.details(id); + } + return VeggieRoutePath.unkonown(); + } + @override + RouteInformation restoreRouteInformation(VeggieRoutePath path) { + print("restoreRouteInformation"); + if (path.isUnknown) { + return RouteInformation(location: '/404'); + } + if (path.isHomePage) { + return RouteInformation(location: '/'); + } + if (path.isDetailsPage) { + return RouteInformation(location: '/veggie/${path.id}'); + } + return null; + } + } + +class VeggieRoutePath { + final int id; + final bool isUnknown; + + VeggieRoutePath.home() : id = null, isUnknown = false; + + VeggieRoutePath.details(this.id) : isUnknown = false; + + VeggieRoutePath.unknown() + : id = null, + isUnknown = true; + + bool get isHomePage => id == null; + + bool get isDetailsPage => id != null; +} + +``` + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/.flutter-plugins-dependencies b/FlutterHelper/flutter_trip/.flutter-plugins-dependencies new file mode 100644 index 00000000..49f416b2 --- /dev/null +++ b/FlutterHelper/flutter_trip/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_splash_screen","path":"/Users/flannery/Library/Android/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_splash_screen-0.1.0/","dependencies":[]},{"name":"flutter_webview_plugin","path":"/Users/flannery/Library/Android/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_webview_plugin-0.3.11/","dependencies":[]}],"android":[{"name":"flutter_splash_screen","path":"/Users/flannery/Library/Android/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_splash_screen-0.1.0/","dependencies":[]},{"name":"flutter_webview_plugin","path":"/Users/flannery/Library/Android/flutter/.pub-cache/hosted/pub.flutter-io.cn/flutter_webview_plugin-0.3.11/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_splash_screen","dependencies":[]},{"name":"flutter_webview_plugin","dependencies":[]}],"date_created":"2021-08-04 13:44:39.130264","version":"2.2.3"} \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/.gitignore b/FlutterHelper/flutter_trip/.gitignore new file mode 100644 index 00000000..fb6c3cad --- /dev/null +++ b/FlutterHelper/flutter_trip/.gitignore @@ -0,0 +1,74 @@ +# Miscellaneous +*.class +*.lock +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# Visual Studio Code related +.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +# Demo +/demo/flutter_hybrid/FlutterHybridiOS/Pods/ \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/.metadata b/FlutterHelper/flutter_trip/.metadata new file mode 100644 index 00000000..24a94d02 --- /dev/null +++ b/FlutterHelper/flutter_trip/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 1407091bfb5bb535630d4d596541817737da8412 + channel: dev + +project_type: app diff --git a/FlutterHelper/flutter_trip/README.md b/FlutterHelper/flutter_trip/README.md new file mode 100644 index 00000000..e9f7f9a1 --- /dev/null +++ b/FlutterHelper/flutter_trip/README.md @@ -0,0 +1,81 @@ + + +这是慕课网官方实战课【[Flutter从入门到进阶-实战携程网App](https://coding.imooc.com/class/321.html)】的项目源码,课件,文档。 + +>课程会不定期更新,建议大家多关注下仓库首页的变更记录以便获得最新的更新内容哦 + +## 概述 + +- 课程接口文档查看[doc](https://git.imooc.com/coding-321/flutter_trip/src/master/doc); +- 课程中所用到的demo查看[demo](https://git.imooc.com/coding-321/flutter_trip/src/master/demo); +- [各章节源码和课件查看指南](https://git.imooc.com/coding-321/flutter_trip#%E5%90%84%E7%AB%A0%E8%8A%82%E6%BA%90%E7%A0%81%E5%92%8C%E8%BE%85%E5%AF%BC%E6%96%87%E6%A1%A3%E6%9F%A5%E7%9C%8B%E6%8C%87%E5%8D%97) +- [Flutter必备Dart基础课件](https://git.imooc.com/coding-321/flutter_trip/src/master/doc/Flutter%e5%bf%85%e5%a4%87Dart%e5%9f%ba%e7%a1%80%e8%af%be%e4%bb%b6.md) + + +## 课程辅导答疑 + +[http://coding.imooc.com/learn/qa/321.html](http://coding.imooc.com/learn/qa/321.html) + +## 如何运行? + +1. 安装和配置Flutter开发环境(如已经配置过可跳过),可参考课程[Flutter入门:开发工具准备与开发环境搭建](https://coding.imooc.com/class/321.html)一章的讲解。 +2. 在项目根目录运行`flutter run`或用装有Flutter和Dart插件的IDE运行; +3. Ok,有问题可以在[课程讨论区](https://coding.imooc.com/class/321.html)提issue哦; + +## 各章节源码和辅导文档查看指南 + +>为方便同学们学习,课程为大家提供了课件和各章节的源码,请通过以下方式查看: + +- [实战部分各章节源码查看方法-点击查看](https://git.imooc.com/coding-321/flutter_trip/src/master/doc/如何查看各章节的源码.md) + - [可通过git查看这部分章节的源码](https://git.imooc.com/coding-321/flutter_trip/src/master/doc/如何查看各章节的源码.md) +- 基础部分的文档和源码 + - Flutter入门:开发工具准备与开发环境搭建 + - [Flutter开发环境搭建(Mac)](http://www.imooc.com/article/284328) + - [Flutter开发环境搭建(Windows)](http://www.imooc.com/article/284627) + - Flutter必备Dart基础:Dart快速入门 + - [Dart知识体系](https://coding.imooc.com/learn/questiondetail/134658.html) + - [Flutter之Dart常用数据类型](https://coding.imooc.com/learn/questiondetail/134659.html) + - [带你揭开Flutter中的面向对象](https://coding.imooc.com/learn/questiondetail/134661.html) + - [带你解锁Flutter中常用的Dart方法类型](https://coding.imooc.com/learn/questiondetail/134662.html) + - [带你了解Dart泛型在Flutter中的应用](https://coding.imooc.com/learn/questiondetail/134663.html) + - [有哪些可以用在Flutter上的编程技巧?](https://coding.imooc.com/learn/questiondetail/134664.html) + - Flutter入门:基础知识十六讲 + - [如何使用Flutter包和插件?](https://git.imooc.com/coding-321/flutter_trip/src/4193fc01c4291639e037103acc5d56f14d372ee5/demo/flutter_base_demo) + - [StatelessWidget与基础组件](https://git.imooc.com/coding-321/flutter_trip/src/cd09f057d4484739794ccbb5f823ce5be30ad8b2/demo/flutter_base_demo/) + - [StatefulWidget与基础组件](https://git.imooc.com/coding-321/flutter_trip/src/6290360d1b35ab0064ed0cef3f6d5cc69622268d/demo/flutter_base_demo/) + - [如何进行Flutter布局开发?](https://git.imooc.com/coding-321/flutter_trip/src/afede085ba8413316d4eddad691c5c1658f2f5b5/demo/flutter_base_demo/) + - [如何创建和使用Flutter的路由与导航?](https://git.imooc.com/coding-321/flutter_trip/src/d686c3895c25d24ab8c56fab7228baee2d507b4f/demo/flutter_base_demo/) + - [如何检测用户手势以及处理点击事件?](https://git.imooc.com/coding-321/flutter_trip/src/b11e21c83db3402b890222a946f3ce5f92a71156/demo/flutter_base_demo/) + - [如何导入和使用Flutter的资源文件?](https://git.imooc.com/coding-321/flutter_trip/src/3c6708ccc082ccb7a6aa21947a9ca3df1aa65c37/demo/flutter_base_demo/) + - [如何打开第三方应用?](https://git.imooc.com/coding-321/flutter_trip/src/3fb96817791e144138053df27cc46c0785af3c5e/demo/flutter_base_demo/) + - [如何修改Flutter应用的主题?](https://git.imooc.com/coding-321/flutter_trip/src/c5a34c6af0a245837c1804686817fa440282d1e5/demo/flutter_base_demo/) + - [如何自定义字体?](https://git.imooc.com/coding-321/flutter_trip/src/a38ac2c3016ed811400dbf24fc72320c3d7f30a0/demo/flutter_base_demo) + - [Flutter 页面生命周期实战指南](https://git.imooc.com/coding-321/flutter_trip/src/92ed7837a191d5ef870be56d8a7b0f670904559b/demo/flutter_base_demo/) + - [如何获取Flutter应用的生命周期?](https://git.imooc.com/coding-321/flutter_trip/src/0e713d023df151c2bdbfb67a211c2c6d782834a7/demo/flutter_base_demo/) + - [实战尝鲜】拍照APP开发-图片获取与图片展示](https://git.imooc.com/coding-321/flutter_trip/src/15838a3c030098de8d28b183bd7e723ec354a83c/demo/flutter_base_demo/) + - Flutter入门:Flutter必备基础 + - [图片控件开发详解](https://coding.imooc.com/learn/questiondetail/134875.html) + - [动画Animation开发指南](https://git.imooc.com/coding-321/flutter_trip/src/master/doc/动画Animation开发指南.md) + - Flutter进阶提升:网络编程与数据存储技术 + - [基于Http实现网络操作](https://coding.imooc.com/learn/questiondetail/134644.html) + - [异步:Future与FutureBuilder实用技巧](https://coding.imooc.com/learn/questiondetail/134645.html) + - [JSON解析与复杂模型转换实用技巧](https://coding.imooc.com/learn/questiondetail/134649.html) + - [基于shared_preferences的本地存储操作](https://coding.imooc.com/learn/questiondetail/134650.html) + - Flutter进阶提升:玩转列表组件 + - [基于ListView实现水平和垂直方式滚动的列表](https://coding.imooc.com/learn/questiondetail/134653.html) + - [基于ExpansionTile实现可展开的列表](https://coding.imooc.com/learn/questiondetail/134654.html) + - [基于GridView实现网格布局](https://coding.imooc.com/learn/questiondetail/134655.html) + - [高级功能列表下拉刷新与上拉加载更多功能实现](https://coding.imooc.com/learn/questiondetail/134656.html) + - Flutter进阶提升:Flutter混合开发 + - [Flutter与Android混合开发实战 辅导资料-持续更新](https://coding.imooc.com/learn/questiondetail/150166.html) + - [Flutter与iOS混合开发实战 辅导资料-持续更新](https://coding.imooc.com/learn/questiondetail/150168.html) + - [Flutter与Android通信开发指南](http://coding.imooc.com/learn/questiondetail/135975.html) +- **其他部分的辅导文档和源码查看方法** + - 方法一: -> [通过git查看](https://git.imooc.com/coding-321/flutter_trip/src/master/doc/如何查看各章节的源码.md) + - 方法二: -> 通过锚点查看(锚点只覆盖了部分章节的文档哦): + ![doc-learn-help](http://www.devio.org/io/flutter_app/img/blog/doc-learn-help2.jpg) + + >然后通过如下方式查看锚点中的文档: + ![doc-learn-help](http://www.devio.org/io/flutter_app/img/blog/doc-learn-help1.jpg) + + diff --git a/base/.gitignore b/FlutterHelper/flutter_trip/android/app/.gitignore similarity index 100% rename from base/.gitignore rename to FlutterHelper/flutter_trip/android/app/.gitignore diff --git a/FlutterHelper/flutter_trip/android/app/build.gradle b/FlutterHelper/flutter_trip/android/app/build.gradle new file mode 100644 index 00000000..92564b26 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/app/build.gradle @@ -0,0 +1,88 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + +android { + compileSdkVersion 28 + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + applicationId "org.devio.fluttertrip" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + ndk { + abiFilters "armeabi-v7a","arm64-v8a","x86_64","x86" //只打包flutter所支持的架构,flutter没有armeabi架构的so,加x86的原因是为了能够兼容模拟器 +// abiFilters "armeabi-v7a" //release 时只打"armeabi-v7包 + } + } + + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + } + } + buildTypes { + release { + signingConfig signingConfigs.release + minifyEnabled true //是否启用代码压缩 需要将targetSdkVersion 和 compileSdkVersion 升级到 28 @https://github.com/flutter/flutter/issues/26860#issuecomment-469751224 + useProguard true + + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + + } + } + packagingOptions { + // 确保app与asr_plugin都依赖的libflutter.so libapp.so merge时不冲突@https://github.com/card-io/card.io-Android-SDK/issues/186#issuecomment-427552552 + pickFirst 'lib/x86_64/libflutter.so' + pickFirst 'lib/x86/libflutter.so' + pickFirst 'lib/arm64-v8a/libflutter.so' + pickFirst 'lib/arm64-v8a/libapp.so' + } +} + +flutter { + source '../..' +} + +dependencies { + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation project(':asr_plugin') +} diff --git a/FlutterHelper/flutter_trip/android/app/proguard-rules.pro b/FlutterHelper/flutter_trip/android/app/proguard-rules.pro new file mode 100644 index 00000000..ee23e18d --- /dev/null +++ b/FlutterHelper/flutter_trip/android/app/proguard-rules.pro @@ -0,0 +1,31 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# 注意!!!要配置在 /android/app/proguard-rules.pro中 +-keep class com.baidu.speech.**{*;} +#Flutter Wrapper +-keep class io.flutter.app.** { *; } +-keep class io.flutter.plugin.** { *; } +-keep class io.flutter.util.** { *; } +-keep class io.flutter.view.** { *; } +-keep class io.flutter.** { *; } +-keep class io.flutter.plugins.** { *; } \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/android/app/src/main/AndroidManifest.xml b/FlutterHelper/flutter_trip/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..03041855 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/android/app/src/main/java/org/devio/fluttertrip/MainActivity.java b/FlutterHelper/flutter_trip/android/app/src/main/java/org/devio/fluttertrip/MainActivity.java new file mode 100644 index 00000000..d9ae2bfe --- /dev/null +++ b/FlutterHelper/flutter_trip/android/app/src/main/java/org/devio/fluttertrip/MainActivity.java @@ -0,0 +1,23 @@ +package org.devio.fluttertrip; + +import android.os.Bundle; + +import org.devio.flutter.plugin.asr.AsrPlugin; +import org.devio.flutter.splashscreen.SplashScreen; + +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + SplashScreen.show(this,true); + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + registerSelfPlugin(); + } + + private void registerSelfPlugin() { + AsrPlugin.registerWith(registrarFor("org.devio.flutter.plugin.asr.AsrPlugin")); + } +} diff --git a/FlutterHelper/flutter_trip/android/app/src/main/res/drawable/launch_background.xml b/FlutterHelper/flutter_trip/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/FlutterHelper/flutter_trip/android/app/src/main/res/layout/launch_screen.xml b/FlutterHelper/flutter_trip/android/app/src/main/res/layout/launch_screen.xml new file mode 100644 index 00000000..e7728f3a --- /dev/null +++ b/FlutterHelper/flutter_trip/android/app/src/main/res/layout/launch_screen.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xhdpi/splash_screen.png b/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xhdpi/splash_screen.png new file mode 100644 index 00000000..41a69429 Binary files /dev/null and b/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xhdpi/splash_screen.png differ diff --git a/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xhdpi/splash_screen_bottom.png b/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xhdpi/splash_screen_bottom.png new file mode 100644 index 00000000..b75a001b Binary files /dev/null and b/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xhdpi/splash_screen_bottom.png differ diff --git a/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..4f22df36 Binary files /dev/null and b/FlutterHelper/flutter_trip/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_trip/android/app/src/main/res/values/colors.xml b/FlutterHelper/flutter_trip/android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..613805e9 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #000000 + \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/android/app/src/main/res/values/styles.xml b/FlutterHelper/flutter_trip/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..3df817fc --- /dev/null +++ b/FlutterHelper/flutter_trip/android/app/src/main/res/values/styles.xml @@ -0,0 +1,10 @@ + + + + diff --git a/bitmap/app/.gitignore b/FlutterHelper/flutter_trip/android/asr_plugin/.gitignore similarity index 100% rename from bitmap/app/.gitignore rename to FlutterHelper/flutter_trip/android/asr_plugin/.gitignore diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/build.gradle b/FlutterHelper/flutter_trip/android/asr_plugin/build.gradle new file mode 100644 index 00000000..e64ba055 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/build.gradle @@ -0,0 +1,47 @@ +apply plugin: 'com.android.library' + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} +flutter { + source '../..' +} +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'com.android.support:appcompat-v7:28.0.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' +} diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/libs/bdasr_V3_20180801_d6f298a.jar b/FlutterHelper/flutter_trip/android/asr_plugin/libs/bdasr_V3_20180801_d6f298a.jar new file mode 100755 index 00000000..cc0dc501 Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/libs/bdasr_V3_20180801_d6f298a.jar differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/proguard-rules.pro b/FlutterHelper/flutter_trip/android/asr_plugin/proguard-rules.pro new file mode 100644 index 00000000..65e26cd8 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/proguard-rules.pro @@ -0,0 +1,22 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile +-keep class com.baidu.speech.**{*;} \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/androidTest/java/org/devio/flutter/plugin/asr/ExampleInstrumentedTest.java b/FlutterHelper/flutter_trip/android/asr_plugin/src/androidTest/java/org/devio/flutter/plugin/asr/ExampleInstrumentedTest.java new file mode 100644 index 00000000..4450ff58 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/androidTest/java/org/devio/flutter/plugin/asr/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package org.devio.flutter.plugin.asr; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("org.devio.flutter.plugin.asr.test", appContext.getPackageName()); + } +} diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/AndroidManifest.xml b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/AndroidManifest.xml new file mode 100644 index 00000000..7a2b7ffc --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/AsrManager.java b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/AsrManager.java new file mode 100644 index 00000000..5af7655d --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/AsrManager.java @@ -0,0 +1,91 @@ +package org.devio.flutter.plugin.asr; + +import android.content.Context; +import android.util.Log; + +import com.baidu.speech.EventManager; +import com.baidu.speech.EventManagerFactory; +import com.baidu.speech.asr.SpeechConstant; + +import org.json.JSONObject; + +import java.util.Map; + +public class AsrManager { + private static final String TAG = "AsrManager"; + /** + * SDK 内部核心 EventManager 类 + */ + private EventManager asr; + + // SDK 内部核心 事件回调类, 用于开发者写自己的识别回调逻辑 + private RecogEventAdapter eventListener; + + // 未release前,只能new一个 + private static volatile boolean isInited = false; + + /** + * 初始化 提供 EventManagerFactory需要的Context和RecogEventAdapter + * + * @param context + * @param listener 识别状态和结果回调 + */ + public AsrManager(Context context, OnAsrListener listener) { + if (isInited) { + Log.e(TAG, "还未调用release(),请勿新建一个新类"); + throw new RuntimeException("还未调用release(),请勿新建一个新类"); + } + isInited = true; + // SDK集成步骤 初始化asr的EventManager示例,多次得到的类,只能选一个使用 + asr = EventManagerFactory.create(context, "asr"); + // SDK集成步骤 设置回调event, 识别引擎会回调这个类告知重要状态和识别结果 + asr.registerListener(eventListener = new RecogEventAdapter(listener)); + } + + /** + * @param params + */ + public void start(Map params) { + // SDK集成步骤 拼接识别参数 + String json = new JSONObject(params).toString(); + Log.i(TAG + ".Debug", "识别参数(反馈请带上此行日志)" + json); + asr.send(SpeechConstant.ASR_START, json, null, 0, 0); + } + + + /** + * 提前结束录音等待识别结果。 + */ + public void stop() { + Log.i(TAG, "停止录音"); + // SDK 集成步骤(可选)停止录音 + if (!isInited) { + throw new RuntimeException("release() was called"); + } + asr.send(SpeechConstant.ASR_STOP, "{}", null, 0, 0); + } + + /** + * 取消本次识别,取消后将立即停止不会返回识别结果。 + * cancel 与stop的区别是 cancel在stop的基础上,完全停止整个识别流程, + */ + public void cancel() { + Log.i(TAG, "取消识别"); + if (!isInited) { + throw new RuntimeException("release() was called"); + } + // SDK集成步骤 (可选) 取消本次识别 + asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0); + } + + public void release() { + if (asr == null) { + return; + } + cancel(); + // SDK 集成步骤(可选),卸载listener + asr.unregisterListener(eventListener); + asr = null; + isInited = false; + } +} diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/AsrPlugin.java b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/AsrPlugin.java new file mode 100644 index 00000000..b098a949 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/AsrPlugin.java @@ -0,0 +1,189 @@ +package org.devio.flutter.plugin.asr; + +import android.Manifest; +import android.app.Activity; +import android.content.pm.PackageManager; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Map; + +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.PluginRegistry; + +public class AsrPlugin implements MethodChannel.MethodCallHandler { + private final static String TAG = "AsrPlugin"; + private final Activity activity; + private ResultStateful resultStateful; + private AsrManager asrManager; + + public static void registerWith(PluginRegistry.Registrar registrar) { + MethodChannel channel = new MethodChannel(registrar.messenger(), "asr_plugin"); + AsrPlugin instance = new AsrPlugin(registrar); + channel.setMethodCallHandler(instance); + } + + public AsrPlugin(PluginRegistry.Registrar registrar) { + this.activity = registrar.activity(); + } + + @Override + public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { + initPermission(); + switch (methodCall.method) { + case "start": + resultStateful = ResultStateful.of(result); + start(methodCall, resultStateful); + break; + case "stop": + stop(methodCall,result); + break; + case "cancel": + cancel(methodCall,result); + break; + default: + result.notImplemented(); + } + } + + private void start(MethodCall call, ResultStateful result) { + if (activity == null) { + Log.e(TAG, "Ignored start, current activity is null."); + result.error("Ignored start, current activity is null.", null, null); + return; + } + if (getAsrManager() != null) { + getAsrManager().start(call.arguments instanceof Map ? (Map) call.arguments : null); + } else { + Log.e(TAG, "Ignored start, current getAsrManager is null."); + result.error("Ignored start, current getAsrManager is null.", null, null); + } + } + + private void stop(MethodCall call, MethodChannel.Result result) { + if (asrManager != null) { + asrManager.stop(); + } + } + + private void cancel(MethodCall call, MethodChannel.Result result) { + if (asrManager != null) { + asrManager.cancel(); + } + } + + @Nullable + private AsrManager getAsrManager() { + if (asrManager == null) { + if (activity != null && !activity.isFinishing()) { + asrManager = new AsrManager(activity, onAsrListener); + } + } + return asrManager; + } + /** + * android 6.0 以上需要动态申请权限 + */ + private void initPermission() { + String permissions[] = {Manifest.permission.RECORD_AUDIO, + Manifest.permission.ACCESS_NETWORK_STATE, + Manifest.permission.INTERNET, + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + }; + + ArrayList toApplyList = new ArrayList(); + + for (String perm :permissions){ + if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(activity, perm)) { + toApplyList.add(perm); + //进入到这里代表没有权限. + + } + } + String tmpList[] = new String[toApplyList.size()]; + if (!toApplyList.isEmpty()){ + ActivityCompat.requestPermissions(activity, toApplyList.toArray(tmpList), 123); + } + + } + private OnAsrListener onAsrListener = new OnAsrListener() { + @Override + public void onAsrReady() { + + } + + @Override + public void onAsrBegin() { + + } + + @Override + public void onAsrEnd() { + + } + + @Override + public void onAsrPartialResult(String[] results, RecogResult recogResult) { + + } + + @Override + public void onAsrOnlineNluResult(String nluResult) { + + } + + @Override + public void onAsrFinalResult(String[] results, RecogResult recogResult) { + if (resultStateful != null) { + resultStateful.success(results[0]); + } + } + + @Override + public void onAsrFinish(RecogResult recogResult) { + + } + + @Override + public void onAsrFinishError(int errorCode, int subErrorCode, String descMessage, RecogResult recogResult) { + if (resultStateful != null) { + resultStateful.error(descMessage, null, null); + } + } + + @Override + public void onAsrLongFinish() { + + } + + @Override + public void onAsrVolume(int volumePercent, int volume) { + + } + + @Override + public void onAsrAudio(byte[] data, int offset, int length) { + + } + + @Override + public void onAsrExit() { + + } + + @Override + public void onOfflineLoaded() { + + } + + @Override + public void onOfflineUnLoaded() { + + } + }; +} diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/OnAsrListener.java b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/OnAsrListener.java new file mode 100755 index 00000000..86c2f96d --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/OnAsrListener.java @@ -0,0 +1,109 @@ +package org.devio.flutter.plugin.asr; + +/** + * 与SDK中回调参数的对应关系定义在RecogEventAdapter类中 + */ + +public interface OnAsrListener { + + /** + * CALLBACK_EVENT_ASR_READY + * ASR_START 输入事件调用后,引擎准备完毕 + */ + void onAsrReady(); + + /** + * CALLBACK_EVENT_ASR_BEGIN + * onAsrReady后检查到用户开始说话 + */ + void onAsrBegin(); + + /** + * CALLBACK_EVENT_ASR_END + * 检查到用户开始说话停止,或者ASR_STOP 输入事件调用后, + */ + void onAsrEnd(); + + /** + * CALLBACK_EVENT_ASR_PARTIAL resultType=partial_result + * onAsrBegin 后 随着用户的说话,返回的临时结果 + * + * @param results 可能返回多个结果,请取第一个结果 + * @param recogResult 完整的结果 + */ + void onAsrPartialResult(String[] results, RecogResult recogResult); + + /** + * 语音的在线语义结果 + * + * CALLBACK_EVENT_ASR_PARTIAL resultType=nlu_result + * @param nluResult + */ + void onAsrOnlineNluResult(String nluResult); + + /** + * CALLBACK_EVENT_ASR_PARTIAL resultType=final_result + * 最终的识别结果 + * + * @param results 可能返回多个结果,请取第一个结果 + * @param recogResult 完整的结果 + */ + void onAsrFinalResult(String[] results, RecogResult recogResult); + + /** + * CALLBACK_EVENT_ASR_FINISH + * @param recogResult 完整的结果 + */ + void onAsrFinish(RecogResult recogResult); + + /** + * CALLBACK_EVENT_ASR_FINISH error!=0 + * + * @param errorCode + * @param subErrorCode + * @param descMessage + * @param recogResult + */ + void onAsrFinishError(int errorCode, int subErrorCode, String descMessage, RecogResult recogResult); + + /** + * 长语音识别结束 + */ + void onAsrLongFinish(); + + /** + * CALLBACK_EVENT_ASR_VOLUME + * 音量回调 + * + * @param volumePercent 音量的相对值,百分比,0-100 + * @param volume 音量绝对值 + */ + void onAsrVolume(int volumePercent, int volume); + + /** + * CALLBACK_EVENT_ASR_AUDIO + * @param data pcm格式,16bits 16000采样率 + * + * @param offset + * @param length + */ + void onAsrAudio(byte[] data, int offset, int length); + + /** + * CALLBACK_EVENT_ASR_EXIT + * 引擎完成整个识别,空闲中 + */ + void onAsrExit(); + + /** + * CALLBACK_EVENT_ASR_LOADED + * 离线命令词资源加载成功 + */ + void onOfflineLoaded(); + + /** + * CALLBACK_EVENT_ASR_UNLOADED + * 离线命令词资源释放成功 + */ + void onOfflineUnLoaded(); +} diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/RecogEventAdapter.java b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/RecogEventAdapter.java new file mode 100755 index 00000000..5ffba818 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/RecogEventAdapter.java @@ -0,0 +1,109 @@ +package org.devio.flutter.plugin.asr; + +import android.util.Log; + +import com.baidu.speech.EventListener; +import com.baidu.speech.asr.SpeechConstant; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Created by fujiayi on 2017/6/14. + */ + +public class RecogEventAdapter implements EventListener { + + private OnAsrListener listener; + + private static final String TAG = "RecogEventAdapter"; + + public RecogEventAdapter(OnAsrListener listener) { + this.listener = listener; + } + + // 基于DEMO集成3.1 开始回调事件 + @Override + public void onEvent(String name, String params, byte[] data, int offset, int length) { + String currentJson = params; + String logMessage = "name:" + name + "; params:" + params; + + // logcat 中 搜索RecogEventAdapter,即可以看见下面一行的日志 + Log.i(TAG, logMessage); + if (false) { // 可以调试,不需要后续逻辑 + return; + } + if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_LOADED)) { + listener.onOfflineLoaded(); + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_UNLOADED)) { + listener.onOfflineUnLoaded(); + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_READY)) { + // 引擎准备就绪,可以开始说话 + listener.onAsrReady(); + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_BEGIN)) { + // 检测到用户的已经开始说话 + listener.onAsrBegin(); + + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_END)) { + // 检测到用户的已经停止说话 + listener.onAsrEnd(); + + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) { + RecogResult recogResult = RecogResult.parseJson(params); + // 临时识别结果, 长语音模式需要从此消息中取出结果 + String[] results = recogResult.getResultsRecognition(); + if (recogResult.isFinalResult()) { + listener.onAsrFinalResult(results, recogResult); + } else if (recogResult.isPartialResult()) { + listener.onAsrPartialResult(results, recogResult); + } else if (recogResult.isNluResult()) { + listener.onAsrOnlineNluResult(new String(data, offset, length)); + } + + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_FINISH)) { + // 识别结束, 最终识别结果或可能的错误 + RecogResult recogResult = RecogResult.parseJson(params); + if (recogResult.hasError()) { + int errorCode = recogResult.getError(); + int subErrorCode = recogResult.getSubError(); + Log.e(TAG, "asr error:" + params); + listener.onAsrFinishError(errorCode, subErrorCode, recogResult.getDesc(), recogResult); + } else { + listener.onAsrFinish(recogResult); + } + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_LONG_SPEECH)) { // 长语音 + listener.onAsrLongFinish(); // 长语音 + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_EXIT)) { + listener.onAsrExit(); + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_VOLUME)) { + // Logger.info(TAG, "asr volume event:" + params); + Volume vol = parseVolumeJson(params); + listener.onAsrVolume(vol.volumePercent, vol.volume); + } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_AUDIO)) { + if (data.length != length) { + Log.e(TAG, "internal error: asr.audio callback data length is not equal to length param"); + } + listener.onAsrAudio(data, offset, length); + } + } + + private Volume parseVolumeJson(String jsonStr) { + Volume vol = new Volume(); + vol.origalJson = jsonStr; + try { + JSONObject json = new JSONObject(jsonStr); + vol.volumePercent = json.getInt("volume-percent"); + vol.volume = json.getInt("volume"); + } catch (JSONException e) { + e.printStackTrace(); + } + return vol; + } + + private class Volume { + private int volumePercent = -1; + private int volume = -1; + private String origalJson; + } + +} diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/RecogResult.java b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/RecogResult.java new file mode 100755 index 00000000..c28e754b --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/RecogResult.java @@ -0,0 +1,134 @@ +package org.devio.flutter.plugin.asr; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Created by fujiayi on 2017/6/24. + */ +public class RecogResult { + private static final int ERROR_NONE = 0; + + private String origalJson; + private String[] resultsRecognition; + private String origalResult; + private String sn; // 日志id, 请求有问题请提问带上sn + private String desc; + private String resultType; + private int error = -1; + private int subError = -1; + + public static RecogResult parseJson(String jsonStr) { + RecogResult result = new RecogResult(); + result.setOrigalJson(jsonStr); + try { + JSONObject json = new JSONObject(jsonStr); + int error = json.optInt("error"); + int subError = json.optInt("sub_error"); + result.setError(error); + result.setDesc(json.optString("desc")); + result.setResultType(json.optString("result_type")); + result.setSubError(subError); + if (error == ERROR_NONE) { + result.setOrigalResult(json.getString("origin_result")); + JSONArray arr = json.optJSONArray("results_recognition"); + if (arr != null) { + int size = arr.length(); + String[] recogs = new String[size]; + for (int i = 0; i < size; i++) { + recogs[i] = arr.getString(i); + } + result.setResultsRecognition(recogs); + } + + + } + } catch (JSONException e) { + e.printStackTrace(); + } + + return result; + } + + public boolean hasError() { + return error != ERROR_NONE; + } + + public boolean isFinalResult() { + return "final_result".equals(resultType); + } + + + public boolean isPartialResult() { + return "partial_result".equals(resultType); + } + + public boolean isNluResult() { + return "nlu_result".equals(resultType); + } + + public String getOrigalJson() { + return origalJson; + } + + public void setOrigalJson(String origalJson) { + this.origalJson = origalJson; + } + + public String[] getResultsRecognition() { + return resultsRecognition; + } + + public void setResultsRecognition(String[] resultsRecognition) { + this.resultsRecognition = resultsRecognition; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public int getError() { + return error; + } + + public void setError(int error) { + this.error = error; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getOrigalResult() { + return origalResult; + } + + public void setOrigalResult(String origalResult) { + this.origalResult = origalResult; + } + + public String getResultType() { + return resultType; + } + + public void setResultType(String resultType) { + this.resultType = resultType; + } + + public int getSubError() { + return subError; + } + + public void setSubError(int subError) { + this.subError = subError; + } +} diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/ResultStateful.java b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/ResultStateful.java new file mode 100644 index 00000000..e703de8e --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/java/org/devio/flutter/plugin/asr/ResultStateful.java @@ -0,0 +1,55 @@ +package org.devio.flutter.plugin.asr; + +import android.util.Log; + +import androidx.annotation.Nullable; +import io.flutter.plugin.common.MethodChannel; + +public class ResultStateful implements MethodChannel.Result { + private final static String TAG = "ResultStateful"; + private MethodChannel.Result result; + private boolean called; + + public static ResultStateful of(MethodChannel.Result result) { + return new ResultStateful(result); + } + + private ResultStateful(MethodChannel.Result result) { + this.result = result; + } + + @Override + public void success(@Nullable Object o) { + if (called) { + printError(); + return; + } + called = true; + result.success(o); + } + + @Override + public void error(String s, @Nullable String s1, @Nullable Object o) { + if (called) { + printError(); + return; + } + called = true; + result.error(s, s1, o); + } + + @Override + public void notImplemented() { + if (called) { + printError(); + return; + } + called = true; + result.notImplemented(); + + } + + private void printError() { + Log.e(TAG, "error:result called"); + } +} diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/arm64-v8a/libBaiduSpeechSDK.so b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/arm64-v8a/libBaiduSpeechSDK.so new file mode 100755 index 00000000..5a0d4e79 Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/arm64-v8a/libBaiduSpeechSDK.so differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/arm64-v8a/libvad.dnn.so b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/arm64-v8a/libvad.dnn.so new file mode 100755 index 00000000..0550061c Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/arm64-v8a/libvad.dnn.so differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/armeabi-v7a/libBaiduSpeechSDK.so b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/armeabi-v7a/libBaiduSpeechSDK.so new file mode 100755 index 00000000..253f5a14 Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/armeabi-v7a/libBaiduSpeechSDK.so differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/armeabi-v7a/libvad.dnn.so b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/armeabi-v7a/libvad.dnn.so new file mode 100755 index 00000000..0550061c Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/armeabi-v7a/libvad.dnn.so differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86/libBaiduSpeechSDK.so b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86/libBaiduSpeechSDK.so new file mode 100755 index 00000000..483acaf1 Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86/libBaiduSpeechSDK.so differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86/libvad.dnn.so b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86/libvad.dnn.so new file mode 100755 index 00000000..0550061c Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86/libvad.dnn.so differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86_64/libBaiduSpeechSDK.so b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86_64/libBaiduSpeechSDK.so new file mode 100755 index 00000000..efae6915 Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86_64/libBaiduSpeechSDK.so differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86_64/libvad.dnn.so b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86_64/libvad.dnn.so new file mode 100755 index 00000000..0550061c Binary files /dev/null and b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/jniLibs/x86_64/libvad.dnn.so differ diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/main/res/values/strings.xml b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/res/values/strings.xml new file mode 100644 index 00000000..3306bd87 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + asr_plugin + diff --git a/FlutterHelper/flutter_trip/android/asr_plugin/src/test/java/org/devio/flutter/plugin/asr/ExampleUnitTest.java b/FlutterHelper/flutter_trip/android/asr_plugin/src/test/java/org/devio/flutter/plugin/asr/ExampleUnitTest.java new file mode 100644 index 00000000..7132aeda --- /dev/null +++ b/FlutterHelper/flutter_trip/android/asr_plugin/src/test/java/org/devio/flutter/plugin/asr/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package org.devio.flutter.plugin.asr; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/android/build.gradle b/FlutterHelper/flutter_trip/android/build.gradle new file mode 100644 index 00000000..541636cc --- /dev/null +++ b/FlutterHelper/flutter_trip/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.3.0' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/FlutterHelper/flutter_trip/android/flutter_trip_key_store b/FlutterHelper/flutter_trip/android/flutter_trip_key_store new file mode 100644 index 00000000..6d274e75 Binary files /dev/null and b/FlutterHelper/flutter_trip/android/flutter_trip_key_store differ diff --git a/FlutterHelper/flutter_trip/android/gradle.properties b/FlutterHelper/flutter_trip/android/gradle.properties new file mode 100644 index 00000000..5a67f180 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +target-platform=android-arm64 +android.enableJetifier=true +android.useAndroidX=true \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/android/gradle/wrapper/gradle-wrapper.properties b/FlutterHelper/flutter_trip/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..2819f022 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip diff --git a/FlutterHelper/flutter_trip/android/key.properties b/FlutterHelper/flutter_trip/android/key.properties new file mode 100644 index 00000000..59f8c86b --- /dev/null +++ b/FlutterHelper/flutter_trip/android/key.properties @@ -0,0 +1,4 @@ +storePassword=123456 +keyPassword=123456 +keyAlias=flutter_key +storeFile=../flutter_trip_key_store \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/android/settings.gradle b/FlutterHelper/flutter_trip/android/settings.gradle new file mode 100644 index 00000000..eaf46274 --- /dev/null +++ b/FlutterHelper/flutter_trip/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app', ':asr_plugin' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/FlutterHelper/flutter_trip/demo/README.md b/FlutterHelper/flutter_trip/demo/README.md new file mode 100644 index 00000000..1249b691 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/README.md @@ -0,0 +1,5 @@ + +- [flutter_base_demo](https://git.imooc.com/coding-321/flutter_trip/src/master/demo/flutter_base_demo) + - Flutter入门:基础知识十六讲 +- [flutter_hybrid](https://git.imooc.com/coding-321/flutter_trip/src/master/demo/flutter_hybrid) + - Flutter进阶提升:Flutter混合开发 \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/.gitignore b/FlutterHelper/flutter_trip/demo/flutter_base_demo/.gitignore new file mode 100644 index 00000000..07488ba6 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/.gitignore @@ -0,0 +1,70 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# Visual Studio Code related +.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +/build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/.metadata b/FlutterHelper/flutter_trip/demo/flutter_base_demo/.metadata new file mode 100644 index 00000000..a5147b73 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 3054a935791bf0bcc34ba0a111df794ddb7a3589 + channel: dev + +project_type: app diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/README.md b/FlutterHelper/flutter_trip/demo/flutter_base_demo/README.md new file mode 100644 index 00000000..8939a457 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/README.md @@ -0,0 +1,16 @@ +# flutter_base_demo + +A new Flutter application. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.io/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/build.gradle b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/build.gradle new file mode 100644 index 00000000..47f41108 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/build.gradle @@ -0,0 +1,62 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "org.devio.flutter.demo.flutter_base_demo" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + testImplementation 'junit:junit:4.12' + //@兼容AndroidX https://flutter.dev/docs/development/packages-and-plugins/androidx-compatibility + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/debug/AndroidManifest.xml b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..dc67bf9e --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/AndroidManifest.xml b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..77273271 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/java/org/devio/flutter/demo/flutter_base_demo/MainActivity.java b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/java/org/devio/flutter/demo/flutter_base_demo/MainActivity.java new file mode 100644 index 00000000..895207ba --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/java/org/devio/flutter/demo/flutter_base_demo/MainActivity.java @@ -0,0 +1,13 @@ +package org.devio.flutter.demo.flutter_base_demo; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/drawable/launch_background.xml b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..db77bb4b Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..17987b79 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..09d43914 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..d5f1c8d3 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..4d6372ee Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/values/styles.xml b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..00fa4417 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/profile/AndroidManifest.xml b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..dc67bf9e --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/build.gradle b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/build.gradle new file mode 100644 index 00000000..541636cc --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.3.0' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/gradle.properties b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/gradle.properties new file mode 100644 index 00000000..08f2b5f9 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableJetifier=true +android.useAndroidX=true diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/gradle/wrapper/gradle-wrapper.properties b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..2819f022 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/settings.gradle b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/settings.gradle new file mode 100644 index 00000000..5a2f14fb --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/fonts/RubikMonoOne-Regular.ttf b/FlutterHelper/flutter_trip/demo/flutter_base_demo/fonts/RubikMonoOne-Regular.ttf new file mode 100755 index 00000000..ee6af948 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/fonts/RubikMonoOne-Regular.ttf differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/images/avatar.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/images/avatar.png new file mode 100644 index 00000000..70841dc8 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/images/avatar.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/AppFrameworkInfo.plist b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..9367d483 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/Debug.xcconfig b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..e8efba11 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/Release.xcconfig b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..399e9340 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Podfile b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Podfile new file mode 100644 index 00000000..d077b08b --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Podfile @@ -0,0 +1,69 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + pods_ary = [] + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) { |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + pods_ary.push({:name => podname, :path => podpath}); + else + puts "Invalid plugin specification: #{line}" + end + } + return pods_ary +end + +target 'Runner' do + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + system('rm -rf .symlinks') + system('mkdir -p .symlinks/plugins') + + # Flutter Pods + generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') + if generated_xcode_build_settings.empty? + puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." + end + generated_xcode_build_settings.map { |p| + if p[:name] == 'FLUTTER_FRAMEWORK_DIR' + symlink = File.join('.symlinks', 'flutter') + File.symlink(File.dirname(p[:path]), symlink) + pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) + end + } + + # Plugin Pods + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.map { |p| + symlink = File.join('.symlinks', 'plugins', p[:name]) + File.symlink(p[:path], symlink) + pod p[:name], :path => File.join(symlink, 'ios') + } +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/project.pbxproj b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..42747c3f --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,571 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 5BB793135B8D0BD1061F5F25 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D26B9B567048DF27864AEA3 /* libPods-Runner.a */; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; + 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 4D26B9B567048DF27864AEA3 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 5BB793135B8D0BD1061F5F25 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 07D9D72DA01D01F38F23A8CA /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 07D9D72DA01D01F38F23A8CA /* Pods */, + 9C5294411D4F647F48506571 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 9C5294411D4F647F48506571 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4D26B9B567048DF27864AEA3 /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + C832C977FCDB856386BF9A50 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 73506C6A4A6DF54A6CA02CB5 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0910; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + }; + 73506C6A4A6DF54A6CA02CB5 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + C832C977FCDB856386BF9A50 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.devio.flutter.demo.flutterBaseDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.devio.flutter.demo.flutterBaseDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.devio.flutter.demo.flutterBaseDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..786d6aad --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcworkspace/contents.xcworkspacedata b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..949b6789 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + BuildSystemType + Original + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/AppDelegate.h b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/AppDelegate.h new file mode 100644 index 00000000..36e21bbf --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/AppDelegate.m b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/AppDelegate.m new file mode 100644 index 00000000..59a72e90 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/AppDelegate.m @@ -0,0 +1,13 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + // Override point for customization after application launch. + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..3d43d11e Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..28c6bf03 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..2ccbfd96 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..f091b6b0 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..4cde1211 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..d0ef06e7 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..dcdc2306 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..2ccbfd96 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..c8f9ed8f Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..a6d6b860 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..a6d6b860 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..75b2d164 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..c4df70d3 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..6a84f41e Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..d0e1f585 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Base.lproj/LaunchScreen.storyboard b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Base.lproj/Main.storyboard b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Info.plist b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Info.plist new file mode 100644 index 00000000..9370aa6d --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flutter_base_demo + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + NSCameraUsageDescription + 在这里配置相机使用说明 + NSMicrophoneUsageDescription + 在这里配置录音使用说明 + NSPhotoLibraryUsageDescription + 在这里配置相册的使用说明 + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/main.m b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/main.m new file mode 100644 index 00000000..dff6597e --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/ios/Runner/main.m @@ -0,0 +1,9 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/app_lifecycle.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/app_lifecycle.dart new file mode 100644 index 00000000..463c75ea --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/app_lifecycle.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +///如何获取Flutter应用维度生命周期 +///WidgetsBindingObserver:是一个Widgets绑定观察器,通过它我们可以监听应用的生命周期、语言等的变化 +class AppLifecycle extends StatefulWidget { + @override + _AppLifecycleState createState() => _AppLifecycleState(); +} + +class _AppLifecycleState extends State + with WidgetsBindingObserver { + @override + void initState() { + WidgetsBinding.instance.addObserver(this); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Flutter应用生命周期'), + leading: BackButton(), + ), + body: Container( + child: Text('Flutter应用生命周期'), + ), + ); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + print('state = $state'); + if (state == AppLifecycleState.paused) { + print('App进入后台'); + } else if (state == AppLifecycleState.resumed) { + print('App进去前台'); + } else if (state == AppLifecycleState.inactive) { + //不常用:应用程序处于非活动状态,并且未接收用户输入时调用,比如:来了个电话 + } else if (state == AppLifecycleState.suspending) { + //不常用:应用程序被挂起是调用,它不会在iOS上触发 + } + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/flutter_layout_page.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/flutter_layout_page.dart new file mode 100644 index 00000000..dd39e5ab --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/flutter_layout_page.dart @@ -0,0 +1,213 @@ +import 'package:flutter/material.dart'; + +///如何进行Flutter布局开发? +class FlutterLayoutPage extends StatefulWidget { + @override + _FlutterLayoutPageState createState() => _FlutterLayoutPageState(); +} + +class _FlutterLayoutPageState extends State { + int _currentIndex = 0; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: '如何进行Flutter布局开发?', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: Scaffold( + appBar: AppBar( + title: Text('如何进行Flutter布局开发?'), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon(Icons.arrow_back), + ), + ), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon( + Icons.home, + color: Colors.grey, + ), + activeIcon: Icon( + Icons.home, + color: Colors.blue, + ), + title: Text('首页')), + BottomNavigationBarItem( + icon: Icon( + Icons.list, + color: Colors.grey, + ), + activeIcon: Icon( + Icons.list, + color: Colors.blue, + ), + title: Text('列表')) + ]), + floatingActionButton: FloatingActionButton( + onPressed: null, + child: Text('点我'), + ), + body: _currentIndex == 0 + ? RefreshIndicator( + child: ListView( + children: [ + Container( + decoration: BoxDecoration(color: Colors.white), + alignment: Alignment.center, + child: Column( + children: [ + Row( + children: [ + ClipOval( + child: SizedBox( + width: 100, + height: 100, + child: Image.network( + 'http://www.devio.org/img/avatar.png'), + ), + ), + Padding( + padding: EdgeInsets.all(10), + child: ClipRRect( + //圆角 + borderRadius: + BorderRadius.all(Radius.circular(10)), + child: Opacity( + opacity: 0.6, //60%透明度 + child: Image.network( + 'http://www.devio.org/img/avatar.png', + width: 100, + height: 100, + ), + ), + ), + ) + ], + ), + TextField( + //输入文本的样式 + decoration: InputDecoration( + contentPadding: EdgeInsets.fromLTRB(5, 0, 0, 0), + hintText: '请输入', + hintStyle: TextStyle(fontSize: 15)), + ), + Container( + height: 100, + margin: EdgeInsets.all(10), + child: PhysicalModel( + color: Colors.transparent, + borderRadius: BorderRadius.circular(6), + clipBehavior: Clip.antiAlias, //抗锯齿 + child: PageView( + children: [ + _item('Page1', Colors.deepPurple), + _item('Page2', Colors.green), + _item('Page3', Colors.red) + ], + ), + ), + ), + Column( + children: [ + FractionallySizedBox( + widthFactor: 1, + child: Container( + decoration: + BoxDecoration(color: Colors.greenAccent), + child: Text('宽度撑满'), + ), + ) + ], + ), + ], + ), + ), + Stack( + children: [ + Image.network( + 'http://www.devio.org/img/avatar.png', + width: 100, + height: 100, + ), + Positioned( + left: 0, + bottom: 0, + child: Image.network( + 'http://www.devio.org/img/avatar.png', + width: 36, + height: 36, + )) + ], + ), + Wrap( + //创建一个wrap布局,从左向右进行排列,会自动换行 + spacing: 8, //水平间距 + runSpacing: 6, //垂直间距 + children: [ + _chip('Flutter'), + _chip('进阶'), + _chip('实战'), + _chip('携程'), + _chip('App'), + ], + ) + ], + ), + onRefresh: _handleRefresh) + : Column( + children: [ + Text('列表'), + Expanded( + child: Container( + decoration: BoxDecoration( + color: Colors.red, + ), + child: Text('拉伸填满高度'), + )) + ], + ), + ), + ); + } + + Future _handleRefresh() async { + await Future.delayed(Duration(milliseconds: 200)); + return null; + } + + _item(String title, Color color) { + return Container( + alignment: Alignment.center, + decoration: BoxDecoration(color: color), + child: Text( + title, + style: TextStyle(fontSize: 22, color: Colors.white), + ), + ); + } + + _chip(String label) { + return Chip( + label: Text(label), + avatar: CircleAvatar( + backgroundColor: Colors.blue.shade900, + child: Text( + label.substring(0, 1), + style: TextStyle(fontSize: 10), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/flutter_widget_lifecycle.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/flutter_widget_lifecycle.dart new file mode 100644 index 00000000..ec1feb77 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/flutter_widget_lifecycle.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; + +///Flutter Widget的生命周期重点讲解StatefulWidget的生命周期 +///因为无状态的widget StatelessWidget只有createElement、与build两个生命周期方法 +///StatefulWidget的生命周期方法按照时期不同可以分为三组: +///1.初始化时期 +///createState、initState +///2.更新期间 +///didChangeDependencies、build、didUpdateWidget +///3.销毁期 +///deactivate、dispose +///扩展阅读: +///http://www.devio.org/io/flutter_app/img/blog/flutter-widget-lifecycle.png +///https://flutterbyexample.com/stateful-widget-lifecycle/ +///提示:本章节的课件文档和说明,可以从课程仓库的文档链接进入到问答区查看哦 +class WidgetLifecycle extends StatefulWidget { + ///当我们构建一个新的StatefulWidget时,这个会立即调用 + ///并且这个方法必须被覆盖 + @override + _WidgetLifecycleState createState() => _WidgetLifecycleState(); +} + +class _WidgetLifecycleState extends State { + int _count = 0; + + ///这是创建widget时调用的除构造方法外的第一个方法: + ///类似于Android的:onCreate() 与iOS的 viewDidLoad() + ///在这个方法中通常会做一些初始化工作,比如channel的初始化,监听器的初始化等 + @override + void initState() { + print('----initState----'); + super.initState(); + } + + ///当依赖的State对象改变时会调用: + ///a.在第一次构建widget时,在initState()之后立即调用此方法; + ///b.如果的StatefulWidgets依赖于InheritedWidget,那么当当前State所依赖InheritedWidget中的变量改变时会再次调用它 + ///拓展:InheritedWidget可以高效的将数据在Widget树中向下传递、共享,可参考:https://book.flutterchina.club/chapter7/inherited_widget.html + @override + void didChangeDependencies() { + print('---didChangeDependencies----'); + super.didChangeDependencies(); + } + + ///这是一个必须实现的方法,在这里实现你要呈现的页面内容: + ///它会在在didChangeDependencies()之后立即调用; + ///另外当调用setState后也会再次调用该方法; + @override + Widget build(BuildContext context) { + print('---build-----'); + return Scaffold( + appBar: AppBar( + title: Text('Flutter页面生命周期'), + leading: BackButton(), + ), + body: Center( + child: Column( + children: [ + RaisedButton( + onPressed: () { + setState(() { + _count += 1; + }); + }, + child: Text( + '点我', + style: TextStyle(fontSize: 26), + ), + ), + Text(_count.toString()) + ], + ), + ), + ); + } + + ///这是一个不常用到的生命周期方法,当父组件需要重新绘制时才会调用; + ///该方法会携带一个oldWidget参数,可以将其与当前的widget进行对比以便执行一些额外的逻辑,如: + /// if (oldWidget.xxx != widget.xxx)... + @override + void didUpdateWidget(WidgetLifecycle oldWidget) { + print('----didUpdateWidget-----'); + super.didUpdateWidget(oldWidget); + } + + ///很少使用,在组件被移除时调用在dispose之前调用 + @override + void deactivate() { + print('-----deactivate------'); + super.deactivate(); + } + + ///常用,组件被销毁时调用: + ///通常在该方法中执行一些资源的释放工作比如,监听器的卸载,channel的销毁等 + @override + void dispose() { + print('-----dispose-----'); + super.dispose(); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/gesture_page.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/gesture_page.dart new file mode 100644 index 00000000..52a6e59c --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/gesture_page.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; + +///如何检测用户手势以及处理点击事件? +class GesturePage extends StatefulWidget { + @override + _GesturePageState createState() => _GesturePageState(); +} + +class _GesturePageState extends State { + String printString = ''; + double moveX = 0, moveY = 0; + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: Scaffold( + appBar: AppBar( + title: Text('如何检测用户手势以及处理点击事件?'), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon(Icons.arrow_back), + ), + ), + body: FractionallySizedBox( + widthFactor: 1, + child: Stack( + children: [ + Column( + children: [ + GestureDetector( + onTap: () => _printMsg('点击'), + onDoubleTap: () => _printMsg('双击'), + onLongPress: () => _printMsg('长按'), + onTapCancel: () => _printMsg('取消'), + onTapUp: (e) => _printMsg('松开'), + onTapDown: (e) => _printMsg('按下'), + child: Container( + padding: EdgeInsets.all(60), + decoration: BoxDecoration(color: Colors.blueAccent), + child: Text( + '点我', + style: TextStyle(fontSize: 36, color: Colors.white), + ), + ), + ), + Text(printString) + ], + ), + Positioned( + //跟着手指滑动的小球 + left: moveX, + top: moveY, + child: GestureDetector( + onPanUpdate: (e) => _doMove(e), + child: Container( + width: 72, + height: 72, + decoration: BoxDecoration( + color: Colors.amber, + borderRadius: BorderRadius.circular(36)), + ), + ), + ) + ], + ), + )), + ); + } + + _printMsg(String msg) { + setState(() { + printString += ' ,$msg'; + }); + } + + _doMove(DragUpdateDetails e) { + setState(() { + moveY += e.delta.dy; + moveX += e.delta.dx; + }); + print(e); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/launch_page.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/launch_page.dart new file mode 100644 index 00000000..2ec69083 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/launch_page.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +///如何打开第三方应用? +class LaunchPage extends StatefulWidget { + @override + _LaunchPageState createState() => _LaunchPageState(); +} + +class _LaunchPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('如何打开第三方应用?'), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon(Icons.arrow_back), + ), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton( + onPressed: () => _launchURL(), + child: Text('打开浏览器'), + ), + RaisedButton( + onPressed: () => _openMap(), + child: Text('打开地图'), + ) + ], + ), + ), + ); + } + + _launchURL() async { + const url = 'http://www.devio.org/'; + if (await canLaunch(url)) { + await launch(url); + } else { + throw 'Could not launch $url'; + } + } + + _openMap() async { + // Android + const url = 'geo:52.32,4.917'; //APP提供者提供的 schema + if (await canLaunch(url)) { + await launch(url); + } else { + //iOS + const url = 'http://maps.apple.com/?ll=52.32,4.917'; + if (await canLaunch(url)) { + await launch(url); + } else { + throw 'Could not launch $url'; + } + } + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/less_group_page.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/less_group_page.dart new file mode 100644 index 00000000..44941823 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/less_group_page.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; + +///StatelessWidget与基础组件 +class LessGroupPage extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + TextStyle textStyle = TextStyle(fontSize: 20); + return MaterialApp( + title: 'StatelessWidget与基础组件', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: Scaffold( + appBar: AppBar( + title: Text('StatelessWidget与基础组件'), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon(Icons.arrow_back), + ), + ), + body: Container( + decoration: BoxDecoration(color: Colors.white), + alignment: Alignment.center, + child: Column( + children: [ + Text( + 'I am Text', + style: textStyle, + ), + Icon( + Icons.android, + size: 50, + color: Colors.red, + ), + CloseButton(), + BackButton(), + Chip( + //材料设计中一个非常有趣的小部件,什么是Chip@https://material.io/design/components/chips.html + avatar: Icon(Icons.people), + label: Text('StatelessWidget与基组件'), + ), + Divider( + height: 10, //容器高度,不是线的高度 + indent: 10, //左侧间距 + color: Colors.orange, + ), + Card( + //带有圆角,阴影,边框等效果的卡片 + color: Colors.blue, + elevation: 5, + margin: EdgeInsets.all(10), + child: Container( + padding: EdgeInsets.all(10), + child: Text( + 'I am Card', + style: textStyle, + ), + ), + ), + AlertDialog( + title: Text('盘他'), + content: Text('你这个糟老头子坏得很'), + ) + ], + ), + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/main.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/main.dart new file mode 100644 index 00000000..cd93dc29 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/main.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_base_demo/app_lifecycle.dart'; +import 'package:flutter_base_demo/flutter_layout_page.dart'; +import 'package:flutter_base_demo/flutter_widget_lifecycle.dart'; +import 'package:flutter_base_demo/gesture_page.dart'; +import 'package:flutter_base_demo/launch_page.dart'; +import 'package:flutter_base_demo/less_group_page.dart'; +import 'package:flutter_base_demo/photo_app_page.dart'; +import 'package:flutter_base_demo/plugin_use.dart'; +import 'package:flutter_base_demo/res_page.dart'; +import 'package:flutter_base_demo/statefull_group_page.dart'; + +void main() => runApp(DynamicTheme()); + +class DynamicTheme extends StatefulWidget { + @override + _DynamicThemeState createState() => _DynamicThemeState(); +} + +class _DynamicThemeState extends State { + Brightness _brightness = Brightness.light; + ///字体下载地址:https://fonts.google.com/specimen/Rubik+Mono+One?selection.family=Rubik+Mono+One + ///更多参考:https://flutter.dev/docs/cookbook/design/fonts + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( +// fontFamily: 'RubikMonoOne',//将该字体应用到全局 + brightness:_brightness, + primarySwatch: Colors.blue, + ), + home: Scaffold( + appBar: AppBar( + title: Text('如何创建和使用Flutter的路由与导航?'), + ), + body: Column( + children: [ + RaisedButton( + onPressed: () { + setState(() { + if (_brightness == Brightness.dark) { + _brightness = Brightness.light; + } else { + _brightness = Brightness.dark; + } + }); + }, + child: Text('切换主题abc',style: TextStyle(fontFamily: 'RubikMonoOne'),), + ), + RouteNavigator() + ], + ), + ), + routes: { + 'plugin': (BuildContext context) => PluginUse(), + 'less': (BuildContext context) => LessGroupPage(), + 'ful': (BuildContext context) => StatefulGroup(), + 'layout': (BuildContext context) => FlutterLayoutPage(), + 'gesture': (BuildContext context) => GesturePage(), + 'res': (BuildContext context) => ResPage(), + 'launch': (BuildContext context) => LaunchPage(), + 'widgetLifecycle': (BuildContext context) => WidgetLifecycle(), + 'appLifecycle': (BuildContext context) => AppLifecycle(), + 'photo': (BuildContext context) => PhotoApp(), + }); + } +} + +class RouteNavigator extends StatefulWidget { + @override + _RouteNavigatorState createState() => _RouteNavigatorState(); +} + +class _RouteNavigatorState extends State { + bool byName = false; + + @override + Widget build(BuildContext context) { + return Container( + child: Column( + children: [ + SwitchListTile( + title: Text('${byName ? '' : '不'}通过路由名跳转'), + value: byName, + onChanged: (value) { + setState(() { + byName = value; + }); + }), + _item('如何使用Flutter包和插件?', PluginUse(), 'plugin'), + _item('StatelessWidget与基础组件', LessGroupPage(), 'less'), + _item('StatefulWidget与基组件', StatefulGroup(), 'ful'), + _item('如何进行Flutter布局开发', FlutterLayoutPage(), 'layout'), + _item('如何检测用户手势以及处理点击事件?', GesturePage(), 'gesture'), + _item('如何导入和使用Flutter的资源文件?', ResPage(), 'res'), + _item('如何打开第三方应用?', LaunchPage(), 'launch'), + _item('Flutter页面生命周期', WidgetLifecycle(), 'widgetLifecycle'), + _item('Flutter应用生命周期', AppLifecycle(), 'appLifecycle'), + _item('【实战尝鲜】拍照APP开发', PhotoApp(), 'photo'), + ], + ), + ); + } + + _item(String title, page, String routeName) { + return Container( + child: RaisedButton( + onPressed: () { + if (byName) { + Navigator.pushNamed(context, routeName); + } else { + Navigator.push( + context, MaterialPageRoute(builder: (context) => page)); + } + }, + child: Text(title), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/photo_app_page.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/photo_app_page.dart new file mode 100644 index 00000000..51129cc9 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/photo_app_page.dart @@ -0,0 +1,112 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; + +///【实战尝鲜】拍照APP开发 +class PhotoApp extends StatefulWidget { + @override + _PhotoAppState createState() => _PhotoAppState(); +} + +class _PhotoAppState extends State { + List _images = []; + + Future getImage(bool isTakePhoto) async { + Navigator.pop(context); + var image = await ImagePicker.pickImage( + source: isTakePhoto ? ImageSource.camera : ImageSource.gallery); + if (image != null) { + setState(() { + _images.add(image); + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('【实战尝鲜】拍照APP开发'), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon(Icons.arrow_back), + ), + ), + body: Center( + child: Wrap( + spacing: 5, + runSpacing: 5, + children: _genImages(), + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _pickImage, + tooltip: '选择图片', + child: Icon(Icons.add_a_photo), + ), + ); + } + + _pickImage() { + showModalBottomSheet( + context: context, + builder: (context) => Container( + height: 160, + child: Column( + children: [ + _item('拍照', true), + _item('从相册选择', false), + ], + ), + )); + } + + _item(String title, bool isTakePhoto) { + return GestureDetector( + child: ListTile( + leading: Icon(isTakePhoto ? Icons.camera_alt : Icons.photo_library), + title: Text(title), + onTap: () => getImage(isTakePhoto), + ), + ); + } + + _genImages() { + return _images.map((file) { + return Stack( + children: [ + ClipRRect( + //圆角效果 + borderRadius: BorderRadius.circular(5), + child: Image.file(file, width: 120, height: 90, fit: BoxFit.fill), + ), + Positioned( + right: 5, + top: 5, + child: GestureDetector( + onTap: () { + setState(() { + _images.remove(file); + }); + }, + child: ClipOval( + //圆角删除按钮 + child: Container( + padding: EdgeInsets.all(3), + decoration: BoxDecoration(color: Colors.black54), + child: Icon( + Icons.close, + size: 18, + color: Colors.white, + ), + ), + ), + )) + ], + ); + }).toList(); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/plugin_use.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/plugin_use.dart new file mode 100644 index 00000000..29d0972b --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/plugin_use.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_color_plugin/flutter_color_plugin.dart'; + +///如何使用Flutter包和插件? +class PluginUse extends StatefulWidget { + @override + _PluginUseState createState() => _PluginUseState(); +} + +class _PluginUseState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('如何使用Flutter包和插件?'), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon(Icons.arrow_back), + ), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'You have pushed the button this many times:', + style: TextStyle(color: ColorUtil.color('#a9ee00')), + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/res_page.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/res_page.dart new file mode 100644 index 00000000..36531391 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/res_page.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +///如何导入和使用Flutter的资源文件? +class ResPage extends StatefulWidget { + @override + _ResPageState createState() => _ResPageState(); +} + +class _ResPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('如何导入和使用Flutter的资源文件?'), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon(Icons.arrow_back), + ), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image( + width: 100, + height: 100, + image: AssetImage('images/avatar.png'), + ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/statefull_group_page.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/statefull_group_page.dart new file mode 100644 index 00000000..3c43a28c --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/lib/statefull_group_page.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; + +///StatefulWidget与基础组件 +class StatefulGroup extends StatefulWidget { + @override + _StatefulGroupState createState() => _StatefulGroupState(); +} + +class _StatefulGroupState extends State { + int _currentIndex = 0; + + @override + Widget build(BuildContext context) { + TextStyle textStyle = TextStyle(fontSize: 20); + return MaterialApp( + title: 'StatefulWidget与基础组件', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: Scaffold( + appBar: AppBar( + title: Text('StatefulWidget与基础组件'), + leading: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon(Icons.arrow_back), + ), + ), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, + onTap: (index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + icon: Icon( + Icons.home, + color: Colors.grey, + ), + activeIcon: Icon( + Icons.home, + color: Colors.blue, + ), + title: Text('首页')), + BottomNavigationBarItem( + icon: Icon( + Icons.list, + color: Colors.grey, + ), + activeIcon: Icon( + Icons.list, + color: Colors.blue, + ), + title: Text('列表')) + ]), + floatingActionButton: FloatingActionButton( + onPressed: null, + child: Text('点我'), + ), + body: _currentIndex == 0 + ? RefreshIndicator( + child: ListView( + children: [ + Container( + decoration: BoxDecoration(color: Colors.white), + alignment: Alignment.center, + child: Column( + children: [ + Image.network( + 'http://www.devio.org/img/avatar.png', + width: 100, + height: 100, + ), + TextField( + //输入文本的样式 + decoration: InputDecoration( + contentPadding: EdgeInsets.fromLTRB(5, 0, 0, 0), + hintText: '请输入', + hintStyle: TextStyle(fontSize: 15)), + ), + Container( + height: 100, + margin: EdgeInsets.only(top: 10), + decoration: + BoxDecoration(color: Colors.lightBlueAccent), + child: PageView( + children: [ + _item('Page1', Colors.deepPurple), + _item('Page2', Colors.green), + _item('Page3', Colors.red) + ], + ), + ) + ], + ), + ), + ], + ), + onRefresh: _handleRefresh) + : Text('列表'), + ), + ); + } + + Future _handleRefresh() async { + await Future.delayed(Duration(milliseconds: 200)); + return null; + } + + _item(String title, Color color) { + return Container( + alignment: Alignment.center, + decoration: BoxDecoration(color: color), + child: Text( + title, + style: TextStyle(fontSize: 22, color: Colors.white), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/pubspec.yaml b/FlutterHelper/flutter_trip/demo/flutter_base_demo/pubspec.yaml new file mode 100644 index 00000000..1e12c879 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/pubspec.yaml @@ -0,0 +1,78 @@ +name: flutter_base_demo +description: A new Flutter application. + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.1.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^0.1.2 + flutter_color_plugin: ^0.0.2 + url_launcher: ^5.0.2 + image_picker: ^0.5.2 +dev_dependencies: + flutter_test: + sdk: flutter + + +# For information on the generic Dart part of this file, see the +# following page: https://www.dartlang.org/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - images/avatar.png + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.io/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.io/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.io/custom-fonts/#from-packages + fonts: + - family: RubikMonoOne + fonts: + - asset: fonts/RubikMonoOne-Regular.ttf \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/demo/flutter_base_demo/test/widget_test.dart b/FlutterHelper/flutter_trip/demo/flutter_base_demo/test/widget_test.dart new file mode 100644 index 00000000..1115308f --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_base_demo/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_base_demo/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/.gitignore b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/.gitignore new file mode 100644 index 00000000..2b75303a --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/.gitignore @@ -0,0 +1,13 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/bitmap/bigimage/.gitignore b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/.gitignore similarity index 100% rename from bitmap/bigimage/.gitignore rename to FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/.gitignore diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/android_keystore.jks b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/android_keystore.jks new file mode 100644 index 00000000..a33a65d7 Binary files /dev/null and b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/android_keystore.jks differ diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/build.gradle b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/build.gradle new file mode 100644 index 00000000..e7aa4d33 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/build.gradle @@ -0,0 +1,42 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "org.devio.flutter.hybrid" + minSdkVersion 16 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + signingConfigs { + release { + storeFile file(MYAPP_RELEASE_STORE_FILE) + storePassword MYAPP_RELEASE_STORE_PASSWORD + keyAlias MYAPP_RELEASE_KEY_ALIAS + keyPassword MYAPP_RELEASE_KEY_PASSWORD + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + implementation project(':flutter') +} diff --git a/base/proguard-rules.pro b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/proguard-rules.pro similarity index 100% rename from base/proguard-rules.pro rename to FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/proguard-rules.pro diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/androidTest/java/org/devio/flutter/hybrid/ExampleInstrumentedTest.java b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/androidTest/java/org/devio/flutter/hybrid/ExampleInstrumentedTest.java new file mode 100644 index 00000000..64ec8259 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/androidTest/java/org/devio/flutter/hybrid/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package org.devio.flutter.hybrid; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("org.devio.flutter.hybrid", appContext.getPackageName()); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/AndroidManifest.xml b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..34419fc7 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/BasicMessageChannelPlugin.java b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/BasicMessageChannelPlugin.java new file mode 100644 index 00000000..03246508 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/BasicMessageChannelPlugin.java @@ -0,0 +1,57 @@ +package org.devio.flutter.hybrid; + +import android.app.Activity; +import android.widget.Toast; + +import io.flutter.plugin.common.BasicMessageChannel; +import io.flutter.plugin.common.StringCodec; +import io.flutter.view.FlutterView; + +/** + * BasicMessageChannel + * 用于传递字符串和半结构化的信息,持续通信,如:Native将遍历到的文件信息陆续传递到Dart + * ,在比如:Flutter将从服务端陆陆续获取到信息交个Native加工,Native处理完返回等 + * Author: CrazyCodeBoy + * 技术博文:http://www.devio.org + * GitHub:https://github.com/crazycodeboy + * Email:crazycodeboy@gmail.com + */ +public class BasicMessageChannelPlugin implements BasicMessageChannel.MessageHandler, BasicMessageChannel.Reply { + private final Activity activity; + private final BasicMessageChannel messageChannel; + + static BasicMessageChannelPlugin registerWith(FlutterView flutterView) { + return new BasicMessageChannelPlugin(flutterView); + } + + private BasicMessageChannelPlugin(FlutterView flutterView) { + this.activity = (Activity) flutterView.getContext(); + this.messageChannel = new BasicMessageChannel<>(flutterView, "BasicMessageChannelPlugin", StringCodec.INSTANCE); + //设置消息处理器,处理来自Dart的消息 + messageChannel.setMessageHandler(this); + } + + @Override + public void onMessage(String s, BasicMessageChannel.Reply reply) {//处理Dart发来的消息 + reply.reply("BasicMessageChannel收到:" + s);//可以通过reply进行回复 + if (activity instanceof IShowMessage) { + ((IShowMessage) activity).onShowMessage(s); + } + Toast.makeText(activity, s, Toast.LENGTH_SHORT).show(); + } + + /** + * 向Dart发送消息,并接受Dart的反馈 + * + * @param message 要给Dart发送的消息内容 + * @param callback 来自Dart的反馈 + */ + void send(String message, BasicMessageChannel.Reply callback) { + messageChannel.send(message, callback); + } + + @Override + public void reply(String s) { + + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/EventChannelPlugin.java b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/EventChannelPlugin.java new file mode 100644 index 00000000..9cfda707 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/EventChannelPlugin.java @@ -0,0 +1,39 @@ +package org.devio.flutter.hybrid; + +import io.flutter.plugin.common.EventChannel; +import io.flutter.view.FlutterView; + +/** + * EventChannelPlugin + * 用于数据流(event streams)的通信,持续通信,通过长用于Native向Dart的通信, + * 如:手机电量变化,网络连接变化,陀螺仪,传感器等; + * Author: CrazyCodeBoy + * 技术博文:http://www.devio.org + * GitHub:https://github.com/crazycodeboy + * Email:crazycodeboy@gmail.com + */ +public class EventChannelPlugin implements EventChannel.StreamHandler { + private EventChannel.EventSink eventSink; + + static EventChannelPlugin registerWith(FlutterView flutterView) { + EventChannelPlugin plugin = new EventChannelPlugin(); + new EventChannel(flutterView, "EventChannelPlugin").setStreamHandler(plugin); + return plugin; + } + + void send(Object params) { + if (eventSink != null) { + eventSink.success(params); + } + } + + @Override + public void onListen(Object args, EventChannel.EventSink eventSink) { + this.eventSink = eventSink; + } + + @Override + public void onCancel(Object o) { + eventSink = null; + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/FlutterAppActivity.java b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/FlutterAppActivity.java new file mode 100644 index 00000000..1ed81b17 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/FlutterAppActivity.java @@ -0,0 +1,53 @@ +package org.devio.flutter.hybrid; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import io.flutter.facade.Flutter; +import io.flutter.view.FlutterView; + +public class FlutterAppActivity extends AppCompatActivity implements IShowMessage { + public final static String INIT_PARAMS = "initParams"; + private UIPresenter uiPresenter; + private BasicMessageChannelPlugin basicMessageChannelPlugin; + private EventChannelPlugin eventChannelPlugin; + + public static void start(Context context, String initParams) { + Intent intent = new Intent(context, FlutterAppActivity.class); + intent.putExtra(INIT_PARAMS, initParams); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + String initParams = getIntent().getStringExtra(INIT_PARAMS); + FlutterView flutterView = Flutter.createView(this, getLifecycle(), initParams); + FrameLayout.LayoutParams layout = + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + setContentView(flutterView, layout); + eventChannelPlugin = EventChannelPlugin.registerWith(flutterView); + //注册Flutter plugin + MethodChannelPlugin.registerWith(flutterView); + basicMessageChannelPlugin = BasicMessageChannelPlugin.registerWith(flutterView); + uiPresenter = new UIPresenter(this, "通信与混合开发", this); + } + + @Override + public void onShowMessage(String message) { + uiPresenter.showDartMessage(message); + } + + @Override + public void sendMessage(String message, boolean useEventChannel) { + if (useEventChannel) { + eventChannelPlugin.send(message); + } else { + basicMessageChannelPlugin.send(message, this::onShowMessage); + } + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/IShowMessage.java b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/IShowMessage.java new file mode 100644 index 00000000..4bae0d50 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/IShowMessage.java @@ -0,0 +1,14 @@ +package org.devio.flutter.hybrid; + + +/** + * Flutter Native通信 | 混合开发 + * Author: CrazyCodeBoy + * 技术博文:http://www.devio.org + * GitHub:https://github.com/crazycodeboy + * Email:crazycodeboy@gmail.com + */ +public interface IShowMessage { + void onShowMessage(String message); + void sendMessage(String message,boolean useEventChannel); +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/MainActivity.java b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/MainActivity.java new file mode 100644 index 00000000..fd61a044 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/MainActivity.java @@ -0,0 +1,23 @@ +package org.devio.flutter.hybrid; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.EditText; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + EditText paramInput = findViewById(R.id.paramInput); + findViewById(R.id.jump).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + String inputParams = paramInput.getText().toString().trim(); + FlutterAppActivity.start(MainActivity.this, inputParams); + } + }); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/MethodChannelPlugin.java b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/MethodChannelPlugin.java new file mode 100644 index 00000000..c273e259 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/MethodChannelPlugin.java @@ -0,0 +1,55 @@ +package org.devio.flutter.hybrid; + +import android.app.Activity; +import android.widget.Toast; + +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.MethodChannel.MethodCallHandler; +import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.view.FlutterView; + +/** + * MethodChannelPlugin + * 用于传递方法调用(method invocation),一次性通信,通常用于Dart调用Native的方法:如拍照; + */ +public class MethodChannelPlugin implements MethodCallHandler { + private final Activity activity; + + /** + * Plugin registration. + */ + public static void registerWith(FlutterView flutterView) { + MethodChannel channel = new MethodChannel(flutterView, "MethodChannelPlugin"); + MethodChannelPlugin instance = new MethodChannelPlugin((Activity) flutterView.getContext()); + channel.setMethodCallHandler(instance); + } + + private MethodChannelPlugin(Activity activity) { + this.activity = activity; + } + + @Override + public void onMethodCall(MethodCall call, Result result) { + switch (call.method) {//处理来自Dart的方法调用 + case "send": + showMessage(call.arguments()); + result.success("MethodChannelPlugin收到:" + call.arguments);//返回结果给Dart + break; + default: + result.notImplemented(); + } + } + + /** + * 展示来自Dart的数据 + * + * @param arguments + */ + private void showMessage(String arguments) { + if (activity instanceof IShowMessage) { + ((IShowMessage) activity).onShowMessage(arguments); + } + Toast.makeText(activity, arguments, Toast.LENGTH_SHORT).show(); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/UIPresenter.java b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/UIPresenter.java new file mode 100644 index 00000000..027f2c89 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/java/org/devio/flutter/hybrid/UIPresenter.java @@ -0,0 +1,93 @@ +package org.devio.flutter.hybrid; + +import android.app.Activity; +import android.content.Context; +import android.support.annotation.NonNull; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.RadioGroup; +import android.widget.TextView; + +/** + * Flutter Native通信 | 混合开发 + * Author: CrazyCodeBoy + * 技术博文:http://www.devio.org + * GitHub:https://github.com/crazycodeboy + * Email:crazycodeboy@gmail.com + */ +public class UIPresenter implements View.OnClickListener { + private final IShowMessage iShowMessage; + Activity activity; + TextView textShow; + EditText input; + String title; + boolean useEventChannel; + public UIPresenter(@NonNull Activity activity, String title, IShowMessage iShowMessage) { + this.activity = activity; + this.title = title; + this.iShowMessage = iShowMessage; + initUI(); + } + + private void initUI() { + ViewGroup contentView = activity.findViewById(android.R.id.content); + View view = LayoutInflater.from(activity).inflate(R.layout.item_container, null); + ViewGroup.LayoutParams layoutParams = + new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + contentView.addView(view, layoutParams); + textShow = view.findViewById(R.id.textShow); + input = view.findViewById(R.id.input); + TextView titleView = view.findViewById(R.id.title); + titleView.setText(title); + view.findViewById(R.id.btnSend).setOnClickListener(this); + RadioGroup radioGroup = view.findViewById(R.id.radioGroup); + radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + if (checkedId == R.id.mode_basic_message_channel) { + useEventChannel = false; + } else if (checkedId == R.id.mode_event_channel) { + useEventChannel = true; + } + } + }); + input.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + iShowMessage.sendMessage(charSequence.toString(),useEventChannel); + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + } + + public void showDartMessage(String message) { + textShow.setText("收到Dart消息:" + message); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.btnSend) { + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + //隐藏软键盘 + imm.hideSoftInputFromWindow(input.getWindowToken(), 0); + + String data = input.getText().toString(); + // sendEvent(data); + } + } +} diff --git a/bitmap/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from bitmap/app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/bitmap/app/src/main/res/drawable/ic_launcher_background.xml b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from bitmap/app/src/main/res/drawable/ic_launcher_background.xml rename to FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/res/drawable/ic_launcher_background.xml diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/res/layout/activity_main.xml b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..17ad7ae3 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridAndroid/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/FirstViewController.h b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/FirstViewController.h new file mode 100644 index 00000000..f809ae89 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/FirstViewController.h @@ -0,0 +1,18 @@ +// +// FirstViewController.h +// FlutterHybridiOS +// +// Created by jph on 2019/2/27. +// Copyright © 2019 devio. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FirstViewController : UIViewController +@property (weak, nonatomic) IBOutlet UITextField *inputParams; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/FirstViewController.m b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/FirstViewController.m new file mode 100644 index 00000000..30af1f3b --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/FirstViewController.m @@ -0,0 +1,34 @@ +// +// FirstViewController.m +// FlutterHybridiOS +// +// Created by jph on 2019/2/27. +// Copyright © 2019 devio. All rights reserved. +// + +#import "FirstViewController.h" +#import "MainViewController.h" +@interface FirstViewController () + +@end + +@implementation FirstViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + + +#pragma mark - Navigation + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + if ([segue.destinationViewController isKindOfClass:[MainViewController class]]) { + ((MainViewController*)segue.destinationViewController + ).inputParams=self.inputParams.text; + } +} + +- (IBAction)onBack:(id)sender { +} +@end diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/Info.plist b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/Info.plist new file mode 100644 index 00000000..16be3b68 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/MainViewController.h b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/MainViewController.h new file mode 100644 index 00000000..418f70b1 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/MainViewController.h @@ -0,0 +1,13 @@ +// +// MianViewController.h +// FlutterHybridiOS +// +// Created by jph on 2019/2/27. +// Copyright © 2019 devio. All rights reserved. +// + +#import +#import +@interface MainViewController : UIViewController +@property(strong)NSString *inputParams; +@end diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/MainViewController.m b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/MainViewController.m new file mode 100644 index 00000000..b1dfac0c --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/MainViewController.m @@ -0,0 +1,98 @@ +// +// ViewController+MianViewController.m +// FlutterHybridiOS +// +// Created by jph on 2019/2/27. +// Copyright © 2019 devio. All rights reserved. +// +#import +#import "MainViewController.h" +@interface MainViewController () +@property (nonatomic) FlutterViewController* flutterViewController; +@property (nonatomic) FlutterBasicMessageChannel* messageChannel; +@property (nonatomic) FlutterEventChannel* eventChannel; +@property (nonatomic) FlutterMethodChannel* methodChannel; +@property (nonatomic) FlutterEventSink eventSink; +@end +@implementation MainViewController +- (void)viewDidLoad{ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sendMessage:) name:@"sendMessage" object:nil]; + [super viewDidLoad]; +} +#pragma mark - naviagor +- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender { + + if ([segue.destinationViewController isKindOfClass:[FlutterViewController class]]) { + self.flutterViewController = segue.destinationViewController; + [self.flutterViewController setInitialRoute:self.inputParams]; + [self initChannel]; + } +} +#pragma mark - sendMessage +- (void)sendMessage:(NSNotification*)notification{ + NSString* mesage = [notification.object valueForKey:@"message"]; + if ([@"true" isEqual:[notification.object valueForKey:@"useEventChannel"]]) { + //用EventChannel传递数据 + if (self.eventSink != nil) { + self.eventSink(mesage); + } + } else { + //用MessageChannel传递数据 + [self.messageChannel sendMessage: mesage reply:^(id _Nullable reply) { + if (reply != nil) { + [self sendShow:reply]; + } + }]; + } +} +#pragma mark - init Channel +- (void)initChannel{ + [self initMessageChannel]; + [self initEventChannel]; + [self initMethodChannel]; +} +- (void)initMessageChannel{ + self.messageChannel = [FlutterBasicMessageChannel messageChannelWithName:@"BasicMessageChannelPlugin" binaryMessenger:self.flutterViewController codec:[FlutterStringCodec sharedInstance]]; + MainViewController* __weak weakSelf = self; + //设置消息处理器,处理来自Dart的消息 + [self.messageChannel setMessageHandler:^(NSString* message, FlutterReply reply) { + reply([NSString stringWithFormat:@"BasicMessageChannel收到:%@",message]); + [weakSelf sendShow:message]; + }]; +} +- (void)initEventChannel{ + self.eventChannel = [FlutterEventChannel eventChannelWithName:@"EventChannelPlugin" binaryMessenger:self.flutterViewController]; + + //设置消息处理器,处理来自Dart的消息 + [self.eventChannel setStreamHandler:self]; +} +- (void)initMethodChannel{ + self.methodChannel = [FlutterMethodChannel methodChannelWithName:@"MethodChannelPlugin" binaryMessenger:self.flutterViewController]; + MainViewController* __weak weakSelf = self; + [self.methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) { + if ([@"send" isEqualToString:call.method]) { + result([NSString stringWithFormat:@"MethodChannelPlugin收到:%@",call.arguments]);//返回结果给Dart); + [weakSelf sendShow:call.arguments]; + } + }]; +} +- (void)sendShow:(NSString*) message{ + [[NSNotificationCenter defaultCenter] postNotificationName:@"showMessage" object:message]; +} +#pragma mark - +//这个onListen是Flutter端开始监听这个channel时的回调,第二个参数 EventSink是用来传数据的载体 +- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)eventSink { + // arguments flutter给native的参数 + // 回调给flutter, 建议使用实例指向,因为该block可以使用多次 + self.eventSink = eventSink; + return nil; +} + +/// flutter不再接收 +- (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments { + // arguments flutter给native的参数 + self.eventSink = nil; + return nil; +} + +@end diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/ViewController.h b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/ViewController.h new file mode 100644 index 00000000..e12400c8 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/ViewController.h @@ -0,0 +1,20 @@ +// +// ViewController.h +// FlutterHybridiOS +// +// Created by jph on 2019/2/25. +// Copyright © 2019 devio. All rights reserved. +// + +#import + +@interface ViewController : UIViewController +- (IBAction)onSwitch:(id)sender; +@property (weak, nonatomic) IBOutlet UILabel *switchLable; +@property (weak, nonatomic) IBOutlet UILabel *showLabel; +- (IBAction)onBack:(id)sender; +- (IBAction)editChange:(id)sender; + + +@end + diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/ViewController.m b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/ViewController.m new file mode 100644 index 00000000..c5e58c48 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/ViewController.m @@ -0,0 +1,51 @@ +// +// ViewController.m +// FlutterHybridiOS +// +// Created by jph on 2019/2/25. +// Copyright © 2019 devio. All rights reserved. +// + +#import +#import "AppDelegate.h" +#import "ViewController.h" +@interface ViewController() +@property(nonatomic,assign) BOOL useEventChannel; +@end + +@implementation ViewController +- (void)viewDidLoad { + [super viewDidLoad]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showMessage:) name:@"showMessage" object:nil]; +} +- (void)showMessage:(NSNotification*)notification{ + id params = notification.object; + self.showLabel.text = [NSString stringWithFormat:@"来自Dart:%@",params]; +} +- (IBAction)onSwitch:(id)sender { + UISwitch *uiswitch = ((UISwitch*)sender); + if (uiswitch.isOn) { + self.useEventChannel = true; + } else { + self.useEventChannel = false; + } +} + +- (IBAction)onBack:(id)sender { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (IBAction)editChange:(id)sender { + NSString * text=((UITextField*)sender).text; + [[NSNotificationCenter defaultCenter] postNotificationName:@"sendMessage" object:@{@"message": text,@"useEventChannel":self.useEventChannel? @"true":@"false"}]; +} +- (void)handleButtonAction { + //以一个完整页面打开Flutter模块 + FlutterViewController *flutterViewController = [FlutterViewController new]; + + [flutterViewController setInitialRoute:@"{name:'devio',dataList:['aa','bb',''cc]}"]; + + [self presentViewController:flutterViewController animated:true completion:nil]; + self.view=flutterViewController.view; +} +@end diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/main.m b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/main.m new file mode 100644 index 00000000..bc2ad470 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOS/main.m @@ -0,0 +1,16 @@ +// +// main.m +// FlutterHybridiOS +// +// Created by jph on 2019/2/25. +// Copyright © 2019 devio. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSTests/FlutterHybridiOSTests.m b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSTests/FlutterHybridiOSTests.m new file mode 100644 index 00000000..b1ee4d40 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSTests/FlutterHybridiOSTests.m @@ -0,0 +1,37 @@ +// +// FlutterHybridiOSTests.m +// FlutterHybridiOSTests +// +// Created by jph on 2019/2/25. +// Copyright © 2019 devio. All rights reserved. +// + +#import + +@interface FlutterHybridiOSTests : XCTestCase + +@end + +@implementation FlutterHybridiOSTests + +- (void)setUp { + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. +} + +- (void)testExample { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSTests/Info.plist b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSTests/Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSUITests/FlutterHybridiOSUITests.m b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSUITests/FlutterHybridiOSUITests.m new file mode 100644 index 00000000..d4862931 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSUITests/FlutterHybridiOSUITests.m @@ -0,0 +1,38 @@ +// +// FlutterHybridiOSUITests.m +// FlutterHybridiOSUITests +// +// Created by jph on 2019/2/25. +// Copyright © 2019 devio. All rights reserved. +// + +#import + +@interface FlutterHybridiOSUITests : XCTestCase + +@end + +@implementation FlutterHybridiOSUITests + +- (void)setUp { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + self.continueAfterFailure = NO; + + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + [[[XCUIApplication alloc] init] launch]; + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. +} + +- (void)testExample { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +@end diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSUITests/Info.plist b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSUITests/Info.plist new file mode 100644 index 00000000..6c40a6cd --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/FlutterHybridiOSUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/Podfile b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/Podfile new file mode 100644 index 00000000..a69e3bcc --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/FlutterHybridiOS/Podfile @@ -0,0 +1,22 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '9.0' +flutter_application_path = '../flutter_module/' +load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') +target 'FlutterHybridiOS' do + # Uncomment the next line if you're using Swift or would like to use dynamic frameworks + # use_frameworks! + + # Pods for FlutterHybridiOS + install_all_flutter_pods(flutter_application_path) + + target 'FlutterHybridiOSTests' do + inherit! :search_paths + # Pods for testing + end + + target 'FlutterHybridiOSUITests' do + inherit! :search_paths + # Pods for testing + end + +end diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/README.md b/FlutterHelper/flutter_trip/demo/flutter_hybrid/README.md new file mode 100644 index 00000000..b75f9821 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/README.md @@ -0,0 +1,19 @@ + + +这是慕课网官方实战课【[Flutter从入门到进阶-实战携程网App](https://coding.imooc.com/class/321.html)】的项目实例源码。 + + +## 如何运行? + +1. 安装和配置Flutter开发环境(如已经配置过可跳过),可参考课程[《Flutter入门:开发工具准备与开发环境搭建》](https://coding.imooc.com/class/321.html)一章的讲解。 +2. 首先在`flutter_hybrid⁩ ▸ ⁨flutter_module⁩`目录下运行`flutter packages get`; +3. 运行在iOS上的方式: + - 在`⁨flutter_hybrid⁩ ▸ ⁨FlutterHybridiOS⁩`目录下运行`pod install`; + - 用Xcode打开`FlutterHybridiOS.xcworkspace`然后运行项目; +4. 运行在Android上的方式: + - 用Android Studio打开`flutter_hybrid⁩ ▸ ⁨FlutterHybridAndroid⁩`然后运行项目; +3. Ok,有问题可以在[课程讨论区](https://coding.imooc.com/class/321.html)提issue哦; + +## 课程辅导答疑 + +[http://coding.imooc.com/learn/qa/321.html](http://coding.imooc.com/learn/qa/321.html) diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/.gitignore b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/.gitignore new file mode 100644 index 00000000..cdecf14a --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/.gitignore @@ -0,0 +1,41 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ + +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +*.swp +profile + +DerivedData/ + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +build/ +.android/ +.ios/ +.flutter-plugins diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/.metadata b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/.metadata new file mode 100644 index 00000000..05785778 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 007a415c2a2fa37e8fd5ad87d6710bca8e212ef1 + channel: dev + +project_type: module diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/README.md b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/README.md new file mode 100644 index 00000000..6071dc0b --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/README.md @@ -0,0 +1,8 @@ +# flutter_module + +A new flutter module project. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](https://flutter.io/). diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/lib/main.dart b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/lib/main.dart new file mode 100644 index 00000000..0e7ccda8 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/lib/main.dart @@ -0,0 +1,150 @@ +import 'dart:async'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +void main() => runApp(MyApp( + initParams: window.defaultRouteName, + )); + +class MyApp extends StatelessWidget { + final String initParams; + + const MyApp({Key key, this.initParams}) : super(key: key); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter 混合开发', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyHomePage( + title: 'Flutter 混合开发', + initParams: initParams, + ), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title, this.initParams}) : super(key: key); + + final String title; + final String initParams; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + static const EventChannel _eventChannelPlugin = + EventChannel('EventChannelPlugin'); + String showMessage = ""; + static const MethodChannel _methodChannelPlugin = + const MethodChannel('MethodChannelPlugin'); + static const BasicMessageChannel _basicMessageChannel = + const BasicMessageChannel('BasicMessageChannelPlugin', StringCodec()); + bool _isMethodChannelPlugin = false; + StreamSubscription _streamSubscription; + + @override + void initState() { + _streamSubscription = _eventChannelPlugin + .receiveBroadcastStream('123') + .listen(_onToDart, onError: _onToDartError); + //使用BasicMessageChannel接受来自Native的消息,并向Native回复 + _basicMessageChannel + .setMessageHandler((String message) => Future(() { + setState(() { + showMessage = 'BasicMessageChannel:'+message; + }); + return "收到Native的消息:" + message; + })); + super.initState(); + } + + @override + void dispose() { + if (_streamSubscription != null) { + _streamSubscription.cancel(); + _streamSubscription = null; + } + super.dispose(); + } + + void _onToDart(message) { + setState(() { + showMessage = 'EventChannel:'+message; + }); + } + + void _onToDartError(error) { + print(error); + } + + void _onTextChange(value) async { + String response; + try { + if (_isMethodChannelPlugin) { + //使用BasicMessageChannel向Native发送消息,并接受Native的回复 + response = await _methodChannelPlugin.invokeMethod('send', value); + } else { + response = await _basicMessageChannel.send(value); + } + } on PlatformException catch (e) { + print(e); + } + setState(() { + showMessage = response ?? ""; + }); + } + + void _onChanelChanged(bool value) => + setState(() => _isMethodChannelPlugin = value); + + @override + Widget build(BuildContext context) { + TextStyle textStyle = TextStyle(fontSize: 20); + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: Container( + alignment: Alignment.topLeft, + decoration: BoxDecoration(color: Colors.lightBlueAccent), + margin: EdgeInsets.only(top: 70), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SwitchListTile( + value: _isMethodChannelPlugin, + onChanged: _onChanelChanged, + title: Text(_isMethodChannelPlugin + ? "MethodChannelPlugin" + : "BasicMessageChannelPlugin"), + ), + TextField( + onChanged: _onTextChange, + decoration: InputDecoration( + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.white)), + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide(color: Colors.white))), + ), + Text( + '收到初始参数initParams:${widget.initParams}', + style: textStyle, + ), + Text( + 'Native传来的数据:' + showMessage, + style: textStyle, + ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/pubspec.yaml b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/pubspec.yaml new file mode 100644 index 00000000..edd91ebf --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/pubspec.yaml @@ -0,0 +1,85 @@ +name: flutter_module +description: A new flutter module project. + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# +# This version is used _only_ for the Runner app, which is used if you just do +# a `flutter run` or a `flutter make-host-app-editable`. It has no impact +# on any other native host app that you embed your Flutter project into. +version: 1.0.0+1 + +environment: + sdk: ">=2.1.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^0.1.2 + +dev_dependencies: + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://www.dartlang.org/tools/pub/pubspec + +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add Flutter specific assets to your application, add an assets section, + # like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.io/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.io/assets-and-images/#from-packages + + # To add Flutter specific custom fonts to your application, add a fonts + # section here, in this "flutter" section. Each entry in this list should + # have a "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.io/custom-fonts/#from-packages + + + # This section identifies your Flutter project as a module meant for + # embedding in a native host app. These identifiers should _not_ ordinarily + # be changed after generation - they are used to ensure that the tooling can + # maintain consistency when adding or modifying assets and plugins. + # They also do not have any bearing on your native host application's + # identifiers, which may be completely independent or the same as these. + module: + androidPackage: com.example.flutter_module + iosBundleIdentifier: com.example.flutterModule diff --git a/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/test/widget_test.dart b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/test/widget_test.dart new file mode 100644 index 00000000..f29cc338 --- /dev/null +++ b/FlutterHelper/flutter_trip/demo/flutter_hybrid/flutter_module/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_module/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/FlutterHelper/flutter_trip/doc/FAQ.md b/FlutterHelper/flutter_trip/doc/FAQ.md new file mode 100644 index 00000000..c56a1bf4 --- /dev/null +++ b/FlutterHelper/flutter_trip/doc/FAQ.md @@ -0,0 +1,180 @@ +## 切分支或更新缓慢(flutter channel dev) + +[Using Flutter in China](https://flutter.dev/community/china) + +在`.bash_profile`中配置: + +``` + export PUB_HOSTED_URL=https://pub.flutter-io.cn + export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn +``` +or +``` + export PUB_HOSTED_URL=https://pub.flutter-io.cn + export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn + git clone -b dev https://github.com/flutter/flutter.git + export PATH="$PWD/flutter/bin:$PATH" + cd ./flutter + flutter doctor +``` + +单纯升级flutter SDK可以终端切到flutter仓库下运行: + +``` +git pull +``` + +## library not found for -lstdc++.6.0.9 +### 出现场景 +运行百度语音识别iOS Demo时; + +### 解决办法 + +linked frameworks and libraries,中移除`lstdc++.6.0.9`。 + + + + + + +## more than one file was found with OS independent path + +### 出现场景 + +依赖的插件中依赖了flutter,导致libflutter.so合并时产生了冲突。 + +### 解决办法 + +在app/build.gradle中添加: + +``` +android { + ... + packagingOptions { + // 确保app与asr_plugin都依赖的libflutter.so merge时不冲突@https://github.com/card-io/card.io-Android-SDK/issues/186#issuecomment-427552552 + pickFirst 'lib/x86_64/libflutter.so' + pickFirst 'lib/armeabi/libflutter.so' + pickFirst 'lib/x86/libflutter.so' + pickFirst 'lib/armeabi-v7a/libflutter.so' + pickFirst 'lib/arm64-v8a/libflutter.so' + } +} +``` + +### 参考 + +[https://github.com/card-io/card.io-Android-SDK/issues/186#issuecomment-427552552](https://github.com/card-io/card.io-Android-SDK/issues/186#issuecomment-427552552) + +## + +``` +Launching lib/main.dart on Android SDK built for x86 in debug mode... +Initializing gradle... +Resolving dependencies... +Gradle task 'assembleDebug'... + +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':app:transformNativeLibsWithMergeJniLibsForDebug'. +> More than one file was found with OS independent path 'lib/x86/libflutter.so' + +* Try: +Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. + +* Get more help at https://help.gradle.org + +BUILD FAILED in 11s +Finished with error: Gradle task assembleDebug failed with exit code 1 + +``` + + +## cannot find symbol + +### 出现场景 +安装完插件后,或者安装完插件用AndroidStudio打开项目目录下的android项目运行时报`GeneratedPluginRegistrant.java`中所引入的类找不到。 + +### 解决办法 + +运行: + +``` +flutter packages pub cache repair //清除flutter插件的安装缓存,重新安装 +``` +之后在运行项目。 + +### 参考 + +[https://github.com/flutter/flutter/issues/24684#issuecomment-454138309](https://github.com/flutter/flutter/issues/24684#issuecomment-454138309) + +## 点击创建一个新的Flutter项目无响应 +- 关闭模拟器之后重试; +- 重启电脑后重试。 + +## parsing a block mapping. assets: + + +``` +Error on line 45, column 4 of pubspec.yaml: Expected a key while parsing a block mapping. + assets: + ^ +Unable to reload your application because "flutter packages get" failed to update package dependencies. +Exception: pub get failed (65) +``` +### 出现场景 +取消注释assets后。 +### 解决方案, +调整assets的空格缩进和其他行对其。 + +### 参考 +[https://stackoverflow.com/questions/50171766/flutter-pub-expected-a-key-while-parsing-a-block-mapping-path](https://stackoverflow.com/questions/50171766/flutter-pub-expected-a-key-while-parsing-a-block-mapping-path) +## Unable to launch app on ios simulator + +``` +Xcode build done. 5.2s +ProcessException: Process "/usr/bin/xcrun" exited abnormally: +"com.example.flutterApp-ctrip": -1 + +An error was encountered processing the command (domain=FBSOpenApplicationServiceErrorDomain, code=1): +The request to open ""com.example.flutterApp-ctrip"" failed. +The request was denied by service delegate (SBMainWorkspace) for reason: NotFound ("Application ""com.example.flutterApp-ctrip"" is unknown to FrontBoard"). +Underlying error (domain=FBSOpenApplicationErrorDomain, code=4): + The operation couldn’t be completed. Application ""com.example.flutterApp-ctrip"" is unknown to FrontBoard. + Application ""com.example.flutterApp-ctrip"" is unknown to FrontBoard. + Command: /usr/bin/xcrun simctl launch 3E3FA943-715F-482F-B003-D46F5902C56C "com.example.flutterApp-ctrip" --enable-dart-profiling --enable-checked-mode --observatory-port=0 +Error launching application on iPhone X. + +``` + +### 出现场景 + +``` +flutter channel dev +flutter upgrade +flutter run +``` + + +### 解决办法 + +>方案一: + +打开`ios/Runner/Info.plist` 将`Bundle identifier`从 `$(PRODUCT_BUNDLE_IDENTIFIER)` 替换为固定值。 + +``` + CFBundleIdentifier +- $(PRODUCT_BUNDLE_IDENTIFIER) ++ com.example.flutterApp +``` + +>方案二: + +用XCode运行项目代替通过Flutter ide运行 + +``` +open ios/Runner.xcworkspace +``` + + +>参考:[https://github.com/flutter/flutter/issues/21335#issuecomment-423969759](https://github.com/flutter/flutter/issues/21335#issuecomment-423969759) \ No newline at end of file diff --git "a/FlutterHelper/flutter_trip/doc/Flutter\345\277\205\345\244\207Dart\345\237\272\347\241\200\350\257\276\344\273\266.md" "b/FlutterHelper/flutter_trip/doc/Flutter\345\277\205\345\244\207Dart\345\237\272\347\241\200\350\257\276\344\273\266.md" new file mode 100644 index 00000000..88b45226 --- /dev/null +++ "b/FlutterHelper/flutter_trip/doc/Flutter\345\277\205\345\244\207Dart\345\237\272\347\241\200\350\257\276\344\273\266.md" @@ -0,0 +1,8 @@ +通过如下链接查看课件和源码: + +- [Dart知识体系](https://coding.imooc.com/learn/questiondetail/134658.html) +- [Flutter之Dart常用数据类型](https://coding.imooc.com/learn/questiondetail/134659.html) +- [带你揭开Flutter中的面向对象](https://coding.imooc.com/learn/questiondetail/134661.html) +- [带你解锁Flutter中常用的Dart方法类型](https://coding.imooc.com/learn/questiondetail/134662.html) +- [带你了解Dart泛型在Flutter中的应用](https://coding.imooc.com/learn/questiondetail/134663.html) +- [有哪些可以用在Flutter上的编程技巧?](https://coding.imooc.com/learn/questiondetail/134664.html) \ No newline at end of file diff --git "a/FlutterHelper/flutter_trip/doc/MATEX\350\275\257\344\273\266\351\200\202\351\205\215\350\247\204\350\214\203\345\222\214\346\214\207\345\257\274_\344\270\211\346\226\271_V1.0.pdf" "b/FlutterHelper/flutter_trip/doc/MATEX\350\275\257\344\273\266\351\200\202\351\205\215\350\247\204\350\214\203\345\222\214\346\214\207\345\257\274_\344\270\211\346\226\271_V1.0.pdf" new file mode 100644 index 00000000..13fc7dfc Binary files /dev/null and "b/FlutterHelper/flutter_trip/doc/MATEX\350\275\257\344\273\266\351\200\202\351\205\215\350\247\204\350\214\203\345\222\214\346\214\207\345\257\274_\344\270\211\346\226\271_V1.0.pdf" differ diff --git "a/FlutterHelper/flutter_trip/doc/images/\346\227\205\346\213\215\346\216\245\345\217\243\345\205\245\345\217\202\350\216\267\345\217\226\346\226\271\346\263\225.jpg" "b/FlutterHelper/flutter_trip/doc/images/\346\227\205\346\213\215\346\216\245\345\217\243\345\205\245\345\217\202\350\216\267\345\217\226\346\226\271\346\263\225.jpg" new file mode 100644 index 00000000..1c82dba5 Binary files /dev/null and "b/FlutterHelper/flutter_trip/doc/images/\346\227\205\346\213\215\346\216\245\345\217\243\345\205\245\345\217\202\350\216\267\345\217\226\346\226\271\346\263\225.jpg" differ diff --git "a/FlutterHelper/flutter_trip/doc/\345\212\250\347\224\273Animation\345\274\200\345\217\221\346\214\207\345\215\227.md" "b/FlutterHelper/flutter_trip/doc/\345\212\250\347\224\273Animation\345\274\200\345\217\221\346\214\207\345\215\227.md" new file mode 100644 index 00000000..2eb9f1d0 --- /dev/null +++ "b/FlutterHelper/flutter_trip/doc/\345\212\250\347\224\273Animation\345\274\200\345\217\221\346\214\207\345\215\227.md" @@ -0,0 +1,682 @@ + + +>- 本节学习过程中遇到无法解决的问题可以在[课程问答区](https://coding.imooc.com/learn/qa/321.html)进行[提问](https://coding.imooc.com/learn/qa/321.html),课程老师会对你进行帮助辅导; +- 欢迎加入课程官方群:687196170 和讲师以及其他师兄弟们一起学习交流; + +动画Animation开发指南 +---- +* 在Flutter中有哪些类型的动画? +* 如何使用动画库中的基础类给widget添加动画? +* 如何为动画添加监听器? +* 该什么时候使用AnimatedWidget与AnimatedBuilder? +* 如何使用Hero动画? + + +精心设计的动画会让用户界面感觉更直观、流畅,能改善用户体验。 Flutter的动画支持可以轻松实现各种动画类型。许多widget,特别是Material Design widgets, 都带有在其设计规范中定义的标准动画效果,但也可以自定义这些效果。 + + +## 在Flutter中有哪些类型的动画? + +在Flutter中动画分为两类:基于tween或基于物理的。 + +>推荐大家查阅我们上面课程中所讲到的Flutter gallery中的示例代码来学习动画。 + +- 补间(Tween)动画:在补间动画中,定义了开始点和结束点、时间线以及定义转换时间和速度的曲线。然后由框架计算如何从开始点过渡到结束点。 +- 基于物理的动画:在基于物理的动画中,运动被模拟为与真实世界的行为相似。例如,当你掷球时,它在何处落地,取决于抛球速度有多快、球有多重、距离地面有多远。 类似地,将连接在弹簧上的球落下(并弹起)与连接到绳子上的球放下的方式也是不同。 + +## 如何使用动画库中的基础类给widget添加动画? + +在为widget添加动画之前,先让我们认识下动画的几个朋友: + +- [Animation](https://docs.flutter.io/flutter/animation/Animation-class.html):是Flutter动画库中的一个核心类,它生成指导动画的值; +- [CurvedAnimation](https://docs.flutter.io/flutter/animation/CurvedAnimation-class.html):Animation的一个子类,将过程抽象为一个非线性曲线; +- [AnimationController](https://docs.flutter.io/flutter/animation/AnimationController-class.html):Animation的一个子类,用来管理Animation; +- [Tween](https://docs.flutter.io/flutter/animation/Tween-class.html):在正在执行动画的对象所使用的数据范围之间生成值。例如,Tween可生成从红到蓝之间的色值,或者从0到255; + +### Animation + +在Flutter中,Animation对象本身和UI渲染没有任何关系。Animation是一个抽象类,它拥有其当前值和状态(完成或停止)。其中一个比较常用的Animation类是`Animation`。 + +**Flutter中的Animation对象是一个在一段时间内依次生成一个区间之间值的类**。Animation对象的输出可以是线性的、曲线的、一个步进函数或者任何其他可以设计的映射。 根据Animation对象的控制方式,动画可以反向运行,甚至可以在中间切换方向。 + +- Animation还可以生成除double之外的其他类型值,如:`Animation` 或 `Animation`; +- Animation对象有状态。可以通过访问其value属性获取动画的当前值; +- Animation对象本身和UI渲染没有任何关系; + +### CurvedAnimation + +CurvedAnimation将动画过程定义为一个非线性曲线。 + +``` +final CurvedAnimation curve = + new CurvedAnimation(parent: controller, curve: Curves.easeIn); +``` + +>注: [Curves](https://docs.flutter.io/flutter/animation/Curves-class.html) 类定义了许多常用的曲线,也可以创建自己的,例如: + +``` +class ShakeCurve extends Curve { + @override + double transform(double t) { + return math.sin(t * math.PI * 2); + } +} +``` + +### AnimationController + +`AnimationController`是一个特殊的`Animation`对象,在屏幕刷新的每一帧,就会生成一个新的值。默认情况下,`AnimationController`在给定的时间段内会线性的生成从0.0到1.0的数字。 例如,下面代码创建一个Animation对象: + +``` +final AnimationController controller = new AnimationController( + duration: const Duration(milliseconds: 2000), vsync: this); +``` + +AnimationController派生自`Animation`,因此可以在需要Animation对象的任何地方使用。 但是,`AnimationController`具有控制动画的其他方法: + +- `forward()`:启动动画; +- `reverse({double from})`:倒放动画; +- `reset()`:重置动画,将其设置到动画的开始位置; +- `stop({ bool canceled = true })`:停止动画; + +当创建一个AnimationController时,需要传递一个vsync参数,存在vsync时会防止屏幕外动画消耗不必要的资源,可以将stateful对象作为vsync的值。 + +>注意: 在某些情况下,值(position,值动画的当前值)可能会超出AnimationController的0.0-1.0的范围。例如,fling()函数允许您提供速度(velocity)、力量(force)、position(通过Force对象)。位置(position)可以是任何东西,因此可以在0.0到1.0范围之外。 CurvedAnimation生成的值也可以超出0.0到1.0的范围。根据选择的曲线,CurvedAnimation的输出可以具有比输入更大的范围。例如,Curves.elasticIn等弹性曲线会生成大于或小于默认范围的值。 + +### Tween + +默认情况下,AnimationController对象的范围从0.0到1.0。如果您需要不同的范围或不同的数据类型,则可以使用Tween来配置动画以生成不同的范围或数据类型的值。例如,以下示例,Tween生成从-200.0到0.0的值: + +``` +final Tween doubleTween = new Tween(begin: -200.0, end: 0.0); +``` + +Tween是一个无状态(stateless)对象,需要begin和end值。Tween的唯一职责就是定义从输入范围到输出范围的映射。输入范围通常为0.0到1.0,但这不是必须的。 + +Tween继承自`Animatable`,而不是继承自`Animation`。Animatable与Animation相似,不是必须输出double值。例如,ColorTween指定两种颜色之间的过渡。 + +``` +final Tween colorTween = + new ColorTween(begin: Colors.transparent, end: Colors.black54); +``` + +Tween对象不存储任何状态。相反,它提供了`evaluate(Animation animation)`方法将映射函数应用于动画当前值。 Animation对象的当前值可以通过`value()`方法取到。evaluate函数还执行一些其它处理,例如分别确保在动画值为0.0和1.0时返回开始和结束状态。 + +#### Tween.animate + +要使用Tween对象,可调用它的`animate()`方法,传入一个控制器对象。例如,以下代码在500毫秒内生成从0到255的整数值。 + +``` +final AnimationController controller = new AnimationController( + duration: const Duration(milliseconds: 500), vsync: this); +Animation alpha = new IntTween(begin: 0, end: 255).animate(controller); +``` + +注意`animate()`返回的是一个Animation,而不是一个Animatable。 + +以下示例构建了一个控制器、一条曲线和一个Tween: + +``` +final AnimationController controller = new AnimationController( + duration: const Duration(milliseconds: 500), vsync: this); +final Animation curve = + new CurvedAnimation(parent: controller, curve: Curves.easeOut); +Animation alpha = new IntTween(begin: 0, end: 255).animate(curve); +``` + +### 为widget添加动画 + +在下面的实例中我们为一个logo添加了一个从小放大的动画: +![zoom.gif](http://www.devio.org/io/flutter_app/img/blog/zoom.gif) + +``` +import 'package:flutter/animation.dart'; +import 'package:flutter/material.dart'; + +void main() => runApp(LogoApp()); + +class LogoApp extends StatefulWidget { + _LogoAppState createState() => _LogoAppState(); +} + +class _LogoAppState extends State with SingleTickerProviderStateMixin { + Animation animation; + AnimationController controller; + AnimationStatus animationState; + double animationValue; + + @override + void initState() { + super.initState(); + controller = + AnimationController(duration: const Duration(seconds: 2), vsync: this); + // #docregion addListener + animation = Tween(begin: 0, end: 300).animate(controller) + ..addListener(() { + // #enddocregion addListener + setState(() { + animationValue = animation.value; + }); + // #docregion addListener + }) + ..addStatusListener((AnimationStatus state) { + setState(() { + animationState = state; + }); + }); + // #enddocregion addListener + } + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.only(top: 50), + child: Column( + children: [ + GestureDetector( + onTap: () { + controller.reset(); + controller.forward(); + }, + child: Text('Start', textDirection: TextDirection.ltr), + ), + Text('State:' + animationState.toString(), + textDirection: TextDirection.ltr), + Text('Value:' + animationValue.toString(), + textDirection: TextDirection.ltr), + Container( + height: animation.value, + width: animation.value, + child: FlutterLogo(), + ), + ], + ), + ); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } +} +``` + +> 注意,在上述代码中要实现这个动画的关键一步是在`addListener()`的回调中添加`setState`的调用这样才能触发页面重新渲染,动画才能有效,另外也可以通过[AnimatedWidget](#AnimatedWidget)来实现,在下文中会讲到。 + +## 如何为动画添加监听器? + +有时我们需要知道动画执行的进度和状态,在Flutter中我们可以通过Animation的`addListener`与`addStatusListener`方法为动画添加监听器: + +- `addListener`:动画的值发生变化时被调用; +- `addStatusListener`:动画状态发生变化时被调用; + +```dart + @override + void initState() { + super.initState(); + controller = + AnimationController(duration: const Duration(seconds: 2), vsync: this); + animation = Tween(begin: 0, end: 300).animate(controller) + // #enddocregion print-state + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + controller.reverse(); + } else if (status == AnimationStatus.dismissed) { + controller.forward(); + } + }) + // #docregion print-state + ..addStatusListener((state) => print('$state')); + ..addListener(() { + // #enddocregion addListener + setState(() { + // The state that has changed here is the animation object’s value. + }); + // #docregion addListener + }); + controller.forward(); + } +``` + +>可对照学习[为widget添加动画](#为widget添加动画)的例子; + + +## 用AnimatedWidget与AnimatedBuilder简化和重构我们对动画的使用 + +### 什么是AnimatedWidget? + +我们可以将`AnimatedWidget`理解为Animation的助手,使用它可以简化我们对动画的使用,在[为widget添加动画](#为widget添加动画)的学习中我们不难发现,在不使用`AnimatedWidget`的情况下需要手动调用动画的`addListener()`并在回调中添加`setState`才能看到动画效果,`AnimatedWidget`将为我们简化这一操作。 + +在下面的重构示例中,LogoApp现在继承自`AnimatedWidget`而不是`StatefulWidget`。`AnimatedWidget`在绘制时使用动画的当前值。LogoApp仍然管理着`AnimationController`和`Tween`。 + +```dart +// Demonstrate a simple animation with AnimatedWidget + +import 'package:flutter/animation.dart'; +import 'package:flutter/material.dart'; + +class AnimatedLogo extends AnimatedWidget { + AnimatedLogo({Key key, Animation animation}) + : super(key: key, listenable: animation); + + Widget build(BuildContext context) { + final Animation animation = listenable; + return new Center( + child: new Container( + margin: new EdgeInsets.symmetric(vertical: 10.0), + height: animation.value, + width: animation.value, + child: new FlutterLogo(), + ), + ); + } +} + +class LogoApp extends StatefulWidget { + _LogoAppState createState() => new _LogoAppState(); +} + +class _LogoAppState extends State with SingleTickerProviderStateMixin { + AnimationController controller; + Animation animation; + + initState() { + super.initState(); + controller = new AnimationController( + duration: const Duration(milliseconds: 2000), vsync: this); + animation = new Tween(begin: 0.0, end: 300.0).animate(controller); + controller.forward(); + } + + Widget build(BuildContext context) { + return new AnimatedLogo(animation: animation); + } + + dispose() { + controller.dispose(); + super.dispose(); + } +} + +void main() { + runApp(new LogoApp()); +} +``` + +### 什么是AnimatedBuilder? + +`AnimatedBuilder`是用于构建动画的通用widget,AnimatedBuilder对于希望将动画作为更大构建函数的一部分包含在内的更复杂的widget时非常有用,其实你可以这样理解:AnimatedBuilder是拆分动画的一个工具类,借助它我们可以将动画和widget进行分离: + +在上面的实例中我们的代码存在的一个问题: 更改动画需要更改显示logo的widget。更好的解决方案是将职责分离: + +* 显示logo +* 定义Animation对象 +* 渲染过渡效果 + +接下来我们就借助`AnimatedBuilder`类来完成此分离。`AnimatedBuilder`是渲染树中的一个独立的类, 与`AnimatedWidget`类似,`AnimatedBuilder`自动监听来自Animation对象的通知,不需要手动调用`addListener()`。 + +我们根据下图的 widget 树来创建我们的代码: + +![AnimatedBuilder-WidgetTree](http://www.devio.org/io/flutter_app/img/blog/AnimatedBuilder-WidgetTree.png) + +```dart +import 'package:flutter/animation.dart'; +import 'package:flutter/material.dart'; + +void main() => runApp(LogoApp()); + +// #docregion LogoWidget +class LogoWidget extends StatelessWidget { + // Leave out the height and width so it fills the animating parent + Widget build(BuildContext context) => Container( + margin: EdgeInsets.symmetric(vertical: 10), + child: FlutterLogo(), + ); +} +// #enddocregion LogoWidget + +// #docregion GrowTransition +class GrowTransition extends StatelessWidget { + GrowTransition({this.child, this.animation}); + + final Widget child; + final Animation animation; + + Widget build(BuildContext context) => Center( + child: AnimatedBuilder( + animation: animation, + builder: (context, child) => Container( + height: animation.value, + width: animation.value, + child: child, + ), + child: child), + ); +} +// #enddocregion GrowTransition + +class LogoApp extends StatefulWidget { + _LogoAppState createState() => _LogoAppState(); +} + +// #docregion print-state +class _LogoAppState extends State with SingleTickerProviderStateMixin { + Animation animation; + AnimationController controller; + + @override + void initState() { + super.initState(); + controller = + AnimationController(duration: const Duration(seconds: 2), vsync: this); + animation = Tween(begin: 0, end: 300).animate(controller); + controller.forward(); + } + // #enddocregion print-state + + @override + Widget build(BuildContext context) => GrowTransition( + child: LogoWidget(), + animation: animation, + ); + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + // #docregion print-state +} +``` + +## 如何使用Hero动画? + + +### 什么是Hero动画? + + + + + +在 Flutter中可以用 `Hero` widget创建这个动画。当 hero 通过动画从源页面飞到目标页面时,目标页面逐渐淡入视野。通常, `hero` 是用户界面的一小部分,如图片,它通常在两个页面都有。从用户的角度来看, `hero` 在页面之间“飞翔”。接下来我们一起来学习如何创建Hero动画: + +#### 实现标准hero动画 + +```dart +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart' show timeDilation; + +class PhotoHero extends StatelessWidget { + const PhotoHero({ Key key, this.photo, this.onTap, this.width }) : super(key: key); + + final String photo; + final VoidCallback onTap; + final double width; + + Widget build(BuildContext context) { + return SizedBox( + width: width, + child: Hero( + tag: photo, + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: onTap, + child: Image.network( + photo, + fit: BoxFit.contain, + ), + ), + ), + ), + ); + } +} + +class HeroAnimation extends StatelessWidget { + Widget build(BuildContext context) { + timeDilation = 10.0; // 1.0 means normal animation speed. + + return Scaffold( + appBar: AppBar( + title: const Text('Basic Hero Animation'), + ), + body: Center( + child: PhotoHero( + photo: 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/hero_animation/images/flippers-alpha.png', + width: 300.0, + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Flippers Page'), + ), + body: Container( + // Set background to blue to emphasize that it's a new route. + color: Colors.lightBlueAccent, + padding: const EdgeInsets.all(16.0), + alignment: Alignment.topLeft, + child: PhotoHero( + photo: 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/hero_animation/images/flippers-alpha.png', + width: 100.0, + onTap: () { + Navigator.of(context).pop(); + }, + ), + ), + ); + } + )); + }, + ), + ), + ); + } +} + +void main() { + runApp(MaterialApp(home: HeroAnimation())); +} +``` + +#### Hero的函数原型 + +```dart + const Hero({ + Key key, + @required this.tag, + this.createRectTween, + this.flightShuttleBuilder, + this.placeholderBuilder, + this.transitionOnUserGestures = false, + @required this.child, + }) : assert(tag != null), + assert(transitionOnUserGestures != null), + assert(child != null), + super(key: key); +``` + +- tag:[必须]用于关联两个Hero动画的标识; +- createRectTween:[可选]定义目标Hero的边界,在从起始位置到目的位置的“飞行”过程中该如何变化; +- child:[必须]定义动画所呈现的widget; + + +#### 实现径向hero动画 + +```dart +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart' show timeDilation; + +class Photo extends StatelessWidget { + Photo({ Key key, this.photo, this.color, this.onTap }) : super(key: key); + + final String photo; + final Color color; + final VoidCallback onTap; + + Widget build(BuildContext context) { + return Material( + // Slightly opaque color appears where the image has transparency. + color: Theme.of(context).primaryColor.withOpacity(0.25), + child: InkWell( + onTap: onTap, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints size) { + return Image.network( + photo, + fit: BoxFit.contain, + ); + }, + ), + ), + ); + } +} + +class RadialExpansion extends StatelessWidget { + RadialExpansion({ + Key key, + this.maxRadius, + this.child, + }) : clipRectSize = 2.0 * (maxRadius / math.sqrt2), + super(key: key); + + final double maxRadius; + final clipRectSize; + final Widget child; + + @override + Widget build(BuildContext context) { + return ClipOval( + child: Center( + child: SizedBox( + width: clipRectSize, + height: clipRectSize, + child: ClipRect( + child: child, + ), + ), + ), + ); + } +} + +class RadialExpansionDemo extends StatelessWidget { + static const double kMinRadius = 32.0; + static const double kMaxRadius = 128.0; + static const opacityCurve = const Interval(0.0, 0.75, curve: Curves.fastOutSlowIn); + + static RectTween _createRectTween(Rect begin, Rect end) { + return MaterialRectCenterArcTween(begin: begin, end: end); + } + + static Widget _buildPage(BuildContext context, String imageName, String description) { + return Container( + color: Theme.of(context).canvasColor, + child: Center( + child: Card( + elevation: 8.0, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: kMaxRadius * 2.0, + height: kMaxRadius * 2.0, + child: Hero( + createRectTween: _createRectTween, + tag: imageName, + child: RadialExpansion( + maxRadius: kMaxRadius, + child: Photo( + photo: imageName, + onTap: () { + Navigator.of(context).pop(); + }, + ), + ), + ), + ), + Text( + description, + style: TextStyle(fontWeight: FontWeight.bold), + textScaleFactor: 3.0, + ), + const SizedBox(height: 16.0), + ], + ), + ), + ), + ); + } + + Widget _buildHero(BuildContext context, String imageName, String description) { + return Container( + width: kMinRadius * 2.0, + height: kMinRadius * 2.0, + child: Hero( + createRectTween: _createRectTween, + tag: imageName, + child: RadialExpansion( + maxRadius: kMaxRadius, + child: Photo( + photo: imageName, + onTap: () { + Navigator.of(context).push( + PageRouteBuilder( + pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) { + return AnimatedBuilder( + animation: animation, + builder: (BuildContext context, Widget child) { + return Opacity( + opacity: opacityCurve.transform(animation.value), + child: _buildPage(context, imageName, description), + ); + } + ); + }, + ), + ); + }, + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + timeDilation = 5.0; // 1.0 is normal animation speed. + + return Scaffold( + appBar: AppBar( + title: const Text('Radial Transition Demo'), + ), + body: Container( + padding: const EdgeInsets.all(32.0), + alignment: FractionalOffset.bottomLeft, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _buildHero(context, 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/chair-alpha.png', 'Chair'), + _buildHero(context, 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/binoculars-alpha.png', 'Binoculars'), + _buildHero(context, 'https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/beachball-alpha.png', 'Beach ball'), + ], + ), + ), + ); + } +} + +void main() { + runApp(MaterialApp(home: RadialExpansionDemo())); +} +``` + +>- 本节学习过程中遇到无法解决的问题可以在[课程问答区](https://coding.imooc.com/learn/qa/321.html)进行[提问](https://coding.imooc.com/learn/qa/321.html),课程老师会对你进行帮助辅导; +- 欢迎加入课程官方群:687196170 和讲师以及其他师兄弟们一起学习交流; + + diff --git "a/FlutterHelper/flutter_trip/doc/\345\246\202\344\275\225\346\237\245\347\234\213\345\220\204\347\253\240\350\212\202\347\232\204\346\272\220\347\240\201.md" "b/FlutterHelper/flutter_trip/doc/\345\246\202\344\275\225\346\237\245\347\234\213\345\220\204\347\253\240\350\212\202\347\232\204\346\272\220\347\240\201.md" new file mode 100644 index 00000000..5ce083c1 --- /dev/null +++ "b/FlutterHelper/flutter_trip/doc/\345\246\202\344\275\225\346\237\245\347\234\213\345\220\204\347\253\240\350\212\202\347\232\204\346\272\220\347\240\201.md" @@ -0,0 +1,31 @@ +## 简单几部教你查看各章节的源码 +为了方便各位小伙伴学习,课程提供了各章节的源代码供小伙伴们参考,那该如何获得各章节的代码呢? + +### 第一步:打开课程仓库首页 + +[https://git.imooc.com/coding-321/flutter_trip](https://git.imooc.com/coding-321/flutter_trip) + +>课程会不定期更新,建议大家多关注下仓库首页的变更记录以便获得最新的更新内容哦 + +### 第二步:点击查看历史提交 + +![点击查看历史提交](http://www.devio.org/io/flutter_app/img/blog/open-code-history.jpg) + +>通过这个入口可以快速切换到各章节的源码 + +### 第三步:浏览备注,切换到对于的章节记录 + +![切换到对于的章节记录](http://www.devio.org/io/flutter_app/img/blog/open-code-list.jpg) + +>通过这个列表可以快速切换到每一章节的提交 + + +### 第四步:浏览代码 + +![浏览代码](http://www.devio.org/io/flutter_app/img/blog/open-code-browse.jpg) + +>通过浏览代码按钮可以切换到对于的章节代码,除此之外,这个页面记录了这次提交的所有变更,需要的同学可以参考学习下 + +### 第五步:Done,请享用~ + +![浏览代码](http://www.devio.org/io/flutter_app/img/blog/open-code-browse-done.jpg) diff --git "a/FlutterHelper/flutter_trip/doc/\346\220\234\347\264\242\346\216\245\345\217\243\346\226\207\346\241\243.md" "b/FlutterHelper/flutter_trip/doc/\346\220\234\347\264\242\346\216\245\345\217\243\346\226\207\346\241\243.md" new file mode 100644 index 00000000..f30259f8 --- /dev/null +++ "b/FlutterHelper/flutter_trip/doc/\346\220\234\347\264\242\346\216\245\345\217\243\346\226\207\346\241\243.md" @@ -0,0 +1,51 @@ + + +- [接口地址](#接口地址) +- [接口字段](#接口字段) +- [SearchModel](#HomeModel) +- [SearchItem](#CommonModel) +- [模型转换工具](#模型转换工具) + + +## 接口地址 + +[https://m.ctrip.com/restapi/h5api/searchapp/search?source=mobileweb&action=autocomplete&contentType=json&keyword=](https://m.ctrip.com/restapi/h5api/searchapp/search?source=mobileweb&action=autocomplete&contentType=json&keyword=) + +## 接口入参 + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +keyword | String | 搜索关键字 + +>eg: +[https://m.ctrip.com/restapi/h5api/searchapp/search?source=mobileweb&action=autocomplete&contentType=json&keyword=长城)](https://m.ctrip.com/restapi/h5api/searchapp/search?source=mobileweb&action=autocomplete&contentType=json&keyword=长城)) + +## 接口字段 + +[JSON在线解析](https://www.json.cn/) + +## SearchModel + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +`List data` | Array | NonNull + + +## SearchItem + +![search-item](http://www.devio.org/io/flutter_app/img/blog/search-item.png) + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +String word | String | Nullable //xx酒店 +String type | String | Nullable //hotel +String price | String | Nullable //实时计价 +String star | String | Nullable //豪华型 +String zonename | String | Nullable //虹桥 +String districtname | String | Nullable //上海 +String url | String | NonNull + + +## 模型转换工具 + +[http://www.devio.org/io/tools/json-to-dart/](http://www.devio.org/io/tools/json-to-dart/) diff --git "a/FlutterHelper/flutter_trip/doc/\346\227\205\346\213\215\346\250\241\345\235\227\346\216\245\345\217\243\346\226\207\346\241\243.md" "b/FlutterHelper/flutter_trip/doc/\346\227\205\346\213\215\346\250\241\345\235\227\346\216\245\345\217\243\346\226\207\346\241\243.md" new file mode 100644 index 00000000..bc0304c9 --- /dev/null +++ "b/FlutterHelper/flutter_trip/doc/\346\227\205\346\213\215\346\250\241\345\235\227\346\216\245\345\217\243\346\226\207\346\241\243.md" @@ -0,0 +1,487 @@ + +- [接口地址](#接口地址) +- [接口字段](#接口字段) +- [模型转换工具](#模型转换工具) + + +## 接口地址 + + +### 旅拍类别接口 + +[`http://www.devio.org/io/flutter_app/json/travel_page.json`](http://www.devio.org/io/flutter_app/json/travel_page.json) + +### Tab页接口 + +>post + +`https://m.ctrip.com/restapi/soa2/16189/json/searchTripShootListForHomePageV2?_fxpcqlniredt=09031014111431397988&__gw_appid=99999999&__gw_ver=1.0&__gw_from=10650013707&__gw_platform=H5` + +>接口地址动态更新,及时关注课程仓库更新公告! + +>快捷查看返回字段:[searchTrip](http://www.devio.org/io/flutter_app/json/searchTrip/searchTrip_推荐.json) + +## 接口入参 + + +### Tab页接口入参 + +**【重要】这个接口做了防爬,所以接口入参需要动态变化,请参考下面的步骤获取动态参数** + +```js +{ + "districtId": -1, + "groupChannelCode": "RX-OMF", + "type": null, + "lat": -180, + "lon": -180, + "locatedDistrictId": 0, + "pagePara": { + "pageIndex": 1, + "pageSize": 10, + "sortType": 9, + "sortDirection": 0 + }, + "imageCutType": 1, + "head": {'cid': "09031014111431397988"}, + "contentType": "json" +} +``` +>【重要】入参获取方法: + +- 打开携程旅拍H5地址[https://m.ctrip.com/webapp/you/livestream/paipai/home.html?Id=0&districtId=-1&autoawaken=close&popup=close&isHideHeader=true&isHideNavBar=YES&s_guid=851ed907-1b92-4e61-95fd-2d169ab3ee6f](https://m.ctrip.com/webapp/you/livestream/paipai/home.html?Id=0&districtId=-1&autoawaken=close&popup=close&isHideHeader=true&isHideNavBar=YES&s_guid=851ed907-1b92-4e61-95fd-2d169ab3ee6f)获取入参 + +>然后打开Chrome浏览器的开发者模式,接着按照下图的步骤获取请求入参: + +![旅拍接口入参获取方法](https://git.imooc.com/coding-321/flutter_trip/raw/master/doc/images/旅拍接口入参获取方法.jpg) + + + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +pageIndex | int | 第几页 +pageSize | int | 每页显示的条目 +groupChannelCode | String | 频道代码 + + + +## 接口字段 + +[JSON在线解析](https://www.json.cn/) + +## 旅拍类别接口 + + +### TravelTabModel + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +String url | String | NonNull +`List tabs` | Array | NonNull + +### TravelTab + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +String labelName | String | NonNull +String groupChannelCode | String | NonNull + + +## Tab页接口 + +### TravelModel + + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +int totalCount | int | NonNull +`List travelItems` | Array | Nullable + +### TravelItem + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +int type | int | Nullable +Article article | Object | Nullable + +### 整个模型 + +```dart +///旅拍模型 +class TravelModel { + int totalCount; + List travelItems; + + TravelModel({this.totalCount, this.travelItems}); + + TravelModel.fromJson(Map json) { + totalCount = json['totalCount']; + if (json['resultList'] != null) { + travelItems = new List(); + json['resultList'].forEach((v) { + travelItems.add(new TravelItem.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['totalCount'] = this.totalCount; + if (this.travelItems != null) { + data['resultList'] = this.travelItems.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class TravelItem { + int type; + Article article; + + TravelItem({this.type, this.article}); + + TravelItem.fromJson(Map json) { + type = json['type']; + article = + json['article'] != null ? new Article.fromJson(json['article']) : null; + } + + Map toJson() { + final Map data = new Map(); + data['type'] = this.type; + if (this.article != null) { + data['article'] = this.article.toJson(); + } + return data; + } +} + +class Article { + int articleId; + int productType; + int sourceType; + String articleTitle; + Author author; + List images; + bool hasVideo; + int readCount; + int likeCount; + int commentCount; + List urls; + List pois; + String publishTime; + String publishTimeDisplay; + String shootTime; + String shootTimeDisplay; + int level; + String distanceText; + bool isLike; + int imageCounts; + bool isCollected; + int collectCount; + + Article( + {this.articleId, + this.productType, + this.sourceType, + this.articleTitle, + this.author, + this.images, + this.hasVideo, + this.readCount, + this.likeCount, + this.commentCount, + this.urls, + this.pois, + this.publishTime, + this.publishTimeDisplay, + this.shootTime, + this.shootTimeDisplay, + this.level, + this.distanceText, + this.isLike, + this.imageCounts, + this.isCollected, + this.collectCount}); + + Article.fromJson(Map json) { + articleId = json['articleId']; + productType = json['productType']; + sourceType = json['sourceType']; + articleTitle = json['articleTitle']; + author = + json['author'] != null ? new Author.fromJson(json['author']) : null; + if (json['images'] != null) { + images = new List(); + json['images'].forEach((v) { + images.add(new Images.fromJson(v)); + }); + } + hasVideo = json['hasVideo']; + readCount = json['readCount']; + likeCount = json['likeCount']; + commentCount = json['commentCount']; + if (json['urls'] != null) { + urls = new List(); + json['urls'].forEach((v) { + urls.add(new Urls.fromJson(v)); + }); + } + if (json['pois'] != null) { + pois = new List(); + json['pois'].forEach((v) { + pois.add(new Pois.fromJson(v)); + }); + } + publishTime = json['publishTime']; + publishTimeDisplay = json['publishTimeDisplay']; + shootTime = json['shootTime']; + shootTimeDisplay = json['shootTimeDisplay']; + level = json['level']; + distanceText = json['distanceText']; + isLike = json['isLike']; + imageCounts = json['imageCounts']; + isCollected = json['isCollected']; + collectCount = json['collectCount']; + } + + Map toJson() { + final Map data = new Map(); + data['articleId'] = this.articleId; + data['productType'] = this.productType; + data['sourceType'] = this.sourceType; + data['articleTitle'] = this.articleTitle; + if (this.author != null) { + data['author'] = this.author.toJson(); + } + if (this.images != null) { + data['images'] = this.images.map((v) => v.toJson()).toList(); + } + data['hasVideo'] = this.hasVideo; + data['readCount'] = this.readCount; + data['likeCount'] = this.likeCount; + data['commentCount'] = this.commentCount; + if (this.urls != null) { + data['urls'] = this.urls.map((v) => v.toJson()).toList(); + } + + data['publishTime'] = this.publishTime; + data['publishTimeDisplay'] = this.publishTimeDisplay; + data['shootTime'] = this.shootTime; + data['shootTimeDisplay'] = this.shootTimeDisplay; + data['level'] = this.level; + data['distanceText'] = this.distanceText; + data['isLike'] = this.isLike; + data['imageCounts'] = this.imageCounts; + data['isCollected'] = this.isCollected; + data['collectCount'] = this.collectCount; + return data; + } +} + +class Author { + int authorId; + String nickName; + String clientAuth; + String jumpUrl; + CoverImage coverImage; + int identityType; + String tag; + + Author( + {this.authorId, + this.nickName, + this.clientAuth, + this.jumpUrl, + this.coverImage, + this.identityType, + this.tag}); + + Author.fromJson(Map json) { + authorId = json['authorId']; + nickName = json['nickName']; + clientAuth = json['clientAuth']; + jumpUrl = json['jumpUrl']; + coverImage = json['coverImage'] != null + ? new CoverImage.fromJson(json['coverImage']) + : null; + identityType = json['identityType']; + tag = json['tag']; + } + + Map toJson() { + final Map data = new Map(); + data['authorId'] = this.authorId; + data['nickName'] = this.nickName; + data['clientAuth'] = this.clientAuth; + data['jumpUrl'] = this.jumpUrl; + if (this.coverImage != null) { + data['coverImage'] = this.coverImage.toJson(); + } + data['identityType'] = this.identityType; + data['tag'] = this.tag; + return data; + } +} + +class CoverImage { + String dynamicUrl; + String originalUrl; + + CoverImage({this.dynamicUrl, this.originalUrl}); + + CoverImage.fromJson(Map json) { + dynamicUrl = json['dynamicUrl']; + originalUrl = json['originalUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['dynamicUrl'] = this.dynamicUrl; + data['originalUrl'] = this.originalUrl; + return data; + } +} + +class Images { + int imageId; + String dynamicUrl; + String originalUrl; + double width; + double height; + int mediaType; + bool isWaterMarked; + + Images( + {this.imageId, + this.dynamicUrl, + this.originalUrl, + this.width, + this.height, + this.mediaType, + this.isWaterMarked}); + + Images.fromJson(Map json) { + imageId = json['imageId']; + dynamicUrl = json['dynamicUrl']; + originalUrl = json['originalUrl']; + width = json['width']; + height = json['height']; + mediaType = json['mediaType']; + isWaterMarked = json['isWaterMarked']; + } + + Map toJson() { + final Map data = new Map(); + data['imageId'] = this.imageId; + data['dynamicUrl'] = this.dynamicUrl; + data['originalUrl'] = this.originalUrl; + data['width'] = this.width; + data['height'] = this.height; + data['mediaType'] = this.mediaType; + data['isWaterMarked'] = this.isWaterMarked; + return data; + } +} + +class Urls { + String version; + String appUrl; + String h5Url; + String wxUrl; + + Urls({this.version, this.appUrl, this.h5Url, this.wxUrl}); + + Urls.fromJson(Map json) { + version = json['version']; + appUrl = json['appUrl']; + h5Url = json['h5Url']; + wxUrl = json['wxUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['version'] = this.version; + data['appUrl'] = this.appUrl; + data['h5Url'] = this.h5Url; + data['wxUrl'] = this.wxUrl; + return data; + } +} + +class Pois { + int poiType; + int poiId; + String poiName; + int districtId; + String districtName; + String districtENName; + PoiExt poiExt; + int source; + int isMain; + + Pois( + {this.poiType, + this.poiId, + this.poiName, + this.districtId, + this.districtName, + this.districtENName, + this.poiExt, + this.source, + this.isMain}); + + Pois.fromJson(Map json) { + poiType = json['poiType']; + poiId = json['poiId']; + poiName = json['poiName']; + districtId = json['districtId']; + districtName = json['districtName']; + districtENName = json['districtENName']; + poiExt = + json['poiExt'] != null ? new PoiExt.fromJson(json['poiExt']) : null; + source = json['source']; + isMain = json['isMain']; + } + + Map toJson() { + final Map data = new Map(); + data['poiType'] = this.poiType; + data['poiId'] = this.poiId; + data['poiName'] = this.poiName; + data['districtId'] = this.districtId; + data['districtName'] = this.districtName; + data['districtENName'] = this.districtENName; + if (this.poiExt != null) { + data['poiExt'] = this.poiExt.toJson(); + } + data['source'] = this.source; + data['isMain'] = this.isMain; + return data; + } +} + +class PoiExt { + String h5Url; + String appUrl; + + PoiExt({this.h5Url, this.appUrl}); + + PoiExt.fromJson(Map json) { + h5Url = json['h5Url']; + appUrl = json['appUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['h5Url'] = this.h5Url; + data['appUrl'] = this.appUrl; + return data; + } +} +``` + + +## 模型转换工具 + +[http://www.devio.org/io/tools/json-to-dart/](http://www.devio.org/io/tools/json-to-dart/) diff --git "a/FlutterHelper/flutter_trip/doc/\351\246\226\351\241\265\345\244\247\346\216\245\345\217\243\346\226\207\346\241\243.md" "b/FlutterHelper/flutter_trip/doc/\351\246\226\351\241\265\345\244\247\346\216\245\345\217\243\346\226\207\346\241\243.md" new file mode 100644 index 00000000..778ca901 --- /dev/null +++ "b/FlutterHelper/flutter_trip/doc/\351\246\226\351\241\265\345\244\247\346\216\245\345\217\243\346\226\207\346\241\243.md" @@ -0,0 +1,98 @@ + + +- [接口地址](#接口地址) +- [接口字段](#接口字段) +- [HomeModel](#HomeModel) +- [CommonModel](#CommonModel) +- [GridNavModel](#GridNavModel) +- [GridNavItem](#GridNavItem) +- [SalesBoxModel](#SalesBoxModel) +- [ConfigModel](#ConfigModel) +- [模型转换工具](#模型转换工具) + + +## 接口地址 + +[http://www.devio.org/io/flutter_app/json/home_page.json](http://www.devio.org/io/flutter_app/json/home_page.json) + +## 接口字段 + +[JSON在线解析](https://www.json.cn/) + +## HomeModel + +![home_page](http://www.devio.org/io/flutter_app/img/blog/home_page.png) + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +ConfigModel config | Object | NonNull +`List` bannerList | Array | NonNull +`List` localNavList | Array | NonNull +GridNavModel gridNav | Object | NonNull +`List` subNavList | Array | NonNull +SalesBoxModel salesBox | Object | NonNull + +## CommonModel + +![common-model](http://www.devio.org/io/flutter_app/img/blog/common-model.png) + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +String icon | String | Nullable +String title | String | Nullable +String url | String | NonNull +String statusBarColor | String | Nullable +bool hideAppBar | bool | Nullable + +## GridNavModel + +![grid-nav](http://www.devio.org/io/flutter_app/img/blog/grid-nav.png) + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +GridNavItem hotel | Object | NonNull +GridNavItem flight | Object | NonNull +GridNavItem travel | Object | NonNull + +# GridNavItem + +![grid-nav-item.png](http://www.devio.org/io/flutter_app/img/blog/grid-nav-item.png) + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +String startColor | String | NonNull +String endColor | String | NonNull +CommonModel mainItem | Object | NonNull +CommonModel item1 | Object | NonNull +CommonModel item2 | Object | NonNull +CommonModel item3 | Object | NonNull +CommonModel item4 | Object | NonNull + + +## SalesBoxModel + +![sales-box](http://www.devio.org/io/flutter_app/img/blog/sales-box.png) + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +String icon | String | NonNull +String moreUrl | String | NonNull +CommonModel bigCard1 | Object | NonNull +CommonModel bigCard2 | Object | NonNull +CommonModel smallCard1 | Object | NonNull +CommonModel smallCard2 | Object | NonNull +CommonModel smallCard3 | Object | NonNull +CommonModel smallCard4 | Object | NonNull + +## ConfigModel + +![config](http://www.devio.org/io/flutter_app/img/blog/config.png) + +字段 | 类型 | 备注 +| -------- | -------- | -------- | +String searchUrl | String | NonNull + + +## 模型转换工具 + +[http://www.devio.org/io/tools/json-to-dart/](http://www.devio.org/io/tools/json-to-dart/) diff --git a/FlutterHelper/flutter_trip/images/type_channelgroup.png b/FlutterHelper/flutter_trip/images/type_channelgroup.png new file mode 100644 index 00000000..40fd73a1 Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_channelgroup.png differ diff --git a/FlutterHelper/flutter_trip/images/type_channelgs.png b/FlutterHelper/flutter_trip/images/type_channelgs.png new file mode 100644 index 00000000..4bb4377f Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_channelgs.png differ diff --git a/FlutterHelper/flutter_trip/images/type_channelplane.png b/FlutterHelper/flutter_trip/images/type_channelplane.png new file mode 100644 index 00000000..a168ad32 Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_channelplane.png differ diff --git a/FlutterHelper/flutter_trip/images/type_channeltrain.png b/FlutterHelper/flutter_trip/images/type_channeltrain.png new file mode 100644 index 00000000..1b77530a Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_channeltrain.png differ diff --git a/FlutterHelper/flutter_trip/images/type_cruise.png b/FlutterHelper/flutter_trip/images/type_cruise.png new file mode 100644 index 00000000..98e74d6e Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_cruise.png differ diff --git a/FlutterHelper/flutter_trip/images/type_district.png b/FlutterHelper/flutter_trip/images/type_district.png new file mode 100644 index 00000000..3a5db15c Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_district.png differ diff --git a/FlutterHelper/flutter_trip/images/type_food.png b/FlutterHelper/flutter_trip/images/type_food.png new file mode 100644 index 00000000..ec7217e9 Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_food.png differ diff --git a/FlutterHelper/flutter_trip/images/type_hotel.png b/FlutterHelper/flutter_trip/images/type_hotel.png new file mode 100644 index 00000000..d9a08a7f Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_hotel.png differ diff --git a/FlutterHelper/flutter_trip/images/type_huodong.png b/FlutterHelper/flutter_trip/images/type_huodong.png new file mode 100644 index 00000000..87d497c3 Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_huodong.png differ diff --git a/FlutterHelper/flutter_trip/images/type_shop.png b/FlutterHelper/flutter_trip/images/type_shop.png new file mode 100644 index 00000000..51fd82b1 Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_shop.png differ diff --git a/FlutterHelper/flutter_trip/images/type_sight.png b/FlutterHelper/flutter_trip/images/type_sight.png new file mode 100644 index 00000000..3d24cd39 Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_sight.png differ diff --git a/FlutterHelper/flutter_trip/images/type_ticket.png b/FlutterHelper/flutter_trip/images/type_ticket.png new file mode 100644 index 00000000..c780ce75 Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_ticket.png differ diff --git a/FlutterHelper/flutter_trip/images/type_travelgroup.png b/FlutterHelper/flutter_trip/images/type_travelgroup.png new file mode 100644 index 00000000..f96a1ba3 Binary files /dev/null and b/FlutterHelper/flutter_trip/images/type_travelgroup.png differ diff --git a/FlutterHelper/flutter_trip/ios/Flutter/AppFrameworkInfo.plist b/FlutterHelper/flutter_trip/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..9367d483 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/FlutterHelper/flutter_trip/ios/Flutter/Debug.xcconfig b/FlutterHelper/flutter_trip/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..e8efba11 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/FlutterHelper/flutter_trip/ios/Flutter/Release.xcconfig b/FlutterHelper/flutter_trip/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..399e9340 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/FlutterHelper/flutter_trip/ios/Flutter/flutter_export_environment.sh b/FlutterHelper/flutter_trip/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 00000000..eea40ddf --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Users/flannery/Library/Android/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/flannery/Desktop/AndroidHelper/FlutterHelper/flutter_trip" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build/ios" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=false" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.packages" diff --git a/FlutterHelper/flutter_trip/ios/Podfile b/FlutterHelper/flutter_trip/ios/Podfile new file mode 100644 index 00000000..d077b08b --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Podfile @@ -0,0 +1,69 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + pods_ary = [] + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) { |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + pods_ary.push({:name => podname, :path => podpath}); + else + puts "Invalid plugin specification: #{line}" + end + } + return pods_ary +end + +target 'Runner' do + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + system('rm -rf .symlinks') + system('mkdir -p .symlinks/plugins') + + # Flutter Pods + generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') + if generated_xcode_build_settings.empty? + puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." + end + generated_xcode_build_settings.map { |p| + if p[:name] == 'FLUTTER_FRAMEWORK_DIR' + symlink = File.join('.symlinks', 'flutter') + File.symlink(File.dirname(p[:path]), symlink) + pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) + end + } + + # Plugin Pods + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.map { |p| + symlink = File.join('.symlinks', 'plugins', p[:name]) + File.symlink(p[:path], symlink) + pod p[:name], :path => File.join(symlink, 'ios') + } +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/project.pbxproj b/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..ee9f9e1f --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,703 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; + 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 9ADFC678ABED42F491684F36 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DE576E76B5BC0DACC6DE45F5 /* libPods-Runner.a */; }; + F483EC8B223E6547002A2034 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F483EC8A223E6547002A2034 /* CoreTelephony.framework */; }; + F483EC8D223E6564002A2034 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = F483EC8C223E6564002A2034 /* libsqlite3.0.tbd */; }; + F483EC8F223E6574002A2034 /* libiconv.2.4.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = F483EC8E223E6574002A2034 /* libiconv.2.4.0.tbd */; }; + F483EC91223E6593002A2034 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = F483EC90223E6593002A2034 /* libc++.tbd */; }; + F483EC93223E65A1002A2034 /* libz.1.2.5.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = F483EC92223E65A1002A2034 /* libz.1.2.5.tbd */; }; + F4AF77C2223E9E3400570310 /* bds_license.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77B9223E9E3400570310 /* bds_license.dat */; }; + F4AF77C3223E9E3400570310 /* bds_easr_basic_model.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77BA223E9E3400570310 /* bds_easr_basic_model.dat */; }; + F4AF77C4223E9E3400570310 /* bds_easr_mfe_cmvn.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77BB223E9E3400570310 /* bds_easr_mfe_cmvn.dat */; }; + F4AF77C5223E9E3400570310 /* temp_license_2018-02-24.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77BC223E9E3400570310 /* temp_license_2018-02-24.dat */; }; + F4AF77C6223E9E3400570310 /* bds_easr_input_model.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77BD223E9E3400570310 /* bds_easr_input_model.dat */; }; + F4AF77C7223E9E3400570310 /* bds_easr_mfe_dnn.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77BE223E9E3400570310 /* bds_easr_mfe_dnn.dat */; }; + F4AF77C8223E9E3400570310 /* bds_easr_gramm.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77BF223E9E3400570310 /* bds_easr_gramm.dat */; }; + F4AF77C9223E9E3400570310 /* bds_easr_wakeup_words.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77C0223E9E3400570310 /* bds_easr_wakeup_words.dat */; }; + F4AF77CA223E9E3400570310 /* bds_easr_dnn_wakeup_model.dat in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77C1223E9E3400570310 /* bds_easr_dnn_wakeup_model.dat */; }; + F4AF77CC223E9E4D00570310 /* BDSClientResources in Resources */ = {isa = PBXBuildFile; fileRef = F4AF77CB223E9E4C00570310 /* BDSClientResources */; }; + F4AF77D1223E9E6700570310 /* libBaiduSpeechSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F4AF77D0223E9E6700570310 /* libBaiduSpeechSDK.a */; }; + F4AF77E5223EA3B000570310 /* AsrManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F4AF77E4223EA3B000570310 /* AsrManager.m */; }; + F4AF77EC223EAD9F00570310 /* AsrPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = F4AF77EA223EAD9E00570310 /* AsrPlugin.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DE576E76B5BC0DACC6DE45F5 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + F483EC8A223E6547002A2034 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; + F483EC8C223E6564002A2034 /* libsqlite3.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; }; + F483EC8E223E6574002A2034 /* libiconv.2.4.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.2.4.0.tbd; path = usr/lib/libiconv.2.4.0.tbd; sourceTree = SDKROOT; }; + F483EC90223E6593002A2034 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; + F483EC92223E65A1002A2034 /* libz.1.2.5.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.1.2.5.tbd; path = usr/lib/libz.1.2.5.tbd; sourceTree = SDKROOT; }; + F4AF77B9223E9E3400570310 /* bds_license.dat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = bds_license.dat; sourceTree = ""; }; + F4AF77BA223E9E3400570310 /* bds_easr_basic_model.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = bds_easr_basic_model.dat; sourceTree = ""; }; + F4AF77BB223E9E3400570310 /* bds_easr_mfe_cmvn.dat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = bds_easr_mfe_cmvn.dat; sourceTree = ""; }; + F4AF77BC223E9E3400570310 /* temp_license_2018-02-24.dat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "temp_license_2018-02-24.dat"; sourceTree = ""; }; + F4AF77BD223E9E3400570310 /* bds_easr_input_model.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = bds_easr_input_model.dat; sourceTree = ""; }; + F4AF77BE223E9E3400570310 /* bds_easr_mfe_dnn.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = bds_easr_mfe_dnn.dat; sourceTree = ""; }; + F4AF77BF223E9E3400570310 /* bds_easr_gramm.dat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = bds_easr_gramm.dat; sourceTree = ""; }; + F4AF77C0223E9E3400570310 /* bds_easr_wakeup_words.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = bds_easr_wakeup_words.dat; sourceTree = ""; }; + F4AF77C1223E9E3400570310 /* bds_easr_dnn_wakeup_model.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = bds_easr_dnn_wakeup_model.dat; sourceTree = ""; }; + F4AF77CB223E9E4C00570310 /* BDSClientResources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = BDSClientResources; sourceTree = ""; }; + F4AF77D0223E9E6700570310 /* libBaiduSpeechSDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libBaiduSpeechSDK.a; sourceTree = ""; }; + F4AF77E3223EA3B000570310 /* AsrManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsrManager.h; sourceTree = ""; }; + F4AF77E4223EA3B000570310 /* AsrManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AsrManager.m; sourceTree = ""; }; + F4AF77E7223EA74900570310 /* BDSASRParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BDSASRParameters.h; sourceTree = ""; }; + F4AF77E8223EA74900570310 /* BDSEventManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BDSEventManager.h; sourceTree = ""; }; + F4AF77E9223EA74900570310 /* BDSASRDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BDSASRDefines.h; sourceTree = ""; }; + F4AF77EA223EAD9E00570310 /* AsrPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AsrPlugin.m; sourceTree = ""; }; + F4AF77EB223EAD9E00570310 /* AsrPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AsrPlugin.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F483EC93223E65A1002A2034 /* libz.1.2.5.tbd in Frameworks */, + F483EC91223E6593002A2034 /* libc++.tbd in Frameworks */, + F483EC8F223E6574002A2034 /* libiconv.2.4.0.tbd in Frameworks */, + F483EC8D223E6564002A2034 /* libsqlite3.0.tbd in Frameworks */, + F483EC8B223E6547002A2034 /* CoreTelephony.framework in Frameworks */, + F4AF77D1223E9E6700570310 /* libBaiduSpeechSDK.a in Frameworks */, + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + 9ADFC678ABED42F491684F36 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 82EA46E04D625A371826E6C5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + F483EC92223E65A1002A2034 /* libz.1.2.5.tbd */, + F483EC90223E6593002A2034 /* libc++.tbd */, + F483EC8E223E6574002A2034 /* libiconv.2.4.0.tbd */, + F483EC8C223E6564002A2034 /* libsqlite3.0.tbd */, + F483EC8A223E6547002A2034 /* CoreTelephony.framework */, + DE576E76B5BC0DACC6DE45F5 /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + F483EC6F223E645A002A2034 /* plugin */, + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + FCB13B4E20F725B88BF371CE /* Pods */, + 82EA46E04D625A371826E6C5 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + F483EC6F223E645A002A2034 /* plugin */ = { + isa = PBXGroup; + children = ( + F4AF77B7223E9DDB00570310 /* ASRPlugin */, + ); + path = plugin; + sourceTree = ""; + }; + F4AF77B7223E9DDB00570310 /* ASRPlugin */ = { + isa = PBXGroup; + children = ( + F4AF77EA223EAD9E00570310 /* AsrPlugin.m */, + F4AF77EB223EAD9E00570310 /* AsrPlugin.h */, + F4AF77E6223EA74900570310 /* Headers */, + F4AF77E3223EA3B000570310 /* AsrManager.h */, + F4AF77E4223EA3B000570310 /* AsrManager.m */, + F4AF77CF223E9E6700570310 /* BDSClientLib */, + F4AF77CB223E9E4C00570310 /* BDSClientResources */, + F4AF77B8223E9E3400570310 /* BDSClientEASRResources */, + ); + path = ASRPlugin; + sourceTree = ""; + }; + F4AF77B8223E9E3400570310 /* BDSClientEASRResources */ = { + isa = PBXGroup; + children = ( + F4AF77B9223E9E3400570310 /* bds_license.dat */, + F4AF77BA223E9E3400570310 /* bds_easr_basic_model.dat */, + F4AF77BB223E9E3400570310 /* bds_easr_mfe_cmvn.dat */, + F4AF77BC223E9E3400570310 /* temp_license_2018-02-24.dat */, + F4AF77BD223E9E3400570310 /* bds_easr_input_model.dat */, + F4AF77BE223E9E3400570310 /* bds_easr_mfe_dnn.dat */, + F4AF77BF223E9E3400570310 /* bds_easr_gramm.dat */, + F4AF77C0223E9E3400570310 /* bds_easr_wakeup_words.dat */, + F4AF77C1223E9E3400570310 /* bds_easr_dnn_wakeup_model.dat */, + ); + path = BDSClientEASRResources; + sourceTree = ""; + }; + F4AF77CF223E9E6700570310 /* BDSClientLib */ = { + isa = PBXGroup; + children = ( + F4AF77D0223E9E6700570310 /* libBaiduSpeechSDK.a */, + ); + path = BDSClientLib; + sourceTree = ""; + }; + F4AF77E6223EA74900570310 /* Headers */ = { + isa = PBXGroup; + children = ( + F4AF77E7223EA74900570310 /* BDSASRParameters.h */, + F4AF77E8223EA74900570310 /* BDSEventManager.h */, + F4AF77E9223EA74900570310 /* BDSASRDefines.h */, + ); + path = Headers; + sourceTree = ""; + }; + FCB13B4E20F725B88BF371CE /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 4E0846CB11F68CE74AAAA087 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 5ADDB2A52B0FBA2A70C0A2A7 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0910; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = Y3MLDMF5L7; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F4AF77C7223E9E3400570310 /* bds_easr_mfe_dnn.dat in Resources */, + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + F4AF77C6223E9E3400570310 /* bds_easr_input_model.dat in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + F4AF77C4223E9E3400570310 /* bds_easr_mfe_cmvn.dat in Resources */, + F4AF77CC223E9E4D00570310 /* BDSClientResources in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, + F4AF77C8223E9E3400570310 /* bds_easr_gramm.dat in Resources */, + F4AF77C3223E9E3400570310 /* bds_easr_basic_model.dat in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + F4AF77C9223E9E3400570310 /* bds_easr_wakeup_words.dat in Resources */, + F4AF77C2223E9E3400570310 /* bds_license.dat in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + F4AF77C5223E9E3400570310 /* temp_license_2018-02-24.dat in Resources */, + F4AF77CA223E9E3400570310 /* bds_easr_dnn_wakeup_model.dat in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + }; + 4E0846CB11F68CE74AAAA087 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 5ADDB2A52B0FBA2A70C0A2A7 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + ); + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F4AF77E5223EA3B000570310 /* AsrManager.m in Sources */, + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m in Sources */, + F4AF77EC223EAD9F00570310 /* AsrPlugin.m in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = Y3MLDMF5L7; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + "$(PROJECT_DIR)/plugin/BDSClientLib", + "$(PROJECT_DIR)/plugin/ASRPlugin/BDSClientLib", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.devio.flutter.trip; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = Y3MLDMF5L7; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + "$(PROJECT_DIR)/plugin/BDSClientLib", + "$(PROJECT_DIR)/plugin/ASRPlugin/BDSClientLib", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.devio.flutter.trip; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = Y3MLDMF5L7; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + "$(PROJECT_DIR)/plugin/BDSClientLib", + "$(PROJECT_DIR)/plugin/ASRPlugin/BDSClientLib", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.devio.flutter.trip; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..786d6aad --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/contents.xcworkspacedata b/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..949b6789 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + BuildSystemType + Original + + diff --git a/FlutterHelper/flutter_trip/ios/Runner/AppDelegate.h b/FlutterHelper/flutter_trip/ios/Runner/AppDelegate.h new file mode 100644 index 00000000..36e21bbf --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/FlutterHelper/flutter_trip/ios/Runner/AppDelegate.m b/FlutterHelper/flutter_trip/ios/Runner/AppDelegate.m new file mode 100644 index 00000000..510ced64 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/AppDelegate.m @@ -0,0 +1,16 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" +#import "AsrPlugin.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + //注册自有的插件 + [AsrPlugin registerWithRegistrar:[self registrarForPlugin:@"AsrPlugain"]]; + // Override point for customization after application launch. + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..f5214247 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..af74ef12 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..b3beb093 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..3057b76b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..23e4e62b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..98039c53 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..a2059dbc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..908dbfe2 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..24d2319f Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..6da81d0c Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..2c3d247c Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..1b222603 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..aff753b7 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..44df93c6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..b8ce982a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/Contents.json b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..14e5217b --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.launchimage/Contents.json b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 00000000..c5fda8e3 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,9 @@ +{ + "images" : [ + + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/splash_screen.imageset/Contents.json b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/splash_screen.imageset/Contents.json new file mode 100644 index 00000000..82ee343c --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/splash_screen.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "splash_screen.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/splash_screen.imageset/splash_screen.png b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/splash_screen.imageset/splash_screen.png new file mode 100644 index 00000000..41a69429 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/Runner/Assets.xcassets/splash_screen.imageset/splash_screen.png differ diff --git a/FlutterHelper/flutter_trip/ios/Runner/Base.lproj/LaunchScreen.storyboard b/FlutterHelper/flutter_trip/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..570348bb --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/ios/Runner/Base.lproj/Main.storyboard b/FlutterHelper/flutter_trip/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/flutter_trip/ios/Runner/Info.plist b/FlutterHelper/flutter_trip/ios/Runner/Info.plist new file mode 100644 index 00000000..c2245f90 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Flutter之旅 + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flutter_trip + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSMicrophoneUsageDescription + 使用语音搜索需要录音权限 + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/FlutterHelper/flutter_trip/ios/Runner/main.m b/FlutterHelper/flutter_trip/ios/Runner/main.m new file mode 100644 index 00000000..dff6597e --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/Runner/main.m @@ -0,0 +1,9 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrManager.h b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrManager.h new file mode 100644 index 00000000..7d2e0fd4 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrManager.h @@ -0,0 +1,19 @@ +// +// NSObject+AsrManager.h +// Runner +// +// Created by jph on 2019/3/17. +// Copyright © 2019 The Chromium Authors. All rights reserved. +// + +#import + +@interface AsrManager:NSObject +typedef void(^AsrCallback)(NSString* message); ++(instancetype)initWith:(AsrCallback)success failure:(AsrCallback)failure; +- (void)start; +- (void)stop; +- (void)cancel; +@end + + diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrManager.m b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrManager.m new file mode 100644 index 00000000..a9b4204f --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrManager.m @@ -0,0 +1,177 @@ +// +// NSObject+AsrManager.m +// Runner +// +// Created by jph on 2019/3/17. +// Copyright © 2019 The Chromium Authors. All rights reserved. +// + +#import "AsrManager.h" +#import "BDSEventManager.h" +#import "BDSASRParameters.h" +#import "BDSASRDefines.h" + +//#error "请在官网新建应用,配置包名,并在此填写应用的 api key, secret key, appid(即appcode)" +const NSString* API_KEY = @"My3eUqlXXehleKokh0S38P9f"; +const NSString* SECRET_KEY = @"TZMSHKGqNs2WW0EmpXTgGOtxGaLVayFT"; +const NSString* APP_ID = @"15519362"; + +@interface AsrManager () +@property (strong, nonatomic) BDSEventManager *asrEventManager; +@property (nonatomic,copy)AsrCallback asrSuccess; +@property (nonatomic,copy)AsrCallback asrFailure; +@end +@implementation AsrManager ++(instancetype)initWith:(AsrCallback)success failure:(AsrCallback)failure{ + AsrManager*asrManager =[AsrManager new]; + asrManager.asrFailure= failure; + asrManager.asrSuccess = success; + return asrManager; +} +-(id)init{ + self = [super init]; + self.asrEventManager = [BDSEventManager createEventManagerWithName:BDS_ASR_NAME]; + [self configVoiceRecognitionClient]; + return self; +} + +#pragma mark - Action +-(void)start{ + [self.asrEventManager setParameter:@(NO) forKey:BDS_ASR_NEED_CACHE_AUDIO]; + [self.asrEventManager setDelegate:self]; + [self.asrEventManager setParameter:nil forKey:BDS_ASR_AUDIO_FILE_PATH]; + [self.asrEventManager setParameter:nil forKey:BDS_ASR_AUDIO_INPUT_STREAM]; + [self.asrEventManager sendCommand:BDS_ASR_CMD_START]; +} +-(void)stop{ + [self.asrEventManager sendCommand:BDS_ASR_CMD_STOP]; +} +-(void)cancel{ + [self.asrEventManager sendCommand:BDS_ASR_CMD_CANCEL]; +} + +#pragma mark - Private: Configuration + +- (void)configVoiceRecognitionClient { + //设置DEBUG_LOG的级别 + [self.asrEventManager setParameter:@(EVRDebugLogLevelTrace) forKey:BDS_ASR_DEBUG_LOG_LEVEL]; + //配置API_KEY 和 SECRET_KEY 和 APP_ID + [self.asrEventManager setParameter:@[API_KEY, SECRET_KEY] forKey:BDS_ASR_API_SECRET_KEYS]; + [self.asrEventManager setParameter:APP_ID forKey:BDS_ASR_OFFLINE_APP_CODE]; + //配置端点检测(二选一) + [self configModelVAD]; + // [self configDNNMFE]; + + // [self.asrEventManager setParameter:@"15361" forKey:BDS_ASR_PRODUCT_ID]; + // ---- 语义与标点 ----- + [self enableNLU]; + // [self enablePunctuation]; + // ------------------------ +} + + +- (void) enableNLU { + // ---- 开启语义理解 ----- + [self.asrEventManager setParameter:@(YES) forKey:BDS_ASR_ENABLE_NLU]; + [self.asrEventManager setParameter:@"1536" forKey:BDS_ASR_PRODUCT_ID]; +} + +- (void) enablePunctuation { + // ---- 开启标点输出 ----- + [self.asrEventManager setParameter:@(NO) forKey:BDS_ASR_DISABLE_PUNCTUATION]; + // 普通话标点 + // [self.asrEventManager setParameter:@"1537" forKey:BDS_ASR_PRODUCT_ID]; + // 英文标点 + [self.asrEventManager setParameter:@"1737" forKey:BDS_ASR_PRODUCT_ID]; + +} + +- (void)configModelVAD { + NSString *modelVAD_filepath = [[NSBundle mainBundle] pathForResource:@"bds_easr_basic_model" ofType:@"dat"]; + [self.asrEventManager setParameter:modelVAD_filepath forKey:BDS_ASR_MODEL_VAD_DAT_FILE]; + [self.asrEventManager setParameter:@(YES) forKey:BDS_ASR_ENABLE_MODEL_VAD]; +} +#pragma mark - MVoiceRecognitionClientDelegate + +- (void)VoiceRecognitionClientWorkStatus:(int)workStatus obj:(id)aObj { + switch (workStatus) { + case EVoiceRecognitionClientWorkStatusNewRecordData: { + + break; + } + + case EVoiceRecognitionClientWorkStatusStartWorkIng: { + + break; + } + case EVoiceRecognitionClientWorkStatusStart: { + + break; + } + case EVoiceRecognitionClientWorkStatusEnd: { + + break; + } + case EVoiceRecognitionClientWorkStatusFlushData: { + + break; + } + case EVoiceRecognitionClientWorkStatusFinish: {//语音识别功能完成,服务器返回正确结果 + if ([aObj isKindOfClass:[NSDictionary class]]) { + NSString *result =aObj[@"results_recognition"][0]; + if (self.asrSuccess) { + self.asrSuccess(result); + } + } + break; + } + case EVoiceRecognitionClientWorkStatusMeterLevel: { + break; + } + case EVoiceRecognitionClientWorkStatusCancel: { + + break; + } + case EVoiceRecognitionClientWorkStatusError: {//发生错误 + if (self.asrFailure) { + self.asrFailure([((NSError *)aObj) description]); + } + break; + } + case EVoiceRecognitionClientWorkStatusLoaded: { + + break; + } + case EVoiceRecognitionClientWorkStatusUnLoaded: { + + break; + } + case EVoiceRecognitionClientWorkStatusChunkThirdData: { + + break; + } + case EVoiceRecognitionClientWorkStatusChunkNlu: { + + break; + } + case EVoiceRecognitionClientWorkStatusChunkEnd: { + + break; + } + case EVoiceRecognitionClientWorkStatusFeedback: { + + break; + } + case EVoiceRecognitionClientWorkStatusRecorderEnd: { + + break; + } + case EVoiceRecognitionClientWorkStatusLongSpeechEnd: { + + break; + } + default: + break; + } +} +@end diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrPlugin.h b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrPlugin.h new file mode 100644 index 00000000..48792a66 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrPlugin.h @@ -0,0 +1,15 @@ +// +// NSObject+AsrManager.h +// Runner +// +// Created by jph on 2019/3/17. +// Copyright © 2019 The Chromium Authors. All rights reserved. +// +#import +#import + +@interface AsrPlugin:NSObject + +@end + + diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrPlugin.m b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrPlugin.m new file mode 100644 index 00000000..215a6437 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/AsrPlugin.m @@ -0,0 +1,50 @@ +// +// NSObject+AsrManager.m +// Runner +// +// Created by jph on 2019/3/17. +// Copyright © 2019 The Chromium Authors. All rights reserved. +// + +#import "AsrPlugin.h" +#import "AsrManager.h" + +@interface AsrPlugin () +@property (strong, nonatomic) AsrManager *asrManager; +@property (strong, nonatomic) FlutterResult result; +@end +@implementation AsrPlugin ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"asr_plugin" binaryMessenger:[registrar messenger] ]; + AsrPlugin* instance =[AsrPlugin new]; + [registrar addMethodCallDelegate:instance channel:channel]; +} +- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { + if ([@"start" isEqualToString:call.method]) { + self.result = result; + [[self _asrManager] start]; + }else if ([@"stop" isEqualToString:call.method]) { + [[self _asrManager] stop]; + }else if ([@"cancel" isEqualToString:call.method]) { + [[self _asrManager] cancel]; + } else{ + result(FlutterMethodNotImplemented); + } +} +- (AsrManager*)_asrManager{ + if (!self.asrManager) { + self.asrManager = [AsrManager initWith:^(NSString *message) { + if (self.result) { + self.result(message); + self.result = nil; + } + } failure:^(NSString *message) { + if (self.result) { + self.result([FlutterError errorWithCode:@"ASR fail" message:message details:nil]); + self.result = nil; + } + }]; + } + return self.asrManager; +} +@end diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_basic_model.dat b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_basic_model.dat new file mode 100755 index 00000000..e98ccb3a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_basic_model.dat differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_dnn_wakeup_model.dat b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_dnn_wakeup_model.dat new file mode 100644 index 00000000..f6dfb59e Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_dnn_wakeup_model.dat differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_gramm.dat b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_gramm.dat new file mode 100644 index 00000000..7eda1925 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_gramm.dat @@ -0,0 +1 @@ +%7B%0A%20%20%20%20%22version%22%3A%20%220.1%22%2C%0A%20%20%20%20%22slots%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%22name%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E5%BC%A0%E4%B8%89%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E6%9D%8E%E5%9B%9B%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E7%8E%8B%E4%BA%94%22%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22appname%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E5%BE%AE%E4%BF%A1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E7%9F%AD%E4%BF%A1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%E8%AE%A1%E7%AE%97%E5%99%A8%22%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22msgbody%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22.%2B%22%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22rules%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%22telephone.call%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%89%93%E7%BB%99%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%89%93%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%91%BC%E5%8F%AB%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%91%BC%E5%8F%AB(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E7%BB%99%3Cname%3E%E6%89%93%E7%94%B5%E8%AF%9D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%E6%89%93%E7%94%B5%E8%AF%9D%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22contacts.view%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%9F%A5%E7%9C%8B%3Cname%3E%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%9F%A5%E7%9C%8B(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%9F%A5%E7%9C%8B%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%9F%A5%E7%9C%8B(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22contacts.create%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22contacts.remove%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%88%A0%E9%99%A4%3Cname%3E%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%88%A0%E9%99%A4(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22message.view%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%9F%A5%E7%9C%8B%E6%9C%AA%E8%AF%BB%E7%9F%AD%E4%BF%A1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%9F%A5%E7%9C%8B%E6%9C%AA%E8%AF%BB%E7%9F%AD%E4%BF%A1%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22message.send%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%E5%86%85%E5%AE%B9%E6%98%AF%3Cmsgbody%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99(%E5%BC%A0%E4%B8%89%7C%E6%9D%8E%E5%9B%9B%7C%E7%8E%8B%E4%BA%94)%E5%86%85%E5%AE%B9%E6%98%AF(.%2B)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22msgbody%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22app.open%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%89%93%E5%BC%80%3Cappname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%89%93%E5%BC%80(%E5%BE%AE%E4%BF%A1%7C%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%E7%9F%AD%E4%BF%A1%7C%E8%AE%A1%E7%AE%97%E5%99%A8)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22appname%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E5%90%AF%E5%8A%A8%3Cappname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E5%90%AF%E5%8A%A8(%E5%BE%AE%E4%BF%A1%7C%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%E7%9F%AD%E4%BF%A1%7C%E8%AE%A1%E7%AE%97%E5%99%A8)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22appname%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22app.search%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E6%90%9C%E7%B4%A2%3Cappname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E6%90%9C%E7%B4%A2(%E5%BE%AE%E4%BF%A1%7C%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%E7%9F%AD%E4%BF%A1%7C%E8%AE%A1%E7%AE%97%E5%99%A8)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22appname%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22app.download%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20%22%E4%B8%8B%E8%BD%BD%3Cappname%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pattern%22%3A%20%22%5E%E4%B8%8B%E8%BD%BD(%E5%BE%AE%E4%BF%A1%7C%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%E7%9F%AD%E4%BF%A1%7C%E8%AE%A1%E7%AE%97%E5%99%A8)%24%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22groups%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22appname%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22grammar%22%3A%20%22%3Cname%3E%20%3D%20%E5%BC%A0%E4%B8%89%7C%20%5Cn%E6%9D%8E%E5%9B%9B%7C%20%5Cn%E7%8E%8B%E4%BA%94%3B%5Cn%3Cappname%3E%20%3D%20%E5%BE%AE%E4%BF%A1%7C%20%5Cn%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%7C%20%5Cn%E7%9F%AD%E4%BF%A1%7C%20%5Cn%E8%AE%A1%E7%AE%97%E5%99%A8%3B%5Cn%3Cmsgbody%3E%20%3D%20%E8%AF%8D%E6%9D%A1%E9%BB%98%E8%AE%A4%E5%80%BC%3B%5Cn%3Cauto_create_node%3E%20%3D%20%E6%9F%A5%E7%9C%8B%E6%9C%AA%E8%AF%BB%E7%9F%AD%E4%BF%A1%3B%5Cn%3C_wakeup%3E%20%3D%20%E5%94%A4%E9%86%92%E8%AF%8D%E5%8D%A0%E4%BD%8D%E7%AC%A6%3B%5Cn%5Cn%5Cn_SCENE_ID_%200%5Cn%5Cn(%20%3Cauto_create_node%3E%20)%5Cn%5Cn(%20%3C_wakeup%3E%3Cauto_create_node%3E%20)%5Cn%5Cn(%20%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99%3Cname%3E%20)%5Cn(%20%E6%89%93%E7%BB%99%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%89%93%E7%BB%99%3Cname%3E%20)%5Cn(%20%E5%91%BC%E5%8F%AB%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E5%91%BC%E5%8F%AB%3Cname%3E%20)%5Cn(%20%E7%BB%99%3Cname%3E%E6%89%93%E7%94%B5%E8%AF%9D%20)%5Cn(%20%3C_wakeup%3E%E7%BB%99%3Cname%3E%E6%89%93%E7%94%B5%E8%AF%9D%20)%5Cn(%20%E6%9F%A5%E7%9C%8B%3Cname%3E%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%20)%5Cn(%20%3C_wakeup%3E%E6%9F%A5%E7%9C%8B%3Cname%3E%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%20)%5Cn(%20%E6%9F%A5%E7%9C%8B%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%9F%A5%E7%9C%8B%3Cname%3E%20)%5Cn(%20%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA%3Cname%3E%20)%5Cn(%20%E5%88%A0%E9%99%A4%3Cname%3E%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%20)%5Cn(%20%3C_wakeup%3E%E5%88%A0%E9%99%A4%3Cname%3E%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%20)%5Cn(%20%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%20)%5Cn(%20%3C_wakeup%3E%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%20)%5Cn(%20%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%E5%86%85%E5%AE%B9%E6%98%AF%3Cmsgbody%3E%20)%5Cn(%20%3C_wakeup%3E%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%E5%86%85%E5%AE%B9%E6%98%AF%3Cmsgbody%3E%20)%5Cn(%20%E6%89%93%E5%BC%80%3Cappname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%89%93%E5%BC%80%3Cappname%3E%20)%5Cn(%20%E5%90%AF%E5%8A%A8%3Cappname%3E%20)%5Cn(%20%3C_wakeup%3E%E5%90%AF%E5%8A%A8%3Cappname%3E%20)%5Cn(%20%E6%90%9C%E7%B4%A2%3Cappname%3E%20)%5Cn(%20%3C_wakeup%3E%E6%90%9C%E7%B4%A2%3Cappname%3E%20)%5Cn(%20%E4%B8%8B%E8%BD%BD%3Cappname%3E%20)%5Cn(%20%3C_wakeup%3E%E4%B8%8B%E8%BD%BD%3Cappname%3E%20)%5Cn%22%2C%0A%20%20%20%20%22origin_slots%22%3A%20%22name%20%3D%20%E5%BC%A0%E4%B8%89%2C%20%E6%9D%8E%E5%9B%9B%2C%20%E7%8E%8B%E4%BA%94%5Cnappname%20%3D%20%E5%BE%AE%E4%BF%A1%2C%20%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE%2C%20%E7%9F%AD%E4%BF%A1%2C%20%E8%AE%A1%E7%AE%97%E5%99%A8%5Cnmsgbody%20%3D%20*%22%2C%0A%20%20%20%20%22origin_rules%22%3A%20%22telephone.call%20%20%20%20%20%3D%20%E6%89%93%E7%94%B5%E8%AF%9D%E7%BB%99%3Cname%3E%2C%20%E6%89%93%E7%BB%99%3Cname%3E%2C%20%E5%91%BC%E5%8F%AB%3Cname%3E%2C%E7%BB%99%3Cname%3E%E6%89%93%E7%94%B5%E8%AF%9D%5Cncontacts.view%20%20%20%20%20%3D%20%E6%9F%A5%E7%9C%8B%3Cname%3E%E7%9A%84%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%2C%20%E6%9F%A5%E7%9C%8B%3Cname%3E%5Cncontacts.create%20%20%3D%20%E6%96%B0%E5%BB%BA%E8%81%94%E7%B3%BB%E4%BA%BA%3Cname%3E%5Cncontacts.remove%3D%20%E5%88%A0%E9%99%A4%3Cname%3E%E7%9A%84%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F%5Cnmessage.view%20%20%20%20%20%3D%20%E6%9F%A5%E7%9C%8B%E6%9C%AA%E8%AF%BB%E7%9F%AD%E4%BF%A1%5Cnmessage.send%20%20%20%20%3D%20%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%2C%20%E5%8F%91%E7%9F%AD%E4%BF%A1%E7%BB%99%3Cname%3E%E5%86%85%E5%AE%B9%E6%98%AF%3Cmsgbody%3E%5Cnapp.open%20%20%20%20%20%20%20%20%20%20%20%20%3D%20%E6%89%93%E5%BC%80%3Cappname%3E%2C%20%E5%90%AF%E5%8A%A8%3Cappname%3E%5Cnapp.search%20%20%20%20%20%20%20%20%20%3D%20%E6%90%9C%E7%B4%A2%3Cappname%3E%5Cnapp.download%20%20%20%20%3D%20%E4%B8%8B%E8%BD%BD%3Cappname%3E%22%0A%7D \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_mfe_cmvn.dat b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_mfe_cmvn.dat new file mode 100644 index 00000000..342b96ff --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_mfe_cmvn.dat @@ -0,0 +1,54 @@ +vec 26 +1.485246e+01 +1.579741e+01 +1.663629e+01 +1.698390e+01 +1.708107e+01 +1.745045e+01 +1.752832e+01 +1.758490e+01 +1.746364e+01 +1.743286e+01 +1.744198e+01 +1.735617e+01 +1.735499e+01 +1.730315e+01 +1.726894e+01 +1.729055e+01 +1.728198e+01 +1.718504e+01 +1.712417e+01 +1.710584e+01 +1.715915e+01 +1.723995e+01 +1.730050e+01 +1.728485e+01 +1.728487e+01 +1.729697e+01 +vec 26 +2.764144e-01 +2.703758e-01 +2.584008e-01 +2.514187e-01 +2.496835e-01 +2.436650e-01 +2.391809e-01 +2.393867e-01 +2.416821e-01 +2.443231e-01 +2.473226e-01 +2.507182e-01 +2.540205e-01 +2.566869e-01 +2.590701e-01 +2.611003e-01 +2.630226e-01 +2.658522e-01 +2.699072e-01 +2.724641e-01 +2.723619e-01 +2.699174e-01 +2.670183e-01 +2.660550e-01 +2.658852e-01 +2.637595e-01 diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_mfe_dnn.dat b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_mfe_dnn.dat new file mode 100644 index 00000000..956531a7 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_mfe_dnn.dat differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_wakeup_words.dat b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_wakeup_words.dat new file mode 100644 index 00000000..06ef0677 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_easr_wakeup_words.dat @@ -0,0 +1 @@ +fAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZBfAEYGGtEYXgB_ZB \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_license.dat b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_license.dat new file mode 100644 index 00000000..95c77fbe --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/bds_license.dat @@ -0,0 +1 @@ +a1a0feb5512e354f3c9a4cc46b89ee3a40db91a2e3d407392583129b9e5d53ef0dc99b108e1c0402283092cdfe62e848d1e7e885516582d5a6bab042289983862caf46fad017cac0e52d073c562f7f122f90c8cba0cfe29a7815d6922e131b9f5fce7fb5dc478b1070719a687a176a5e63bb1c674f899cdb99a608b6f7d098f054bafd3c9ebe2edf612bb536f28b9a771db519e0843155b388f69afa91be62472cf1005339868d5e1af244a137707aa588af1ba03d908a69320d449e38329dede1a0770e6a725a04d4190545b120a9902340c1255c73a6ec08ad731c3f601c4e2efbeccd660c53497009522a94566a14da63bdc6fab1e51e25a7fc6f403bbf39 \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/temp_license_2018-02-24.dat b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/temp_license_2018-02-24.dat new file mode 100644 index 00000000..898a123f --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientEASRResources/temp_license_2018-02-24.dat @@ -0,0 +1 @@ +1f8aab4589493657ba730e4f32722efa6596910f0ccad102f1b3cde4c605af767dbf2e92a55242cc493f2977278a6716448f17603a00b0a66b44f4b96ad1a1d299e4316acdc58ad5434a01026db3b7afed69f4fb8274488148303cd059bcfe37a42713a42bfa09733518024516f4f35c7d46e2c595de3ec85396e430c831ae9354bafd3c9ebe2edf612bb536f28b9a771db519e0843155b388f69afa91be62472cf1005339868d5e1af244a137707aa588af1ba03d908a69320d449e38329dede1a0770e6a725a04d4190545b120a9902340c1255c73a6ec08ad731c3f601c4e2efbeccd660c53497009522a94566a14da63bdc6fab1e51e25a7fc6f403bbf39 \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrclosed@2x.png new file mode 100755 index 00000000..6c9fe48b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrclosed_highlight@2x.png new file mode 100755 index 00000000..ed25edfc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..7528facf Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrdialogbg@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrdialogbg@2x.png new file mode 100755 index 00000000..a2034c85 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrdialogbg@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..4a45e1f8 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..3176a272 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrleftbutton@2x.png new file mode 100755 index 00000000..0089014e Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrleftbutton_highlight@2x.png new file mode 100755 index 00000000..508efe5a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrrightbtn@2x.png new file mode 100755 index 00000000..cd1514bc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrrightbtn_highlight@2x.png new file mode 100755 index 00000000..da7b15f5 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..348406b3 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtb@2x.png new file mode 100755 index 00000000..bea135bc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtb_highlight@2x.png new file mode 100755 index 00000000..b84a2629 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtn@2x.png new file mode 100644 index 00000000..30954024 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtn_highlight@2x.png new file mode 100755 index 00000000..e06edf33 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/themeDesc.plist new file mode 100644 index 00000000..70ce0b01 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkBlue.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrclosed@2x.png new file mode 100755 index 00000000..6c9fe48b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrclosed_highlight@2x.png new file mode 100755 index 00000000..ed25edfc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..7528facf Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrdialogbg@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrdialogbg@2x.png new file mode 100644 index 00000000..a2034c85 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrdialogbg@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..4a45e1f8 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..3176a272 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrleftbutton@2x.png new file mode 100644 index 00000000..0089014e Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrleftbutton_highlight@2x.png new file mode 100644 index 00000000..508efe5a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrrightbtn@2x.png new file mode 100644 index 00000000..930ad27a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrrightbtn_highlight@2x.png new file mode 100644 index 00000000..17c495d0 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..348406b3 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtb@2x.png new file mode 100644 index 00000000..bea135bc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtb_highlight@2x.png new file mode 100644 index 00000000..b84a2629 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtn@2x.png new file mode 100644 index 00000000..b3dc3760 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtn_highlight@2x.png new file mode 100644 index 00000000..3bcb1b12 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/themeDesc.plist new file mode 100644 index 00000000..b62ef456 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkGreen.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrclosed@2x.png new file mode 100755 index 00000000..6c9fe48b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrclosed_highlight@2x.png new file mode 100755 index 00000000..ed25edfc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..7528facf Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrdialogbg@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrdialogbg@2x.png new file mode 100644 index 00000000..a2034c85 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrdialogbg@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..4a45e1f8 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..3176a272 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrleftbutton@2x.png new file mode 100644 index 00000000..0089014e Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrleftbutton_highlight@2x.png new file mode 100644 index 00000000..508efe5a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrrightbtn@2x.png new file mode 100644 index 00000000..87a08732 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrrightbtn_highlight@2x.png new file mode 100644 index 00000000..ed027afa Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..348406b3 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtb@2x.png new file mode 100644 index 00000000..bea135bc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtb_highlight@2x.png new file mode 100644 index 00000000..b84a2629 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtn@2x.png new file mode 100644 index 00000000..94bdb2f0 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtn_highlight@2x.png new file mode 100644 index 00000000..6a3032df Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/themeDesc.plist new file mode 100644 index 00000000..774ca117 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkOrange.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrclosed@2x.png new file mode 100755 index 00000000..6c9fe48b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrclosed_highlight@2x.png new file mode 100755 index 00000000..ed25edfc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..7528facf Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrdialogbg@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrdialogbg@2x.png new file mode 100644 index 00000000..a2034c85 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrdialogbg@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..4a45e1f8 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..3176a272 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrleftbutton@2x.png new file mode 100644 index 00000000..0089014e Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrleftbutton_highlight@2x.png new file mode 100644 index 00000000..508efe5a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrrightbtn@2x.png new file mode 100644 index 00000000..d658a697 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrrightbtn_highlight@2x.png new file mode 100644 index 00000000..a27730ee Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..348406b3 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtb@2x.png new file mode 100644 index 00000000..bea135bc Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtb_highlight@2x.png new file mode 100644 index 00000000..b84a2629 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtn@2x.png new file mode 100644 index 00000000..ac5d6806 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtn_highlight@2x.png new file mode 100644 index 00000000..145eadb7 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/themeDesc.plist new file mode 100644 index 00000000..b28d3d3c Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/darkRed.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/animation@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/animation@2x.png new file mode 100644 index 00000000..3f1e445f Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/animation@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/animation@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/animation@3x.png new file mode 100644 index 00000000..0cc1bb85 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/animation@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/application@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/application@2x.png new file mode 100644 index 00000000..45e8f340 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/application@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/application@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/application@3x.png new file mode 100644 index 00000000..5f20f95b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/application@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed@2x.png new file mode 100644 index 00000000..8d2fd8af Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed@3x.png new file mode 100644 index 00000000..2d3f355d Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed_highlight@2x.png new file mode 100644 index 00000000..2a923d80 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed_highlight@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed_highlight@3x.png new file mode 100644 index 00000000..3ffd07d0 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrclosed_highlight@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..e10537a9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrerror@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrerror@2x.png new file mode 100644 index 00000000..a6d279f5 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrerror@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrerror@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrerror@3x.png new file mode 100644 index 00000000..ccd5cf2c Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrerror@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..59070293 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..6209a8ee Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrleftbutton@2x.png new file mode 100755 index 00000000..918adf34 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrleftbutton_highlight@2x.png new file mode 100755 index 00000000..0f255ad6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrnoconnection@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrnoconnection@2x.png new file mode 100644 index 00000000..d65abdaa Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrnoconnection@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrnoconnection@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrnoconnection@3x.png new file mode 100644 index 00000000..7185af30 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrnoconnection@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrretry@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrretry@2x.png new file mode 100644 index 00000000..12d97d43 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrretry@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrretry_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrretry_highlight@2x.png new file mode 100644 index 00000000..fac70231 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrretry_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrrightbtn@2x.png new file mode 100755 index 00000000..80949934 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrrightbtn_highlight@2x.png new file mode 100755 index 00000000..cff182b0 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..07c06e1b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtb@2x.png new file mode 100644 index 00000000..066fe960 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtb_highlight@2x.png new file mode 100755 index 00000000..fac80bcb Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtn@2x.png new file mode 100644 index 00000000..f54eb161 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtn_highlight@2x.png new file mode 100644 index 00000000..232aa962 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/calendar@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/calendar@2x.png new file mode 100644 index 00000000..b0795fd4 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/calendar@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/calendar@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/calendar@3x.png new file mode 100644 index 00000000..046c9595 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/calendar@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/dividing_line@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/dividing_line@2x.png new file mode 100644 index 00000000..62170d0c Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/dividing_line@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/dividing_line@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/dividing_line@3x.png new file mode 100644 index 00000000..62170d0c Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/dividing_line@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/fiction@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/fiction@2x.png new file mode 100644 index 00000000..3be3aefd Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/fiction@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/fiction@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/fiction@3x.png new file mode 100644 index 00000000..20974540 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/fiction@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/film@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/film@2x.png new file mode 100644 index 00000000..78b52c43 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/film@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/film@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/film@3x.png new file mode 100644 index 00000000..074d4724 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/film@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/game@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/game@2x.png new file mode 100644 index 00000000..9934aa67 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/game@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/game@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/game@3x.png new file mode 100644 index 00000000..7c28f381 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/game@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/health@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/health@2x.png new file mode 100644 index 00000000..2b396c4b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/health@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/health@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/health@3x.png new file mode 100644 index 00000000..8cf6f27f Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/health@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/help@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/help@2x.png new file mode 100644 index 00000000..451a83ff Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/help@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/help@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/help@3x.png new file mode 100644 index 00000000..c57ddf6b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/help@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/life_service@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/life_service@2x.png new file mode 100644 index 00000000..6451ebeb Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/life_service@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/life_service@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/life_service@3x.png new file mode 100644 index 00000000..52a3178f Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/life_service@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/mother_and_baby@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/mother_and_baby@2x.png new file mode 100644 index 00000000..ad7edfb2 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/mother_and_baby@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/mother_and_baby@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/mother_and_baby@3x.png new file mode 100644 index 00000000..e52f760a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/mother_and_baby@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/music@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/music@2x.png new file mode 100644 index 00000000..57600c6d Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/music@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/music@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/music@3x.png new file mode 100644 index 00000000..6462f433 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/music@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/praxis@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/praxis@2x.png new file mode 100644 index 00000000..f790e902 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/praxis@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/praxis@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/praxis@3x.png new file mode 100644 index 00000000..0dd3e6c9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/praxis@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/stock@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/stock@2x.png new file mode 100644 index 00000000..40782ad3 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/stock@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/stock@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/stock@3x.png new file mode 100644 index 00000000..896e6931 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/stock@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/themeDesc.plist new file mode 100644 index 00000000..78f9e210 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/tv_drama@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/tv_drama@2x.png new file mode 100644 index 00000000..58884663 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/tv_drama@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/tv_drama@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/tv_drama@3x.png new file mode 100644 index 00000000..506d2030 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/tv_drama@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/whether@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/whether@2x.png new file mode 100644 index 00000000..355e969b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/whether@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/whether@3x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/whether@3x.png new file mode 100644 index 00000000..04e19138 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultFullScreenTheme.bundle/whether@3x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrclosed@2x.png new file mode 100644 index 00000000..6a1ba2a6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrclosed_highlight@2x.png new file mode 100644 index 00000000..f3437b90 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..e10537a9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..59070293 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..6209a8ee Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrleftbutton@2x.png new file mode 100755 index 00000000..918adf34 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrleftbutton_highlight@2x.png new file mode 100755 index 00000000..0f255ad6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrrightbtn@2x.png new file mode 100755 index 00000000..80949934 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrrightbtn_highlight@2x.png new file mode 100755 index 00000000..cff182b0 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..dd99a6c6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtb@2x.png new file mode 100755 index 00000000..de238695 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtb_highlight@2x.png new file mode 100755 index 00000000..fac80bcb Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtn@2x.png new file mode 100755 index 00000000..9594c589 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtn_highlight@2x.png new file mode 100755 index 00000000..cb701f33 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/themeDesc.plist new file mode 100644 index 00000000..6faec668 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/defaultTheme.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrclosed@2x.png new file mode 100755 index 00000000..f92a50b6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrclosed_highlight@2x.png new file mode 100755 index 00000000..f3437b90 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..e10537a9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrdialogbg@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrdialogbg@2x.png new file mode 100755 index 00000000..fcac705a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrdialogbg@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..59070293 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..6209a8ee Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrleftbutton@2x.png new file mode 100755 index 00000000..918adf34 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrleftbutton_highlight@2x.png new file mode 100755 index 00000000..0f255ad6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrrightbtn@2x.png new file mode 100755 index 00000000..80949934 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrrightbtn_highlight@2x.png new file mode 100755 index 00000000..cff182b0 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..dd99a6c6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtb@2x.png new file mode 100755 index 00000000..de238695 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtb_highlight@2x.png new file mode 100755 index 00000000..fac80bcb Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtn@2x.png new file mode 100755 index 00000000..9594c589 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtn_highlight@2x.png new file mode 100755 index 00000000..cb701f33 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/themeDesc.plist new file mode 100644 index 00000000..6faec668 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightBlue.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrclosed@2x.png new file mode 100755 index 00000000..6a1ba2a6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrclosed_highlight@2x.png new file mode 100755 index 00000000..f3437b90 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..e10537a9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrdialogbg@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrdialogbg@2x.png new file mode 100755 index 00000000..fcac705a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrdialogbg@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..59070293 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..6209a8ee Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrleftbutton@2x.png new file mode 100755 index 00000000..918adf34 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrleftbutton_highlight@2x.png new file mode 100755 index 00000000..0f255ad6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrrightbtn@2x.png new file mode 100755 index 00000000..0cbf386a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrrightbtn_highlight@2x.png new file mode 100755 index 00000000..73ae5468 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..dd99a6c6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtb@2x.png new file mode 100755 index 00000000..de238695 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtb_highlight@2x.png new file mode 100755 index 00000000..fac80bcb Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtn@2x.png new file mode 100755 index 00000000..c8e1c4d5 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtn_highlight@2x.png new file mode 100755 index 00000000..521a62e9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/themeDesc.plist new file mode 100644 index 00000000..b1be0f07 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightGreen.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrclosed@2x.png new file mode 100755 index 00000000..6a1ba2a6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrclosed_highlight@2x.png new file mode 100755 index 00000000..f3437b90 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..e10537a9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrdialogbg@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrdialogbg@2x.png new file mode 100755 index 00000000..fcac705a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrdialogbg@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..59070293 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..6209a8ee Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrleftbutton@2x.png new file mode 100755 index 00000000..918adf34 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrleftbutton_highlight@2x.png new file mode 100755 index 00000000..0f255ad6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrrightbtn@2x.png new file mode 100755 index 00000000..7661ca8a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrrightbtn_highlight@2x.png new file mode 100755 index 00000000..772a9a42 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..dd99a6c6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtb@2x.png new file mode 100755 index 00000000..de238695 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtb_highlight@2x.png new file mode 100755 index 00000000..fac80bcb Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtn@2x.png new file mode 100644 index 00000000..cc9d0f27 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtn_highlight@2x.png new file mode 100755 index 00000000..50a8452e Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/themeDesc.plist new file mode 100644 index 00000000..e76a6e5e Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightOrange.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrclosed@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrclosed@2x.png new file mode 100755 index 00000000..6a1ba2a6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrclosed@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrclosed_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrclosed_highlight@2x.png new file mode 100755 index 00000000..f3437b90 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrclosed_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrdialoganmition_mask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrdialoganmition_mask@2x.png new file mode 100644 index 00000000..e10537a9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrdialoganmition_mask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrdialogbg@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrdialogbg@2x.png new file mode 100755 index 00000000..fcac705a Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrdialogbg@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrhelp@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrhelp@2x.png new file mode 100755 index 00000000..59070293 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrhelp@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrhelp_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrhelp_highlight@2x.png new file mode 100755 index 00000000..6209a8ee Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrhelp_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrleftbutton@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrleftbutton@2x.png new file mode 100755 index 00000000..918adf34 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrleftbutton@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrleftbutton_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrleftbutton_highlight@2x.png new file mode 100755 index 00000000..0f255ad6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrleftbutton_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrrightbtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrrightbtn@2x.png new file mode 100755 index 00000000..299719be Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrrightbtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrrightbtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrrightbtn_highlight@2x.png new file mode 100755 index 00000000..c712bc39 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrrightbtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrtextmask@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrtextmask@2x.png new file mode 100644 index 00000000..dd99a6c6 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrtextmask@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtb@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtb@2x.png new file mode 100755 index 00000000..de238695 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtb@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtb_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtb_highlight@2x.png new file mode 100755 index 00000000..fac80bcb Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtb_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtn@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtn@2x.png new file mode 100755 index 00000000..5d03e684 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtn@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtn_highlight@2x.png b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtn_highlight@2x.png new file mode 100755 index 00000000..d9aca904 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/bdvrwholebtn_highlight@2x.png differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/themeDesc.plist b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/themeDesc.plist new file mode 100644 index 00000000..7fd33c76 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Theme/lightRed.bundle/themeDesc.plist differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_cancel.caf b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_cancel.caf new file mode 100644 index 00000000..e2f260d9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_cancel.caf differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_end.caf b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_end.caf new file mode 100755 index 00000000..6e9279b4 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_end.caf differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_fail.caf b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_fail.caf new file mode 100644 index 00000000..ed5ce83b Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_fail.caf differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_start.caf b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_start.caf new file mode 100755 index 00000000..ef6e5eb9 Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_start.caf differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_success.caf b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_success.caf new file mode 100644 index 00000000..36cbd89c Binary files /dev/null and b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/BDSClientResources/Tone/record_success.caf differ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSASRDefines.h b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSASRDefines.h new file mode 100644 index 00000000..715d2a65 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSASRDefines.h @@ -0,0 +1,174 @@ +// +// BDSASRDefines.h +// BDSpeechClient +// +// Created by baidu on 16/6/6. +// Copyright © 2016年 baidu. All rights reserved. +// + +#ifndef BDSASRDefines_h +#define BDSASRDefines_h + +#import + +#pragma mark - ASR Delegate +@protocol BDSClientASRDelegate +- (void)VoiceRecognitionClientWorkStatus:(int)workStatus obj:(id)aObj; // TBDVoiceRecognitionClientWorkStatus +@end + +#pragma mark - ASR Command +extern NSString* BDS_ASR_CMD_START; +extern NSString* BDS_ASR_CMD_STOP; +extern NSString* BDS_ASR_CMD_CANCEL; +extern NSString* BDS_ASR_CMD_LOAD_ENGINE; +extern NSString* BDS_ASR_CMD_UNLOAD_ENGINE; + +#pragma mark - 设定采样率 +typedef enum TBDVoiceRecognitionRecordSampleRateFlags +{ + EVoiceRecognitionRecordSampleRateAuto = 0, + EVoiceRecognitionRecordSampleRate8K, + EVoiceRecognitionRecordSampleRate16K, +} TBDVoiceRecognitionRecordSampleRateFlags; + +#pragma mark - 设置识别语言 +typedef enum TBDVoiceRecognitionLanguage +{ + EVoiceRecognitionLanguageChinese = 0, + EVoiceRecognitionLanguageCantonese, + EVoiceRecognitionLanguageEnglish, + EVoiceRecognitionLanguageSichuanDialect, +} TBDVoiceRecognitionLanguage; + +#pragma mark - 提示音类型 +typedef enum TBDVoiceRecognitionPlayTones +{ + EVRPlayToneTypeStart = (1 << 0), // 开始识别提示音, record_start.caf (会影响端点检测准确率,建议不要与端点检测同时开启) + EVRPlayToneTypeEnd = (1 << 1), // 结束识别提示音, record_end.caf + EVRPlayToneTypeSuccess = (1 << 2), // 识别成功提示音, record_success.caf + EVRPlayToneTypeFail = (1 << 3), // 识别失败提示音, record_fail.caf + EVRPlayToneTypeCancel = (1 << 4), // 取消识别提示音, record_cancel.caf + EVRPlayToneNone = 0, // 关闭提示音 + EVRPlayToneAll = (EVRPlayToneTypeStart | EVRPlayToneTypeEnd | EVRPlayToneTypeSuccess | EVRPlayToneTypeFail | EVRPlayToneTypeCancel) // 打开所有提示音 +} TBDVoiceRecognitionPlayTones; + +#pragma mark - 语音识别策略 +typedef enum TBDVoiceRecognitionStrategy +{ + EVR_STRATEGY_ONLINE = 0, // 在线识别 + EVR_STRATEGY_BOTH = 4, // 并行模式 +} TBDVoiceRecognitionStrategy; + +#pragma mark - 语音识别离线引擎类型 +typedef enum TBDVoiceRecognitionOfflineEngineType +{ + EVR_OFFLINE_ENGINE_INPUT = 0, // 离线引擎输入法模式 + EVR_OFFLINE_ENGINE_GRAMMER = 2, // 离线引擎语法模式 +} TBDVoiceRecognitionOfflineEngineType; + +#pragma mark - 语音识别类型 +typedef enum TBDVoiceRecognitionProperty +{ + EVoiceRecognitionPropertyMusic = 10001, // 音乐 + EVoiceRecognitionPropertyVideo = 10002, // 视频 + EVoiceRecognitionPropertyApp = 10003, // 应用 + EVoiceRecognitionPropertyWeb = 10004, // web + EVoiceRecognitionPropertySearch = 10005, // 热词 + EVoiceRecognitionPropertyEShopping = 10006, // 电商&购物 + EVoiceRecognitionPropertyHealth = 10007, // 健康&母婴 + EVoiceRecognitionPropertyCall = 10008, // 打电话 + EVoiceRecognitionPropertyMedicalCare = 10052, // 医疗 + EVoiceRecognitionPropertyCar = 10053, // 汽车 + EVoiceRecognitionPropertyCatering = 10054, // 娱乐餐饮 + EVoiceRecognitionPropertyFinanceAndEconomics = 10055, // 财经 + EVoiceRecognitionPropertyGame = 10056, // 游戏 + EVoiceRecognitionPropertyCookbook = 10057, // 菜谱 + EVoiceRecognitionPropertyAssistant = 10058, // 助手 + EVoiceRecognitionPropertyRecharge = 10059, // 话费充值 + EVoiceRecognitionPropertyMap = 10060, // 地图 + EVoiceRecognitionPropertyInput = 20000, // 输入 +} TBDVoiceRecognitionProperty; + +#pragma mark - 语音识别状态 +typedef enum TBDVoiceRecognitionClientWorkStatus +{ + EVoiceRecognitionClientWorkStatusStartWorkIng, // 识别工作开始,开始采集及处理数据 + EVoiceRecognitionClientWorkStatusStart, // 检测到用户开始说话 + EVoiceRecognitionClientWorkStatusEnd, // 本地声音采集结束,等待识别结果返回并结束录音 + EVoiceRecognitionClientWorkStatusNewRecordData, // 录音数据回调 + EVoiceRecognitionClientWorkStatusFlushData, // 连续上屏 + EVoiceRecognitionClientWorkStatusFinish, // 语音识别功能完成,服务器返回正确结果 + EVoiceRecognitionClientWorkStatusMeterLevel, // 当前音量回调 + EVoiceRecognitionClientWorkStatusCancel, // 用户取消 + EVoiceRecognitionClientWorkStatusError, // 发生错误 + /* 离线引擎状态 */ + EVoiceRecognitionClientWorkStatusLoaded, // 离线引擎加载完成 + EVoiceRecognitionClientWorkStatusUnLoaded, // 离线引擎卸载完成 + /* CHUNK状态 */ + EVoiceRecognitionClientWorkStatusChunkThirdData, // CHUNK: 识别结果中的第三方数据 + EVoiceRecognitionClientWorkStatusChunkNlu, // CHUNK: 识别结果中的语义结果 + EVoiceRecognitionClientWorkStatusChunkEnd, // CHUNK: 识别过程结束 + /* LOG */ + EVoiceRecognitionClientWorkStatusFeedback, // Feedback: 识别过程反馈的打点数据 + /* Only for iOS */ + EVoiceRecognitionClientWorkStatusRecorderEnd, // 录音机关闭,页面跳转需检测此时间,规避状态条 (iOS) + /* LONG SPEECH END */ + EVoiceRecognitionClientWorkStatusLongSpeechEnd // 长语音结束状态 +} TBDVoiceRecognitionClientWorkStatus; + +#pragma mark - 语音识别错误通知状态分类 +typedef enum TVoiceRecognitionClientErrorDomain +{ + EVRClientErrorDomainRecord = 10, // 录音设备出错 + EVRClientErrorDomainVAD = 20, // 语音数据处理过程出错 + EVRClientErrorDomainOnline = 30, // 在线识别引擎出错 + EVRClientErrorDomainLocalNetwork = 31, // 本地网络联接出错 + EVRClientErrorDomainHTTP = 32, // HTTP协议错误 + EVRClientErrorDomainServer = 33, // 服务器返回错误 + EVRClientErrorDomainOffline = 34, // 离线引擎返回错误 + EVRClientErrorDomainCommom = 40, // 其他错误 +} TVoiceRecognitionClientErrorDomain; + +#pragma mark - 语音识别错误通知状态 +typedef enum TVoiceRecognitionClientErrorCode +{ + EVRClientErrorCodeRecoderException = (EVRClientErrorDomainRecord << 16) | (0x0000FFFF & 1), // 录音设备异常 + EVRClientErrorCodeRecoderNoPermission = (EVRClientErrorDomainRecord << 16) | (0x0000FFFF & 2), // 无录音权限 + EVRClientErrorCodeRecoderUnAvailable = (EVRClientErrorDomainRecord << 16) | (0x0000FFFF & 3), // 录音设备不可用 + EVRClientErrorCodeInterruption = (EVRClientErrorDomainRecord << 16) | (0x0000FFFF & 4), // 录音中断 + + EVRClientErrorCodeVADException = (EVRClientErrorDomainVAD << 16) | (0x0000FFFF & 1), // 前端库异常 + EVRClientErrorCodeNoSpeech = (EVRClientErrorDomainVAD << 16) | (0x0000FFFF & 2), // 用户未说话 + EVRClientErrorCodeShort = (EVRClientErrorDomainVAD << 16) | (0x0000FFFF & 3), // 用户说话声音太短 + + EVRClientErrorCodeDecoderExceptioin = (EVRClientErrorDomainOnline << 16) | (0x0000FFFF & 1), // 在线识别引擎异常 + EVRClientErrorCodeDecoderNetworkUnavailable = (EVRClientErrorDomainOnline << 16) | (0x0000FFFF & 2), // 网络不可用 + EVRClientErrorCodeDecoderTokenFailed = (EVRClientErrorDomainOnline << 16) | (0x0000FFFF & 3), // 获取token失败 + EVRClientErrorCodeDecoderResolveUrlFailed = (EVRClientErrorDomainOnline << 16) | (0x0000FFFF & 4), // 解析url失败 + EVRClientErrorCodeLocalTimeout = (EVRClientErrorDomainLocalNetwork << 16) | (0x0000FFFF & 1), // 请求超时 + + EVRClientErrorCodeServerParamError = (EVRClientErrorDomainServer << 16) | (0x0000FFFF & -3001), // 协议参数错误 + EVRClientErrorCodeServerRecognError = (EVRClientErrorDomainServer << 16) | (0x0000FFFF & -3002), // 识别过程出错 + EVRClientErrorCodeServerNoFindResult = (EVRClientErrorDomainServer << 16) | (0x0000FFFF & -3003), // 没有找到匹配结果 + EVRClientErrorCodeServerAppNameUnknownError = (EVRClientErrorDomainServer << 16) | (0x0000FFFF & -3004), // AppnameUnkown错误 + EVRClientErrorCodeServerSpeechQualityProblem = (EVRClientErrorDomainServer << 16) | (0x0000FFFF & -3005), // 声音不符合识别要求 + EVRClientErrorCodeServerSpeechTooLong = (EVRClientErrorDomainServer << 16) | (0x0000FFFF & -3006), // 语音过长 + + EVRClientErrorCodeCommonBusy = (EVRClientErrorDomainCommom << 16) | (0x0000FFFF & 1), // 识别器忙 + EVRClientErrorCodeCommonPropertyListInvalid = (EVRClientErrorDomainCommom << 16) | (0x0000FFFF & 2), // 垂类设置有误 + EVRClientErrorCodeCommonEnqueueError = (EVRClientErrorDomainCommom << 16) | (0x0000FFFF & 3) // 语音数据enqueue失败 +} TVoiceRecognitionClientErrorCode; + +#pragma mark - 调试日志级别 +typedef enum TBDVoiceRecognitionDebugLogLevel +{ + EVRDebugLogLevelOff = 0, + EVRDebugLogLevelFatal = 1, + EVRDebugLogLevelError = 2, + EVRDebugLogLevelWarning = 3, + EVRDebugLogLevelInformation = 4, + EVRDebugLogLevelDebug = 5, + EVRDebugLogLevelTrace = 6 +} TBDVoiceRecognitionDebugLogLevel; + +#endif /* BDSASRDefines_h */ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSASRParameters.h b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSASRParameters.h new file mode 100644 index 00000000..94a42ee6 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSASRParameters.h @@ -0,0 +1,473 @@ +// +// BDSASRParameters.h +// BDSpeechClient +// +// Created by baidu on 16/6/6. +// Copyright © 2016年 baidu. All rights reserved. +// + +#ifndef BDSASRParameters_h +#define BDSASRParameters_h + +#import + +#pragma mark - 开发者身份验证 + +/* + * BDS_ASR_API_SECRET_KEYS + * Value explanation: 设置API_KEY and SECRET_KEY + * Value type: NSArray + * Default value: - + */ +extern NSString* BDS_ASR_API_SECRET_KEYS; + + +#pragma mark - 识别器参数配置 + +/* + * BDS_ASR_SAMPLE_RATE + * Value explanation: 设置录音采样率,自动模式根据当前网络情况自行调整 + * Value type: TVoiceRecognitionRecordSampleRateFlags + * Default value: @(EVoiceRecognitionRecordSampleRate16K) + */ +extern NSString* BDS_ASR_SAMPLE_RATE; + +/* + * BDS_ASR_STRATEGY + * Value explanation: 语音识别策略 + * Value type: TBDVoiceRecognitionStrategy + * Default value: @(EVR_STRATEGY_ONLINE) + */ +extern NSString* BDS_ASR_STRATEGY; + +/* + * BDS_ASR_CITY_ID + * Value explanation: 设置城市ID,仅对地图识别类型有效 + * Value type: NSInteger + * Default value: @(1)(全国) + */ +extern NSString* BDS_ASR_CITY_ID; + +/* + * BDS_ASR_PROPERTY_LIST + * Value explanation: 设置识别类型列表,输入法不可与其他类型复合 + * Value type: NSArray[TBDVoiceRecognitionProperty] + * Default value: @[@(EVoiceRecognitionPropertySearch)] + */ +extern NSString* BDS_ASR_PROPERTY_LIST; + +/* + * BDS_ASR_LANGUAGE + * Value explanation: 设置识别语言 + * Value type: TVoiceRecognitionLanguage + * Default value: @(EVoiceRecognitionLanguageChinese) + */ +extern NSString* BDS_ASR_LANGUAGE; + +/* + * BDS_ASR_ENABLE_NLU + * Value explanation: 开启语义解析,将返回包含语义的json串 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_ENABLE_NLU; + +/* + * BDS_ASR_DISABLE_PUNCTUATION + * Value explanation: 关闭输出标点 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_DISABLE_PUNCTUATION; + +/* + * BDS_ASR_ENABLE_CONTACTS + * Value explanation: 开启通讯录识别功能,将优先返回通讯录识别结果,需事先用uploader上传通讯录 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_ENABLE_CONTACTS; + +/* + * BDS_ASR_ENABLE_LOCAL_VAD + * Value explanation: 是否需要对录音数据进行端点检测,如果关闭,请同时关闭服务端提前返回:BDS_ASR_ENABLE_EARLY_RETURN + * Value type: BOOL + * Default value: @(YES) + */ +extern NSString* BDS_ASR_ENABLE_LOCAL_VAD; + +/* + * BDS_ASR_ENABLE_MODEL_VAD + * Value explanation: 是否使用modelVAD,打开需配置资源文件参数 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_ENABLE_MODEL_VAD; + +/* + * BDS_ASR_MODEL_VAD_DAT_FILE + * Value explanation: modelVAD所需资源文件 + * Value type: NSString + * Default value: @"" + */ +extern NSString* BDS_ASR_MODEL_VAD_DAT_FILE; + +/* + * BDS_ASR_ENABLE_EARLY_RETURN + * Value explanation: 服务端开启提前返回,即允许服务端在未收到客户端发送的结束标志前提前结束识别过程 + * Value type: BOOL + * Default value: @(YES) + */ +extern NSString* BDS_ASR_ENABLE_EARLY_RETURN; + +/* + * BDS_ASR_VAD_ENABLE_LONG_PRESS + * Value explanation: 设置VAD模式为长按(特殊情况设置) + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_VAD_ENABLE_LONG_PRESS; + +/* + * BDS_ASR_MFE_DNN_DAT_FILE + * Value explanation: 设置MFE模型文件 + * Value type: string + * Default value: - + */ +extern NSString* BDS_ASR_MFE_DNN_DAT_FILE; + +/* + * BDS_ASR_MFE_CMVN_DAT_FILE + * Value explanation: 设置MFE CMVN文件路径 + * Value type: string + * Default value: - + */ +extern NSString* BDS_ASR_MFE_CMVN_DAT_FILE; + +/* + * BDS_ASR_MFE_MAX_WAIT_DURATION + * Value explanation: 设置最大等待语音时间 + * Value type: float (帧数,每帧大小为10ms) + * Default value: - + */ +extern NSString* BDS_ASR_MFE_MAX_WAIT_DURATION; + +/* + * BDS_ASR_MFE_MAX_SPEECH_PAUSE + * Value explanation: 设置切分门限 + * Value type: float (帧数,每帧大小为10ms) + * Default value: - + */ +extern NSString* BDS_ASR_MFE_MAX_SPEECH_PAUSE; + +#pragma mark - 音频文件路径(文件识别) + +/* + * BDS_ASR_AUDIO_FILE_PATH + * Value explanation: 设置音频文件路径(数据源) + * Value type: NSString + * Default value: @"" + */ +extern NSString* BDS_ASR_AUDIO_FILE_PATH; + +/* + * BDS_ASR_AUDIO_INPUT_STREAM + * Value explanation: 设置音频输入流(数据源) + * Value type: NSInputStream + * Default value: nil + */ +extern NSString* BDS_ASR_AUDIO_INPUT_STREAM; + +/* + * BDS_ASR_DISABLE_AUDIO_OPERATION + * Value explanation: Disable sdk audio operation (Set audio session disactive). + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_DISABLE_AUDIO_OPERATION; + +#pragma mark - 提示音 + +/* + * BDS_ASR_PLAY_TONE + * Value explanation: 识别提示音设置,需添加相应声音文件,可替换 + * Value type: TBDVoiceRecognitionPlayTones + * Default value: @(EVRPlayToneNone) (关闭提示音) + */ +extern NSString* BDS_ASR_PLAY_TONE; + +#pragma mark - SDK 工作队列 + +/* + * BDS_ASR_WORK_QUEUE + * Value explanation: 指定SDK工作队列 + * Value type: dispatch_queue_t + * Default value: main queue (dispatch_get_main_queue()) + * Example: dispatch_queue_create("queueLabel", DISPATCH_QUEUE_SERIAL) + */ +extern NSString* BDS_ASR_WORK_QUEUE; + +#pragma mark - 日志级别 + +/* + * BDS_ASR_DEBUG_LOG_LEVEL + * Value explanation: 指定调试日志级别 + * Value type: TBDVoiceRecognitionDebugLogLevel + * Default value: @(EVRDebugLogLevelOff) + */ +extern NSString* BDS_ASR_DEBUG_LOG_LEVEL; + +#pragma mark - Offline Engine Verify + +/* + * BDS_ASR_OFFLINE_APP_CODE + * Value explanation: 离线授权所需APPCODE(APPID),如使用该方式进行正式授权,请移除临时授权文件 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_OFFLINE_APP_CODE; + +/* + * BDS_ASR_OFFLINE_LICENSE_FILE_PATH + * Value explanation: 离线授权文件路径 + * Value type: NSString + * Default value: @"" + */ +extern NSString* BDS_ASR_OFFLINE_LICENSE_FILE_PATH; + + +#pragma mark - Offline Engine KWS + +/* + * BDS_ASR_OFFLINE_ENGINE_TYPE + * Value explanation: 离线识别引擎类型 + * Value type: TBDVoiceRecognitionOfflineEngineType + * Default value: @(EVR_OFFLINE_ENGINE_GRAMMER) + */ +extern NSString* BDS_ASR_OFFLINE_ENGINE_TYPE; + +/* + * BDS_ASR_OFFLINE_ENGINE_DAT_FILE_PATH + * Value explanation: 离线识别资源文件路径 + * Value type: NSString + * Default value: @"" + */ +extern NSString* BDS_ASR_OFFLINE_ENGINE_DAT_FILE_PATH; + +/* + * BDS_ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH + * Value explanation: 离线识别语法文件路径 + * Value type: NSString + * Default value: @"" + */ +extern NSString* BDS_ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH; +/* + * BDS_ASR_OFFLINE_ENGINE_GRAMMER_SLOT + * Value explanation: 语法模式离线语法槽,使用该参数更新离线语法文件 + * Value type: NSString (@"{\"name\":[\"张三\",\"李四\"],\"appname\":[\"手白\",\"度秘\"]}") + * Default value: @"" + */ +extern NSString* BDS_ASR_OFFLINE_ENGINE_GRAMMER_SLOT; +/* + * BDS_ASR_OFFLINE_ENGINE_WAKEUP_WORDS_FILE_PATH + * Value explanation: 唤醒词文件路径,使用了唤醒并使用离线语法识别的情况下需要设置,其他情况请忽略该参数 + * Value type: NSString + * Default value: @"" + */ + +extern NSString* BDS_ASR_OFFLINE_ENGINE_WAKEUP_WORDS_FILE_PATH; + +#pragma mark - VR from Wakeup + +/* + * BDS_ASR_OFFLINE_ENGINE_TRIGGERED_WAKEUP_WORD + * Value explanation: 当前触发唤醒词,唤醒后立即调用识别的情况下配置,其他情况请忽略该参数 + * Value type: NSString + * Default value: @"" + */ +extern NSString* BDS_ASR_OFFLINE_ENGINE_TRIGGERED_WAKEUP_WORD; + +/* + * BDS_ASR_NEED_CACHE_AUDIO + * Value explanation: 唤醒后立刻进行识别需开启该参数,其他情况请忽略该参数 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_NEED_CACHE_AUDIO; + +#pragma mark - 服务端配置 + +/* + * BDS_ASR_PRODUCT_ID + * Value explanation: 设置产品ID + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_PRODUCT_ID; + +/* + * BDS_ASR_FIX_APP + * Value explanation: 请忽略该参数 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_FIX_APP; + +/* + * BDS_ASR_SERVER_URL + * Value explanation: 设置服务器地址 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_SERVER_URL; + +/* + * BDS_ASR_BROWSER_USER_AGENT + * Value explanation: 设置浏览器标识(Http request header),资源返回时会根据UA适配 + * Value type: NSString + * Default value: -(可通过[UIWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]获取) + */ +extern NSString* BDS_ASR_BROWSER_USER_AGENT; + +/* + * BDS_ASR_LOCATION + * Value explanation: 更新当前地理位置信息,与地理位置相关的资源会优先返回附近资源信息, 请传入通过GPS获取到的经纬度数据 + * Value type: CLLocation + * Default value: - + */ +extern NSString* BDS_ASR_LOCATION; + + +#pragma mark - 识别器扩展配置 + +/* + * BDS_ASR_PROTOCOL + * Value explanation: 设置协议类型 + * Value type: TBDVoiceRecognitionProtocol + * Default value: @(EPROTOCOL_DEFAULT) + */ +extern NSString* BDS_ASR_PROTOCOL; + +/* + * BDS_ASR_COMPRESSION_TYPE + * Value explanation: 录音数据压缩算法 + * Value type: TBDVoiceRecognitionAudioCompressionType + * Default value: @(EVR_AUDIO_COMPRESSION_BV32) + */ +extern NSString* BDS_ASR_COMPRESSION_TYPE; + +/* + * BDS_ASR_ENABLE_DRC + * Value explanation: 是否进行车载环境下的噪声消除 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_ENABLE_DRC; + +/* + * BDS_ASR_PUNCTUATION_EXT_MODE + * Value explanation: 扩展标点模式 + * Value type: TBDVoiceRecognitionPuncMode + * Default value: EVR_PUNC_MODE_FULL + */ +extern NSString* BDS_ASR_PUNCTUATION_EXT_MODE; + + +#pragma mark - 扩展参数 + +/* + * BDS_ASR_BUA + * Value explanation: 扩展参数,浏览器标识 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_BUA; + +/* + * BDS_ASR_PAM + * Value explanation: 扩展参数,多轮对话需要的信息 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_PAM; + +/* + * BDS_ASR_STC + * Value explanation: 扩展参数,统计信息 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_STC; + +/* + * BDS_ASR_LTP + * Value explanation: 扩展参数,轻应用参数(uid) + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_LTP; + +/* + * BDS_ASR_TXT + * Value explanation: 扩展参数,上传文本,如果设置了该字段,将略过语音输入和识别阶段(暂不支持) + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_TXT; + +#pragma mark - CHUNK + +/* + * BDS_ASR_CHUNK_KEY + * Value explanation: Chunk协议授权字段 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_CHUNK_KEY; + +/* + * BDS_ASR_CHUNK_PARAM + * Value explanation: Chunk协议透传字段 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_CHUNK_PARAM; + +/* + * BDS_ASR_CHUNK_ENABLE + * Value explanation: Chunk协议开关 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_CHUNK_ENABLE; + +#pragma mark - FEEDBACK + +/* + * BDS_ASR_ENABLE_FEEDBACK + * Value explanation: 是否开启打点反馈功能 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_ENABLE_FEEDBACK; + +#pragma mark - LONG-SPEECH +/* + * BDS_ASR_ENABLE_LONG_SPEECH + * Value explanation: 是否启用长语音识别 + * Value type: BOOL + * Default value: @(NO) + */ +extern NSString* BDS_ASR_ENABLE_LONG_SPEECH; + +#pragma mark - Params with Command + +/* + * BDS_ASR_REALTIME_DATA + * Value explanation: 实时透传参数,随命令同步发送 + * Value type: NSString + * Default value: - + */ +extern NSString* BDS_ASR_REALTIME_DATA; + +#endif /* BDSASRParameters_h */ diff --git a/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSEventManager.h b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSEventManager.h new file mode 100644 index 00000000..5e2bcca1 --- /dev/null +++ b/FlutterHelper/flutter_trip/ios/plugin/ASRPlugin/Headers/BDSEventManager.h @@ -0,0 +1,23 @@ +// +// BDSEventManager.h +// BDSpeechClient +// +// Created by baidu on 16/6/6. +// Copyright © 2016年 baidu. All rights reserved. +// + +#import + +extern NSString* BDS_ASR_NAME; +extern NSString* BDS_WAKEUP_NAME; +extern NSString* BDS_UPLOADER_NAME; + +@interface BDSEventManager : NSObject + ++ (BDSEventManager *)createEventManagerWithName:(NSString *)name; +- (BOOL)setParameter:(id)param forKey:(NSString *)key; +- (void)sendCommand:(NSString *)command; +- (BOOL)setDelegate:(id)delegate; +- (NSString *)libver; + +@end diff --git a/FlutterHelper/flutter_trip/lib/dao/home_dao.dart b/FlutterHelper/flutter_trip/lib/dao/home_dao.dart new file mode 100644 index 00000000..71ff52d5 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/dao/home_dao.dart @@ -0,0 +1,21 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_trip/model/home_model.dart'; +import 'package:http/http.dart' as http; + +const HOME_URL = 'http://www.devio.org/io/flutter_app/json/home_page.json'; + +///首页大接口 +class HomeDao { + static Future fetch() async { + final response = await http.get(HOME_URL); + if (response.statusCode == 200) { + Utf8Decoder utf8decoder = Utf8Decoder(); // fix 中文乱码 + var result = json.decode(utf8decoder.convert(response.bodyBytes)); + return HomeModel.fromJson(result); + } else { + throw Exception('Failed to load home_page.json'); + } + } +} diff --git a/FlutterHelper/flutter_trip/lib/dao/search_dao.dart b/FlutterHelper/flutter_trip/lib/dao/search_dao.dart new file mode 100644 index 00000000..70d91ea4 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/dao/search_dao.dart @@ -0,0 +1,22 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_trip/model/seach_model.dart'; +import 'package:http/http.dart' as http; + +///搜索接口 +class SearchDao { + static Future fetch(String url, String text) async { + final response = await http.get(url); + if (response.statusCode == 200) { + Utf8Decoder utf8decoder = Utf8Decoder(); // fix 中文乱码 + var result = json.decode(utf8decoder.convert(response.bodyBytes)); + //只有当当前输入的内容和服务端返回的内容一致时才渲染 + SearchModel model = SearchModel.fromJson(result); + model.keyword = text; + return model; + } else { + throw Exception('Failed to load home_page.json'); + } + } +} diff --git a/FlutterHelper/flutter_trip/lib/dao/travel_dao.dart b/FlutterHelper/flutter_trip/lib/dao/travel_dao.dart new file mode 100644 index 00000000..8f53dac2 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/dao/travel_dao.dart @@ -0,0 +1,43 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_trip/model/travel_model.dart'; +import 'package:http/http.dart' as http; + +///旅拍页接口 + +var Params = { + "districtId": -1, + "groupChannelCode": "RX-OMF", + "type": null, + "lat": -180, + "lon": -180, + "locatedDistrictId": 0, + "pagePara": { + "pageIndex": 1, + "pageSize": 10, + "sortType": 9, + "sortDirection": 0 + }, + "imageCutType": 1, + "head": {'cid': "09031014111431397988"}, + "contentType": "json" +}; + +class TravelDao { + static Future fetch( + String url,Map params, String groupChannelCode, int pageIndex, int pageSize) async { + Map paramsMap = params['pagePara']; + paramsMap['pageIndex'] = pageIndex; + paramsMap['pageSize'] = pageSize; + params['groupChannelCode'] = groupChannelCode; + final response = await http.post(url, body: jsonEncode(params)); + if (response.statusCode == 200) { + Utf8Decoder utf8decoder = Utf8Decoder(); // fix 中文乱码 + var result = json.decode(utf8decoder.convert(response.bodyBytes)); + return TravelItemModel.fromJson(result); + } else { + throw Exception('Failed to load travel'); + } + } +} diff --git a/FlutterHelper/flutter_trip/lib/dao/travel_tab_dao.dart b/FlutterHelper/flutter_trip/lib/dao/travel_tab_dao.dart new file mode 100644 index 00000000..1d56f44e --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/dao/travel_tab_dao.dart @@ -0,0 +1,21 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_trip/model/home_model.dart'; +import 'package:flutter_trip/model/travel_tab_model.dart'; +import 'package:http/http.dart' as http; + +///旅拍类别接口 +class TravelTabDao { + static Future fetch() async { + final response = await http + .get('http://www.devio.org/io/flutter_app/json/travel_page.json'); + if (response.statusCode == 200) { + Utf8Decoder utf8decoder = Utf8Decoder(); // fix 中文乱码 + var result = json.decode(utf8decoder.convert(response.bodyBytes)); + return TravelTabModel.fromJson(result); + } else { + throw Exception('Failed to load travel_page.json'); + } + } +} diff --git a/FlutterHelper/flutter_trip/lib/main.dart b/FlutterHelper/flutter_trip/lib/main.dart new file mode 100644 index 00000000..0b91f86e --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/main.dart @@ -0,0 +1,27 @@ +/** + * 《Flutter从入门到进阶-实战携程网App》 + * 课程地址: + * https://coding.imooc.com/class/321.html + * 课程代码、文档: + * https://git.imooc.com/coding-321/ + * 课程辅导答疑区: + * http://coding.imooc.com/learn/qa/321.html + */ + +import 'package:flutter/material.dart'; +import 'package:flutter_trip/navigator/tab_navigator.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter之旅', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: TabNavigator(), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/flutter_trip/lib/model/common_model.dart b/FlutterHelper/flutter_trip/lib/model/common_model.dart new file mode 100644 index 00000000..8d6bd424 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/model/common_model.dart @@ -0,0 +1,21 @@ + +class CommonModel { + final String icon; + final String title; + final String url; + final String statusBarColor; + final bool hideAppBar; + + CommonModel( + {this.icon, this.title, this.url, this.statusBarColor, this.hideAppBar}); + + factory CommonModel.fromJson(Map json) { + return CommonModel( + icon: json['icon'], + title: json['title'], + url: json['url'], + statusBarColor: json['statusBarColor'], + hideAppBar: json['hideAppBar'] + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/model/config_model.dart b/FlutterHelper/flutter_trip/lib/model/config_model.dart new file mode 100644 index 00000000..8658e3cb --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/model/config_model.dart @@ -0,0 +1,13 @@ +class ConfigModel { + final String searchUrl; + + ConfigModel({this.searchUrl}); + + factory ConfigModel.fromJson(Map json) { + return ConfigModel(searchUrl: json['searchUrl']); + } + + Map toJson() { + return {searchUrl: searchUrl}; + } +} diff --git a/FlutterHelper/flutter_trip/lib/model/grid_nav_model.dart b/FlutterHelper/flutter_trip/lib/model/grid_nav_model.dart new file mode 100644 index 00000000..af9ad000 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/model/grid_nav_model.dart @@ -0,0 +1,51 @@ +import 'package:flutter_trip/model/common_model.dart'; + +///首页网格卡片模型 +class GridNavModel { + final GridNavItem hotel; + final GridNavItem flight; + final GridNavItem travel; + + GridNavModel({this.hotel, this.flight, this.travel}); + + factory GridNavModel.fromJson(Map json) { + return json != null + ? GridNavModel( + hotel: GridNavItem.fromJson(json['hotel']), + flight: GridNavItem.fromJson(json['flight']), + travel: GridNavItem.fromJson(json['travel']), + ) + : null; + } +} + +class GridNavItem { + final String startColor; + final String endColor; + final CommonModel mainItem; + final CommonModel item1; + final CommonModel item2; + final CommonModel item3; + final CommonModel item4; + + GridNavItem( + {this.startColor, + this.endColor, + this.mainItem, + this.item1, + this.item2, + this.item3, + this.item4}); + + factory GridNavItem.fromJson(Map json) { + return GridNavItem( + startColor: json['startColor'], + endColor: json['endColor'], + mainItem: CommonModel.fromJson(json['mainItem']), + item1: CommonModel.fromJson(json['item1']), + item2: CommonModel.fromJson(json['item2']), + item3: CommonModel.fromJson(json['item3']), + item4: CommonModel.fromJson(json['item4']), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/model/home_model.dart b/FlutterHelper/flutter_trip/lib/model/home_model.dart new file mode 100644 index 00000000..981ddff0 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/model/home_model.dart @@ -0,0 +1,51 @@ +//config Object NonNull +//bannerList Array NonNull +//localNavList Array NonNull +//gridNav Object NonNull +//subNavList Array NonNull +//salesBox Object NonNull +import 'package:flutter_trip/model/common_model.dart'; +import 'package:flutter_trip/model/config_model.dart'; +import 'package:flutter_trip/model/grid_nav_model.dart'; +import 'package:flutter_trip/model/sales_box_model.dart'; + +class HomeModel { + final ConfigModel config; + final List bannerList; + final List localNavList; + final List subNavList; + final GridNavModel gridNav; + final SalesBoxModel salesBox; + + HomeModel( + {this.config, + this.bannerList, + this.localNavList, + this.subNavList, + this.gridNav, + this.salesBox}); + + factory HomeModel.fromJson(Map json) { + var localNavListJson = json['localNavList'] as List; + List localNavList = + localNavListJson.map((i) => CommonModel.fromJson(i)).toList(); + + var bannerListJson = json['bannerList'] as List; + List bannerList = + bannerListJson.map((i) => CommonModel.fromJson(i)).toList(); + + var subNavListJson = json['subNavList'] as List; + List subNavList = + subNavListJson.map((i) => CommonModel.fromJson(i)).toList(); + + return HomeModel( + localNavList: localNavList, + bannerList: bannerList, + subNavList: subNavList, + config: ConfigModel.fromJson(json['config']), + gridNav: GridNavModel.fromJson(json['gridNav']), + salesBox: SalesBoxModel.fromJson(json['salesBox']), + ); + } + +} diff --git a/FlutterHelper/flutter_trip/lib/model/sales_box_model.dart b/FlutterHelper/flutter_trip/lib/model/sales_box_model.dart new file mode 100644 index 00000000..a902500d --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/model/sales_box_model.dart @@ -0,0 +1,36 @@ +import 'package:flutter_trip/model/common_model.dart'; + +///活动入口模型 +class SalesBoxModel { + final String icon; + final String moreUrl; + final CommonModel bigCard1; + final CommonModel bigCard2; + final CommonModel smallCard1; + final CommonModel smallCard2; + final CommonModel smallCard3; + final CommonModel smallCard4; + + SalesBoxModel( + {this.icon, + this.moreUrl, + this.bigCard1, + this.bigCard2, + this.smallCard1, + this.smallCard2, + this.smallCard3, + this.smallCard4}); + + factory SalesBoxModel.fromJson(Map json) { + return SalesBoxModel( + icon: json['icon'], + moreUrl: json['moreUrl'], + bigCard1: CommonModel.fromJson(json['bigCard1']), + bigCard2: CommonModel.fromJson(json['bigCard2']), + smallCard1: CommonModel.fromJson(json['smallCard1']), + smallCard2: CommonModel.fromJson(json['smallCard2']), + smallCard3: CommonModel.fromJson(json['smallCard3']), + smallCard4: CommonModel.fromJson(json['smallCard4']), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/model/seach_model.dart b/FlutterHelper/flutter_trip/lib/model/seach_model.dart new file mode 100644 index 00000000..916deba7 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/model/seach_model.dart @@ -0,0 +1,45 @@ +///搜索模型 +class SearchModel { + String keyword; + final List data; + + SearchModel({this.data}); + + factory SearchModel.fromJson(Map json) { + var dataJson = json['data'] as List; + List data = + dataJson.map((i) => SearchItem.fromJson(i)).toList(); + return SearchModel(data: data); + } +} + +class SearchItem { + final String word; //xx酒店 + final String type; //hotel + final String price; //实时计价 + final String star; //豪华型 + final String zonename; //虹桥 + final String districtname; //上海 + final String url; + + SearchItem( + {this.word, + this.type, + this.price, + this.star, + this.zonename, + this.districtname, + this.url}); + + factory SearchItem.fromJson(Map json) { + return SearchItem( + word: json['word'], + type: json['type'], + price: json['price'], + star: json['star'], + zonename: json['zonename'], + districtname: json['districtname'], + url: json['url'], + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/model/travel_model.dart b/FlutterHelper/flutter_trip/lib/model/travel_model.dart new file mode 100644 index 00000000..5d2b8c51 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/model/travel_model.dart @@ -0,0 +1,425 @@ +///旅拍页模型 +class TravelItemModel { + int totalCount; + List resultList; + + TravelItemModel({this.totalCount, this.resultList}); + + TravelItemModel.fromJson(Map json) { + totalCount = json['totalCount']; + if (json['resultList'] != null) { + resultList = new List(); + json['resultList'].forEach((v) { + resultList.add(new TravelItem.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['totalCount'] = this.totalCount; + if (this.resultList != null) { + data['resultList'] = this.resultList.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class TravelItem { + int type; + Article article; + + TravelItem({this.type, this.article}); + + TravelItem.fromJson(Map json) { + type = json['type']; + article = + json['article'] != null ? new Article.fromJson(json['article']) : null; + } + + Map toJson() { + final Map data = new Map(); + data['type'] = this.type; + if (this.article != null) { + data['article'] = this.article.toJson(); + } + return data; + } +} + +class Article { + int articleId; + String articleType; + int productType; + int sourceType; + String articleTitle; + Author author; + List images; + bool hasVideo; + int readCount; + int likeCount; + int commentCount; + List urls; + List tags; + List topics; + List pois; + String publishTime; + String publishTimeDisplay; + String shootTime; + String shootTimeDisplay; + int level; + String distanceText; + bool isLike; + int imageCounts; + bool isCollected; + int collectCount; + int articleStatus; + String poiName; + + Article( + {this.articleId, + this.articleType, + this.productType, + this.sourceType, + this.articleTitle, + this.author, + this.images, + this.hasVideo, + this.readCount, + this.likeCount, + this.commentCount, + this.urls, + this.tags, + this.topics, + this.pois, + this.publishTime, + this.publishTimeDisplay, + this.shootTime, + this.shootTimeDisplay, + this.level, + this.distanceText, + this.isLike, + this.imageCounts, + this.isCollected, + this.collectCount, + this.articleStatus, + this.poiName}); + + Article.fromJson(Map json) { + articleId = json['articleId']; + articleType = json['articleType']; + productType = json['productType']; + sourceType = json['sourceType']; + articleTitle = json['articleTitle']; + author = + json['author'] != null ? new Author.fromJson(json['author']) : null; + if (json['images'] != null) { + images = new List(); + json['images'].forEach((v) { + images.add(new Images.fromJson(v)); + }); + } + hasVideo = json['hasVideo']; + readCount = json['readCount']; + likeCount = json['likeCount']; + commentCount = json['commentCount']; + if (json['urls'] != null) { + urls = new List(); + json['urls'].forEach((v) { + urls.add(new Urls.fromJson(v)); + }); + } + if (json['topics'] != null) { + topics = new List(); + json['topics'].forEach((v) { + topics.add(new Topics.fromJson(v)); + }); + } + if (json['pois'] != null) { + pois = new List(); + json['pois'].forEach((v) { + pois.add(new Pois.fromJson(v)); + }); + } + publishTime = json['publishTime']; + publishTimeDisplay = json['publishTimeDisplay']; + shootTime = json['shootTime']; + shootTimeDisplay = json['shootTimeDisplay']; + level = json['level']; + distanceText = json['distanceText']; + isLike = json['isLike']; + imageCounts = json['imageCounts']; + isCollected = json['isCollected']; + collectCount = json['collectCount']; + articleStatus = json['articleStatus']; + poiName = json['poiName']; + } + + Map toJson() { + final Map data = new Map(); + data['articleId'] = this.articleId; + data['articleType'] = this.articleType; + data['productType'] = this.productType; + data['sourceType'] = this.sourceType; + data['articleTitle'] = this.articleTitle; + if (this.author != null) { + data['author'] = this.author.toJson(); + } + if (this.images != null) { + data['images'] = this.images.map((v) => v.toJson()).toList(); + } + data['hasVideo'] = this.hasVideo; + data['readCount'] = this.readCount; + data['likeCount'] = this.likeCount; + data['commentCount'] = this.commentCount; + if (this.urls != null) { + data['urls'] = this.urls.map((v) => v.toJson()).toList(); + } + if (this.topics != null) { + data['topics'] = this.topics.map((v) => v.toJson()).toList(); + } + if (this.pois != null) { + data['pois'] = this.pois.map((v) => v.toJson()).toList(); + } + data['publishTime'] = this.publishTime; + data['publishTimeDisplay'] = this.publishTimeDisplay; + data['shootTime'] = this.shootTime; + data['shootTimeDisplay'] = this.shootTimeDisplay; + data['level'] = this.level; + data['distanceText'] = this.distanceText; + data['isLike'] = this.isLike; + data['imageCounts'] = this.imageCounts; + data['isCollected'] = this.isCollected; + data['collectCount'] = this.collectCount; + data['articleStatus'] = this.articleStatus; + data['poiName'] = this.poiName; + return data; + } +} + +class Author { + int authorId; + String nickName; + String clientAuth; + String jumpUrl; + CoverImage coverImage; + int identityType; + String tag; + + Author( + {this.authorId, + this.nickName, + this.clientAuth, + this.jumpUrl, + this.coverImage, + this.identityType, + this.tag}); + + Author.fromJson(Map json) { + authorId = json['authorId']; + nickName = json['nickName']; + clientAuth = json['clientAuth']; + jumpUrl = json['jumpUrl']; + coverImage = json['coverImage'] != null + ? new CoverImage.fromJson(json['coverImage']) + : null; + identityType = json['identityType']; + tag = json['tag']; + } + + Map toJson() { + final Map data = new Map(); + data['authorId'] = this.authorId; + data['nickName'] = this.nickName; + data['clientAuth'] = this.clientAuth; + data['jumpUrl'] = this.jumpUrl; + if (this.coverImage != null) { + data['coverImage'] = this.coverImage.toJson(); + } + data['identityType'] = this.identityType; + data['tag'] = this.tag; + return data; + } +} + +class CoverImage { + String dynamicUrl; + String originalUrl; + + CoverImage({this.dynamicUrl, this.originalUrl}); + + CoverImage.fromJson(Map json) { + dynamicUrl = json['dynamicUrl']; + originalUrl = json['originalUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['dynamicUrl'] = this.dynamicUrl; + data['originalUrl'] = this.originalUrl; + return data; + } +} + +class Images { + int imageId; + String dynamicUrl; + String originalUrl; + double width; + double height; + int mediaType; + bool isWaterMarked; + + Images( + {this.imageId, + this.dynamicUrl, + this.originalUrl, + this.width, + this.height, + this.mediaType, + this.isWaterMarked}); + + Images.fromJson(Map json) { + imageId = json['imageId']; + dynamicUrl = json['dynamicUrl']; + originalUrl = json['originalUrl']; + width = json['width']; + height = json['height']; + mediaType = json['mediaType']; + isWaterMarked = json['isWaterMarked']; + } + + Map toJson() { + final Map data = new Map(); + data['imageId'] = this.imageId; + data['dynamicUrl'] = this.dynamicUrl; + data['originalUrl'] = this.originalUrl; + data['width'] = this.width; + data['height'] = this.height; + data['mediaType'] = this.mediaType; + data['isWaterMarked'] = this.isWaterMarked; + return data; + } +} + +class Urls { + String version; + String appUrl; + String h5Url; + String wxUrl; + + Urls({this.version, this.appUrl, this.h5Url, this.wxUrl}); + + Urls.fromJson(Map json) { + version = json['version']; + appUrl = json['appUrl']; + h5Url = json['h5Url']; + wxUrl = json['wxUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['version'] = this.version; + data['appUrl'] = this.appUrl; + data['h5Url'] = this.h5Url; + data['wxUrl'] = this.wxUrl; + return data; + } +} + +class Topics { + int topicId; + String topicName; + int level; + + Topics({this.topicId, this.topicName, this.level}); + + Topics.fromJson(Map json) { + topicId = json['topicId']; + topicName = json['topicName']; + level = json['level']; + } + + Map toJson() { + final Map data = new Map(); + data['topicId'] = this.topicId; + data['topicName'] = this.topicName; + data['level'] = this.level; + return data; + } +} + +class Pois { + int poiType; + int poiId; + String poiName; + int businessId; + int districtId; + PoiExt poiExt; + int source; + int isMain; + bool isInChina; + String countryName; + + Pois( + {this.poiType, + this.poiId, + this.poiName, + this.businessId, + this.districtId, + this.poiExt, + this.source, + this.isMain, + this.isInChina, + this.countryName}); + + Pois.fromJson(Map json) { + poiType = json['poiType']; + poiId = json['poiId']; + poiName = json['poiName']; + businessId = json['businessId']; + districtId = json['districtId']; + poiExt = + json['poiExt'] != null ? new PoiExt.fromJson(json['poiExt']) : null; + source = json['source']; + isMain = json['isMain']; + isInChina = json['isInChina']; + countryName = json['countryName']; + } + + Map toJson() { + final Map data = new Map(); + data['poiType'] = this.poiType; + data['poiId'] = this.poiId; + data['poiName'] = this.poiName; + data['businessId'] = this.businessId; + data['districtId'] = this.districtId; + if (this.poiExt != null) { + data['poiExt'] = this.poiExt.toJson(); + } + data['source'] = this.source; + data['isMain'] = this.isMain; + data['isInChina'] = this.isInChina; + data['countryName'] = this.countryName; + return data; + } +} + +class PoiExt { + String h5Url; + String appUrl; + + PoiExt({this.h5Url, this.appUrl}); + + PoiExt.fromJson(Map json) { + h5Url = json['h5Url']; + appUrl = json['appUrl']; + } + + Map toJson() { + final Map data = new Map(); + data['h5Url'] = this.h5Url; + data['appUrl'] = this.appUrl; + return data; + } +} diff --git a/FlutterHelper/flutter_trip/lib/model/travel_tab_model.dart b/FlutterHelper/flutter_trip/lib/model/travel_tab_model.dart new file mode 100644 index 00000000..68ac5a5f --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/model/travel_tab_model.dart @@ -0,0 +1,47 @@ +///旅拍类别模型 +class TravelTabModel { + Map params; + String url; + List tabs; + + TravelTabModel({this.url, this.tabs}); + + TravelTabModel.fromJson(Map json) { + url = json['url']; + params = json['params']; + if (json['tabs'] != null) { + tabs = new List(); + json['tabs'].forEach((v) { + tabs.add(new TravelTab.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['url'] = this.url; + if (this.tabs != null) { + data['tabs'] = this.tabs.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class TravelTab { + String labelName; + String groupChannelCode; + + TravelTab({this.labelName, this.groupChannelCode}); + + TravelTab.fromJson(Map json) { + labelName = json['labelName']; + groupChannelCode = json['groupChannelCode']; + } + + Map toJson() { + final Map data = new Map(); + data['labelName'] = this.labelName; + data['groupChannelCode'] = this.groupChannelCode; + return data; + } +} diff --git a/FlutterHelper/flutter_trip/lib/navigator/tab_navigator.dart b/FlutterHelper/flutter_trip/lib/navigator/tab_navigator.dart new file mode 100644 index 00000000..9f2c39fc --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/navigator/tab_navigator.dart @@ -0,0 +1,78 @@ +/** + * 《Flutter从入门到进阶-实战携程网App》 + * 课程地址: + * https://coding.imooc.com/class/321.html + * 课程代码、文档: + * https://git.imooc.com/coding-321/ + * 课程辅导答疑区: + * http://coding.imooc.com/learn/qa/321.html + */ +import 'package:flutter/material.dart'; +import 'package:flutter_trip/pages/home_page.dart'; +import 'package:flutter_trip/pages/my_page.dart'; +import 'package:flutter_trip/pages/search_page.dart'; +import 'package:flutter_trip/pages/travel_page.dart'; + +class TabNavigator extends StatefulWidget { + @override + _TabNavigatorState createState() => _TabNavigatorState(); +} + +class _TabNavigatorState extends State { + final _defaultColor = Colors.grey; + final _activeColor = Colors.blue; + int _currentIndex = 0; + final PageController _controller = PageController( + initialPage: 0, + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: PageView( + controller: _controller, + children: [ + HomePage(), + SearchPage( + hideLeft: true, + ), + TravelPage(), + MyPage(), + ], + physics: NeverScrollableScrollPhysics(), + ), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, + onTap: (index) { + _controller.jumpToPage(index); + setState(() { + _currentIndex = index; + }); + }, + type: BottomNavigationBarType.fixed, + items: [ + _bottomItem('首页', Icons.home, 0), + _bottomItem('搜索', Icons.search, 1), + _bottomItem('旅拍', Icons.camera_alt, 2), + _bottomItem('我的', Icons.account_circle, 3), + ]), + ); + } + + _bottomItem(String title, IconData icon, int index) { + return BottomNavigationBarItem( + icon: Icon( + icon, + color: _defaultColor, + ), + activeIcon: Icon( + icon, + color: _activeColor, + ), + title: Text( + title, + style: TextStyle( + color: _currentIndex != index ? _defaultColor : _activeColor), + )); + } +} diff --git a/FlutterHelper/flutter_trip/lib/pages/home_page.dart b/FlutterHelper/flutter_trip/lib/pages/home_page.dart new file mode 100644 index 00000000..488b0cc5 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/pages/home_page.dart @@ -0,0 +1,215 @@ +/** + * 《Flutter从入门到进阶-实战携程网App》 + * 课程地址: + * https://coding.imooc.com/class/321.html + * 课程代码、文档: + * https://git.imooc.com/coding-321/ + * 课程辅导答疑区: + * http://coding.imooc.com/learn/qa/321.html + */ +import 'package:flutter/material.dart'; +import 'package:flutter_splash_screen/flutter_splash_screen.dart'; +import 'package:flutter_swiper/flutter_swiper.dart'; +import 'package:flutter_trip/dao/home_dao.dart'; +import 'package:flutter_trip/model/common_model.dart'; +import 'package:flutter_trip/model/grid_nav_model.dart'; +import 'package:flutter_trip/model/home_model.dart'; +import 'package:flutter_trip/model/sales_box_model.dart'; +import 'package:flutter_trip/pages/search_page.dart'; +import 'package:flutter_trip/pages/speak_page.dart'; +import 'package:flutter_trip/util/navigator_util.dart'; +import 'package:flutter_trip/widget/grid_nav.dart'; +import 'package:flutter_trip/widget/loading_container.dart'; +import 'package:flutter_trip/widget/local_nav.dart'; +import 'package:flutter_trip/widget/sales_box.dart'; +import 'package:flutter_trip/widget/search_bar.dart'; +import 'package:flutter_trip/widget/sub_nav.dart'; +import 'package:flutter_trip/widget/webview.dart'; + +const APPBAR_SCROLL_OFFSET = 100; +const SEARCH_BAR_DEFAULT_TEXT = '网红打卡地 景点 酒店 美食'; + +class HomePage extends StatefulWidget { + @override + _HomePageState createState() => _HomePageState(); +} + +class _HomePageState extends State { + double appBarAlpha = 0; + List localNavList = []; + List bannerList = []; + List subNavList = []; + GridNavModel gridNavModel; + SalesBoxModel salesBoxModel; + bool _loading = true; + + @override + void initState() { + super.initState(); + _handleRefresh(); + Future.delayed(Duration(milliseconds: 600), () { + FlutterSplashScreen.hide(); + }); + } + + _onScroll(offset) { + double alpha = offset / APPBAR_SCROLL_OFFSET; + if (alpha < 0) { + alpha = 0; + } else if (alpha > 1) { + alpha = 1; + } + setState(() { + appBarAlpha = alpha; + }); + print(appBarAlpha); + } + + Future _handleRefresh() async { + try { + HomeModel model = await HomeDao.fetch(); + setState(() { + localNavList = model.localNavList; + subNavList = model.subNavList; + gridNavModel = model.gridNav; + salesBoxModel = model.salesBox; + bannerList = model.bannerList; + _loading = false; + }); + } catch (e) { + print(e); + setState(() { + _loading = false; + }); + } + return null; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color(0xfff2f2f2), + body: LoadingContainer( + isLoading: _loading, + child: Stack( + children: [ + MediaQuery.removePadding( + removeTop: true, + context: context, + child: RefreshIndicator( + onRefresh: _handleRefresh, + child: NotificationListener( + onNotification: (scrollNotification) { + if (scrollNotification is ScrollUpdateNotification && + scrollNotification.depth == 0) { + //滚动且是列表滚动的时候 + _onScroll(scrollNotification.metrics.pixels); + } + }, + child: _listView, + )), + ), + _appBar + ], + )), + ); + } + + Widget get _listView { + return ListView( + children: [ + _banner, + Padding( + padding: EdgeInsets.fromLTRB(7, 4, 7, 4), + child: LocalNav(localNavList: localNavList), + ), + Padding( + padding: EdgeInsets.fromLTRB(7, 0, 7, 4), + child: GridNav(gridNavModel: gridNavModel)), + Padding( + padding: EdgeInsets.fromLTRB(7, 0, 7, 4), + child: SubNav(subNavList: subNavList)), + Padding( + padding: EdgeInsets.fromLTRB(7, 0, 7, 4), + child: SalesBox(salesBox: salesBoxModel)), + ], + ); + } + + Widget get _appBar { + return Column( + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + //AppBar渐变遮罩背景 + colors: [Color(0x66000000), Colors.transparent], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Container( + padding: EdgeInsets.fromLTRB(0, 20, 0, 0), + height: 80.0, + decoration: BoxDecoration( + color: Color.fromARGB((appBarAlpha * 255).toInt(), 255, 255, 255), + ), + child: SearchBar( + searchBarType: appBarAlpha > 0.2 + ? SearchBarType.homeLight + : SearchBarType.home, + inputBoxClick: _jumpToSearch, + speakClick: _jumpToSpeak, + defaultText: SEARCH_BAR_DEFAULT_TEXT, + leftButtonClick: () {}, + ), + ), + ), + Container( + height: appBarAlpha > 0.2 ? 0.5 : 0, + decoration: BoxDecoration( + boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 0.5)])) + ], + ); + } + + Widget get _banner { + return Container( + height: 160, + child: Swiper( + itemCount: bannerList.length, + autoplay: true, + itemBuilder: (BuildContext context, int index) { + return GestureDetector( + onTap: () { + CommonModel model = bannerList[index]; + NavigatorUtil.push( + context, + WebView( + url: model.url, + title: model.title, + hideAppBar: model.hideAppBar)); + }, + child: Image.network( + bannerList[index].icon, + fit: BoxFit.fill, + ), + ); + }, + pagination: SwiperPagination(), + ), + ); + } + + _jumpToSearch() { + NavigatorUtil.push( + context, + SearchPage( + hint: SEARCH_BAR_DEFAULT_TEXT, + )); + } + + _jumpToSpeak() { + NavigatorUtil.push(context, SpeakPage()); + } +} diff --git a/FlutterHelper/flutter_trip/lib/pages/my_page.dart b/FlutterHelper/flutter_trip/lib/pages/my_page.dart new file mode 100644 index 00000000..586b8a2a --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/pages/my_page.dart @@ -0,0 +1,31 @@ +/** + * 《Flutter从入门到进阶-实战携程网App》 + * 课程地址: + * https://coding.imooc.com/class/321.html + * 课程代码、文档: + * https://git.imooc.com/coding-321/ + * 课程辅导答疑区: + * http://coding.imooc.com/learn/qa/321.html + */ +import 'package:flutter/material.dart'; +import 'package:flutter_trip/widget/webview.dart'; + +class MyPage extends StatefulWidget { + @override + _MyPageState createState() => _MyPageState(); +} + +class _MyPageState extends State { + + @override + Widget build(BuildContext context) { + return Scaffold( + body: WebView( + url: 'https://m.ctrip.com/webapp/myctrip/', + hideAppBar: true, + backForbid: true, + statusBarColor: '4c5bca', + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/pages/search_page.dart b/FlutterHelper/flutter_trip/lib/pages/search_page.dart new file mode 100644 index 00000000..b91ea347 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/pages/search_page.dart @@ -0,0 +1,250 @@ +/** + * 《Flutter从入门到进阶-实战携程网App》 + * 课程地址: + * https://coding.imooc.com/class/321.html + * 课程代码、文档: + * https://git.imooc.com/coding-321/ + * 课程辅导答疑区: + * http://coding.imooc.com/learn/qa/321.html + */ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_trip/dao/search_dao.dart'; +import 'package:flutter_trip/model/seach_model.dart'; +import 'package:flutter_trip/pages/speak_page.dart'; +import 'package:flutter_trip/util/navigator_util.dart'; +import 'package:flutter_trip/widget/search_bar.dart'; +import 'package:flutter_trip/widget/webview.dart'; + +const TYPES = [ + 'channelgroup', + 'gs', + 'plane', + 'train', + 'cruise', + 'district', + 'food', + 'hotel', + 'huodong', + 'shop', + 'sight', + 'ticket', + 'travelgroup' +]; +const URL = + 'https://m.ctrip.com/restapi/h5api/searchapp/search?source=mobileweb&action=autocomplete&contentType=json&keyword='; + +class SearchPage extends StatefulWidget { + final bool hideLeft; + final String searchUrl; + final String keyword; + final String hint; + + const SearchPage( + {Key key, this.hideLeft, this.searchUrl = URL, this.keyword, this.hint}) + : super(key: key); + + @override + _SearchPageState createState() => _SearchPageState(); +} + +class _SearchPageState extends State { + SearchModel searchModel; + String keyword; + + @override + void initState() { + if (widget.keyword != null) { + _onTextChange(widget.keyword); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + _appBar(), + MediaQuery.removePadding( + removeTop: true, + context: context, + child: Expanded( + flex: 1, + child: ListView.builder( + itemCount: searchModel?.data?.length ?? 0, + itemBuilder: (BuildContext context, int position) { + return _item(position); + }), + ), + ) + ], + ), + ); + } + + _onTextChange(String text) { + keyword = text; + if (text.length == 0) { + setState(() { + searchModel = null; + }); + return; + } + String url = widget.searchUrl + text; + SearchDao.fetch(url, text).then((SearchModel model) { + //只有当当前输入的内容和服务端返回的内容一致时才渲染 + if (model.keyword == keyword) { + setState(() { + searchModel = model; + }); + } + }).catchError((e) { + print(e); + }); + } + + _appBar() { + return Column( + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + //AppBar渐变遮罩背景 + colors: [Color(0x66000000), Colors.transparent], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + child: Container( + padding: EdgeInsets.only(top: 20), + height: 80, + decoration: BoxDecoration(color: Colors.white), + child: SearchBar( + hideLeft: widget.hideLeft, + defaultText: widget.keyword, + hint: widget.hint, + speakClick: _jumpToSpeak, + leftButtonClick: () { + Navigator.pop(context); + }, + onChanged: _onTextChange, + )), + ) + ], + ); + } + + _jumpToSpeak() { + NavigatorUtil.push(context, SpeakPage()); + } + + _item(int position) { + if (searchModel == null || searchModel.data == null) return null; + SearchItem item = searchModel.data[position]; + return GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: item.url, + title: '详情', + )); + }, + child: Container( + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 0.3, color: Colors.grey))), + child: Row( + children: [ + Container( + margin: EdgeInsets.all(1), + child: Image( + height: 26, + width: 26, + image: AssetImage(_typeImage(item.type))), + ), + Column( + children: [ + Container( + width: 300, + child: _title(item), + ), + Container( + width: 300, + margin: EdgeInsets.only(top: 5), + child: _subTitle(item)) + ], + ) + ], + ), + ), + ); + } + + _typeImage(String type) { + if (type == null) return 'images/type_travelgroup.png'; + String path = 'travelgroup'; + for (final val in TYPES) { + if (type.contains(val)) { + path = val; + break; + } + } + return 'images/type_$path.png'; + } + + _title(SearchItem item) { + if (item == null) { + return null; + } + List spans = []; + spans.addAll(_keywordTextSpans(item.word, searchModel.keyword)); + spans.add(TextSpan( + text: ' ' + (item.districtname ?? '') + ' ' + (item.zonename ?? ''), + style: TextStyle(fontSize: 16, color: Colors.grey))); + return RichText(text: TextSpan(children: spans)); + } + + _subTitle(SearchItem item) { + return RichText( + text: TextSpan(children: [ + TextSpan( + text: item.price ?? '', + style: TextStyle(fontSize: 16, color: Colors.orange), + ), + TextSpan( + text: ' ' + (item.star ?? ''), + style: TextStyle(fontSize: 12, color: Colors.grey), + ) + ]), + ); + } + + _keywordTextSpans(String word, String keyword) { + List spans = []; + if (word == null || word.length == 0) return spans; + //搜索关键字高亮忽略大小写 + String wordL = word.toLowerCase(), keywordL = keyword.toLowerCase(); + List arr = wordL.split(keywordL); + TextStyle normalStyle = TextStyle(fontSize: 16, color: Colors.black87); + TextStyle keywordStyle = TextStyle(fontSize: 16, color: Colors.orange); + //'wordwoc'.split('w') -> [, ord, oc] @https://www.tutorialspoint.com/tpcg.php?p=wcpcUA + int preIndex = 0; + for (int i = 0; i < arr.length; i++) { + if (i != 0) { + //搜索关键字高亮忽略大小写 + preIndex = wordL.indexOf(keywordL, preIndex); + spans.add(TextSpan( + text: word.substring(preIndex, preIndex + keyword.length), + style: keywordStyle)); + } + String val = arr[i]; + if (val != null && val.length > 0) { + spans.add(TextSpan(text: val, style: normalStyle)); + } + } + return spans; + } +} diff --git a/FlutterHelper/flutter_trip/lib/pages/speak_page.dart b/FlutterHelper/flutter_trip/lib/pages/speak_page.dart new file mode 100644 index 00000000..1e174847 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/pages/speak_page.dart @@ -0,0 +1,212 @@ +/** + * 《Flutter从入门到进阶-实战携程网App》 + * 课程地址: + * https://coding.imooc.com/class/321.html + * 课程代码、文档: + * https://git.imooc.com/coding-321/ + * 课程辅导答疑区: + * http://coding.imooc.com/learn/qa/321.html + */ +import 'package:flutter/material.dart'; +import 'package:flutter_trip/pages/search_page.dart'; +import 'package:flutter_trip/plugin/asr_manager.dart'; +import 'package:flutter_trip/util/navigator_util.dart'; + +///语音识别 +class SpeakPage extends StatefulWidget { + @override + _SpeakPageState createState() => _SpeakPageState(); +} + +class _SpeakPageState extends State + with SingleTickerProviderStateMixin { + String speakTips = '长按说话'; + String speakResult = ''; + Animation animation; + AnimationController controller; + + @override + void initState() { + controller = AnimationController( + vsync: this, duration: Duration(milliseconds: 1000)); + animation = CurvedAnimation(parent: controller, curve: Curves.easeIn) + ..addStatusListener((status) { + if (status == AnimationStatus.completed) { + controller.reverse(); + } else if (status == AnimationStatus.dismissed) { + controller.forward(); + } + }); + super.initState(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + padding: EdgeInsets.all(30), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [_topItem(), _bottomItem()], + ), + ), + ), + ); + } + + _speakStart() { + controller.forward(); + setState(() { + speakTips = '- 识别中 -'; + }); + AsrManager.start().then((text) { + if (text != null && text.length > 0) { + setState(() { + speakResult = text; + }); + Navigator.pop(context); + NavigatorUtil.push( + context, + SearchPage( + keyword: speakResult, + )); + print("----------" + text); + } + }).catchError((e) { + print("----------" + e.toString()); + }); + } + + _speakStop() { + setState(() { + speakTips = '长按说话'; + }); + controller.reset(); + controller.stop(); + AsrManager.stop(); + } + + _topItem() { + return Column( + children: [ + Padding( + padding: EdgeInsets.fromLTRB(0, 30, 0, 30), + child: Text('你可以这样说', + style: TextStyle(fontSize: 16, color: Colors.black54))), + Text('故宫门票\n北京一日游\n迪士尼乐园', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + color: Colors.grey, + )), + Padding( + padding: EdgeInsets.all(20), + child: Text( + speakResult, + style: TextStyle(color: Colors.blue), + ), + ) + ], + ); + } + + _bottomItem() { + return FractionallySizedBox( + widthFactor: 1, + child: Stack( + children: [ + GestureDetector( + onTapDown: (e) { + _speakStart(); + }, + onTapUp: (e) { + _speakStop(); + }, + onTapCancel: () { + _speakStop(); + }, + child: Center( + child: Column( + children: [ + Padding( + padding: EdgeInsets.all(10), + child: Text( + speakTips, + style: TextStyle(color: Colors.blue, fontSize: 12), + ), + ), + Stack( + children: [ + Container( + //占坑,避免动画执行过程中导致父布局大小变得 + height: MIC_SIZE, + width: MIC_SIZE, + ), + Center( + child: AnimatedMic( + animation: animation, + ), + ) + ], + ) + ], + ), + ), + ), + Positioned( + right: 0, + bottom: 20, + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Icon( + Icons.close, + size: 30, + color: Colors.grey, + ), + ), + ) + ], + ), + ); + } +} + +const double MIC_SIZE = 80; + +class AnimatedMic extends AnimatedWidget { + static final _opacityTween = Tween(begin: 1, end: 0.5); + static final _sizeTween = Tween(begin: MIC_SIZE, end: MIC_SIZE - 20); + + AnimatedMic({Key key, Animation animation}) + : super(key: key, listenable: animation); + + @override + Widget build(BuildContext context) { + final Animation animation = listenable; + return Opacity( + opacity: _opacityTween.evaluate(animation), + child: Container( + height: _sizeTween.evaluate(animation), + width: _sizeTween.evaluate(animation), + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(MIC_SIZE / 2), + ), + child: Icon( + Icons.mic, + color: Colors.white, + size: 30, + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/pages/travel_page.dart b/FlutterHelper/flutter_trip/lib/pages/travel_page.dart new file mode 100644 index 00000000..2e125742 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/pages/travel_page.dart @@ -0,0 +1,88 @@ +/** + * 《Flutter从入门到进阶-实战携程网App》 + * 课程地址: + * https://coding.imooc.com/class/321.html + * 课程代码、文档: + * https://git.imooc.com/coding-321/ + * 课程辅导答疑区: + * http://coding.imooc.com/learn/qa/321.html + */ +import 'package:flutter/material.dart'; +import 'package:flutter_trip/dao/travel_tab_dao.dart'; +import 'package:flutter_trip/model/travel_tab_model.dart'; +import 'package:flutter_trip/pages/travel_tab_page.dart'; +import 'package:underline_indicator/underline_indicator.dart'; + +class TravelPage extends StatefulWidget { + @override + _TravelPageState createState() => _TravelPageState(); +} + +class _TravelPageState extends State with TickerProviderStateMixin { + TabController _controller; + List tabs = []; + TravelTabModel travelTabModel; + + @override + void initState() { + _controller = TabController(length: 0, vsync: this); + TravelTabDao.fetch().then((TravelTabModel model) { + _controller = TabController( + length: model.tabs.length, vsync: this); //fix tab label 空白问题 + setState(() { + tabs = model.tabs; + travelTabModel = model; + }); + }).catchError((e) { + print(e); + }); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + Container( + color: Colors.white, + padding: EdgeInsets.only(top: 30), + child: TabBar( + controller: _controller, + isScrollable: true, + labelColor: Colors.black, + labelPadding: EdgeInsets.fromLTRB(20, 0, 10, 5), + indicator: UnderlineIndicator( + strokeCap: StrokeCap.round, + borderSide: BorderSide( + color: Color(0xff2fcfbb), + width: 3, + ), + insets: EdgeInsets.only(bottom: 10)), + tabs: tabs.map((TravelTab tab) { + return Tab( + text: tab.labelName, + ); + }).toList()), + ), + Flexible( + child: TabBarView( + controller: _controller, + children: tabs.map((TravelTab tab) { + return TravelTabPage( + travelUrl: travelTabModel.url, + params: travelTabModel.params, + groupChannelCode: tab.groupChannelCode, + ); + }).toList())), + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/pages/travel_tab_page.dart b/FlutterHelper/flutter_trip/lib/pages/travel_tab_page.dart new file mode 100644 index 00000000..7dfdc6eb --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/pages/travel_tab_page.dart @@ -0,0 +1,272 @@ +/** + * 《Flutter从入门到进阶-实战携程网App》 + * 课程地址: + * https://coding.imooc.com/class/321.html + * 课程代码、文档: + * https://git.imooc.com/coding-321/ + * 课程辅导答疑区: + * http://coding.imooc.com/learn/qa/321.html + */ +import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; +import 'package:flutter_trip/dao/travel_dao.dart'; +import 'package:flutter_trip/model/travel_model.dart'; +import 'package:flutter_trip/util/navigator_util.dart'; +import 'package:flutter_trip/widget/loading_container.dart'; +import 'package:flutter_trip/widget/webview.dart'; + +const _TRAVEL_URL = + 'https://m.ctrip.com/restapi/soa2/16189/json/searchTripShootListForHomePageV2?_fxpcqlniredt=09031014111431397988&__gw_appid=99999999&__gw_ver=1.0&__gw_from=10650013707&__gw_platform=H5'; + +const PAGE_SIZE = 10; + +class TravelTabPage extends StatefulWidget { + final String travelUrl; + final Map params; + final String groupChannelCode; + + const TravelTabPage( + {Key key, this.travelUrl, this.params, this.groupChannelCode}) + : super(key: key); + + @override + _TravelTabPageState createState() => _TravelTabPageState(); +} + +class _TravelTabPageState extends State + with AutomaticKeepAliveClientMixin { + List travelItems; + int pageIndex = 1; + bool _loading = true; + ScrollController _scrollController = ScrollController(); + + @override + void initState() { + _loadData(); + _scrollController.addListener(() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + _loadData(loadMore: true); + } + }); + super.initState(); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + super.build(context); + return Scaffold( + body: LoadingContainer( + isLoading: _loading, + child: RefreshIndicator( + onRefresh: _handleRefresh, + child: MediaQuery.removePadding( + removeTop: true, + context: context, + child: StaggeredGridView.countBuilder( + controller: _scrollController, + crossAxisCount: 4, + itemCount: travelItems?.length ?? 0, + itemBuilder: (BuildContext context, int index) => _TravelItem( + index: index, + item: travelItems[index], + ), + staggeredTileBuilder: (int index) => new StaggeredTile.fit(2), + )), + ), + ), + ); + } + + void _loadData({loadMore = false}) { + if (loadMore) { + pageIndex++; + } else { + pageIndex = 1; + } + + TravelDao.fetch(widget.travelUrl ?? _TRAVEL_URL, widget.params, + widget.groupChannelCode, pageIndex, PAGE_SIZE) + .then((TravelItemModel model) { + _loading = false; + setState(() { + List items = _filterItems(model.resultList); + if (travelItems != null) { + travelItems.addAll(items); + } else { + travelItems = items; + } + }); + }).catchError((e) { + _loading = false; + print(e); + }); + } + + List _filterItems(List resultList) { + if (resultList == null) { + return []; + } + List filterItems = []; + resultList.forEach((item) { + if (item.article != null) { + //移除article为空的模型 + filterItems.add(item); + } + }); + return filterItems; + } + + @override + bool get wantKeepAlive => true; + + Future _handleRefresh() async { + _loadData(); + return null; + } +} + +class _TravelItem extends StatelessWidget { + final TravelItem item; + final int index; + + const _TravelItem({Key key, this.item, this.index}) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + if (item.article.urls != null && item.article.urls.length > 0) { + NavigatorUtil.push( + context,WebView( + url: item.article.urls[0].h5Url, + title: '详情', + )); + } + }, + child: Card( + child: PhysicalModel( + color: Colors.transparent, + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.circular(5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _itemImage(), + Container( + padding: EdgeInsets.all(4), + child: Text( + item.article.articleTitle, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 14, color: Colors.black87), + ), + ), + _infoText() + ], + ), + ), + ), + ); + } + + _itemImage() { + return Stack( + children: [ + Image.network(item.article.images[0]?.dynamicUrl), + Positioned( + bottom: 8, + left: 8, + child: Container( + padding: EdgeInsets.fromLTRB(5, 1, 5, 1), + decoration: BoxDecoration( + color: Colors.black54, + borderRadius: BorderRadius.circular(10)), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 3), + child: Icon( + Icons.location_on, + color: Colors.white, + size: 12, + )), + LimitedBox( + maxWidth: 130, + child: Text( + _poiName(), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ) + ], + ), + )) + ], + ); + } + + String _poiName() { + return item.article.pois == null || item.article.pois.length == 0 + ? '未知' + : item.article.pois[0]?.poiName ?? '未知'; + } + + _infoText() { + return Container( + padding: EdgeInsets.fromLTRB(6, 0, 6, 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + PhysicalModel( + color: Colors.transparent, + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.circular(12), + child: Image.network( + item.article.author?.coverImage?.dynamicUrl, + width: 24, + height: 24, + ), + ), + Container( + padding: EdgeInsets.all(5), + width: 90, + child: Text( + item.article.author?.nickName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 12), + ), + ) + ], + ), + Row( + children: [ + Icon( + Icons.thumb_up, + size: 14, + color: Colors.grey, + ), + Padding( + padding: EdgeInsets.only(left: 3), + child: Text( + item.article.likeCount.toString(), + style: TextStyle(fontSize: 10), + ), + ) + ], + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/plugin/asr_manager.dart b/FlutterHelper/flutter_trip/lib/plugin/asr_manager.dart new file mode 100644 index 00000000..112e09ad --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/plugin/asr_manager.dart @@ -0,0 +1,20 @@ +import 'package:flutter/services.dart'; + +class AsrManager { + static const MethodChannel _channel = const MethodChannel('asr_plugin'); + + ///开始录音 + static Future start({Map params}) async { + return await _channel.invokeMethod('start', params ?? {}); + } + + ///停止录音 + static Future stop() async { + return await _channel.invokeMethod('stop'); + } + + ///取消录音 + static Future cancel() async { + return await _channel.invokeMethod('cancel'); + } +} diff --git a/FlutterHelper/flutter_trip/lib/util/navigator_util.dart b/FlutterHelper/flutter_trip/lib/util/navigator_util.dart new file mode 100644 index 00000000..27c731cb --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/util/navigator_util.dart @@ -0,0 +1,9 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class NavigatorUtil { + ///跳转到指定页面 + static push(BuildContext context, Widget page) { + Navigator.push(context, MaterialPageRoute(builder: (context) => page)); + } +} diff --git a/FlutterHelper/flutter_trip/lib/widget/grid_nav.dart b/FlutterHelper/flutter_trip/lib/widget/grid_nav.dart new file mode 100644 index 00000000..156d420c --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/widget/grid_nav.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_trip/model/common_model.dart'; +import 'package:flutter_trip/model/grid_nav_model.dart'; +import 'package:flutter_trip/util/navigator_util.dart'; +import 'package:flutter_trip/widget/webview.dart'; + +///网格卡片 +class GridNav extends StatelessWidget { + final GridNavModel gridNavModel; + + const GridNav({Key key, @required this.gridNavModel}) : super(key: key); + + @override + Widget build(BuildContext context) { + return PhysicalModel( + color: Colors.transparent, + borderRadius: BorderRadius.circular(6), + clipBehavior: Clip.antiAlias, + child: Column( + children: _gridNavItems(context), + ), + ); + } + + _gridNavItems(BuildContext context) { + List items = []; + if (gridNavModel == null) return items; + if (gridNavModel.hotel != null) { + items.add(_gridNavItem(context, gridNavModel.hotel, true)); + } + if (gridNavModel.flight != null) { + items.add(_gridNavItem(context, gridNavModel.flight, false)); + } + if (gridNavModel.travel != null) { + items.add(_gridNavItem(context, gridNavModel.travel, false)); + } + return items; + } + + _gridNavItem(BuildContext context, GridNavItem gridNavItem, bool first) { + List items = []; + items.add(_mainItem(context, gridNavItem.mainItem)); + items.add(_doubleItem(context, gridNavItem.item1, gridNavItem.item2)); + items.add(_doubleItem(context, gridNavItem.item3, gridNavItem.item4)); + List expandItems = []; + items.forEach((item) { + expandItems.add(Expanded(child: item, flex: 1)); + }); + Color startColor = Color(int.parse('0xff' + gridNavItem.startColor)); + Color endColor = Color(int.parse('0xff' + gridNavItem.endColor)); + return Container( + height: 88, + margin: first ? null : EdgeInsets.only(top: 3), + decoration: BoxDecoration( + //线性渐变 + gradient: LinearGradient(colors: [startColor, endColor])), + child: Row(children: expandItems), + ); + } + + _mainItem(BuildContext context, CommonModel model) { + return _wrapGesture( + context, + Stack( + alignment: AlignmentDirectional.topCenter, + children: [ + Image.network( + model.icon, + fit: BoxFit.contain, + height: 88, + width: 121, + alignment: AlignmentDirectional.bottomEnd, + ), + Container( + margin: EdgeInsets.only(top: 11), + child: Text( + model.title, + style: TextStyle(fontSize: 14, color: Colors.white), + ), + ) + ], + ), + model); + } + + _doubleItem( + BuildContext context, CommonModel topItem, CommonModel bottomItem) { + return Column( + children: [ + Expanded( + child: _item(context, topItem, true), + ), + Expanded( + child: _item(context, bottomItem, false), + ) + ], + ); + } + + _item(BuildContext context, CommonModel item, bool first) { + BorderSide borderSide = BorderSide(width: 0.8, color: Colors.white); + return FractionallySizedBox( + //撑满父布局的宽度 + widthFactor: 1, + child: Container( + decoration: BoxDecoration( + border: Border( + left: borderSide, + bottom: first ? borderSide : BorderSide.none, + )), + child: _wrapGesture( + context, + Center( + child: Text( + item.title, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 14, color: Colors.white), + ), + ), + item), + ), + ); + } + + _wrapGesture(BuildContext context, Widget widget, CommonModel model) { + return GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: model.url, + statusBarColor: model.statusBarColor, + title: model.title, + hideAppBar: model.hideAppBar, + )); + }, + child: widget, + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/widget/loading_container.dart b/FlutterHelper/flutter_trip/lib/widget/loading_container.dart new file mode 100644 index 00000000..40e6eb0e --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/widget/loading_container.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +///加载进度条组件 +class LoadingContainer extends StatelessWidget { + final Widget child; + final bool isLoading; + final bool cover; + + const LoadingContainer( + {Key key, + @required this.isLoading, + this.cover = false, + @required this.child}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return !cover + ? !isLoading ? child : _loadingView + : Stack( + children: [child, isLoading ? _loadingView : Container()], + ); + } + + Widget get _loadingView { + return Center( + child: CircularProgressIndicator(), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/widget/local_nav.dart b/FlutterHelper/flutter_trip/lib/widget/local_nav.dart new file mode 100644 index 00000000..5ee5914e --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/widget/local_nav.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_trip/model/common_model.dart'; +import 'package:flutter_trip/util/navigator_util.dart'; +import 'package:flutter_trip/widget/webview.dart'; + +class LocalNav extends StatelessWidget { + final List localNavList; + + const LocalNav({Key key, @required this.localNavList}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: 64, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(6), + ), + ), + child: Padding( + padding: EdgeInsets.all(7), + child: _items(context), + ), + ); + } + + _items(BuildContext context) { + if (localNavList == null) return null; + List items = []; + localNavList.forEach((model) { + items.add(_item(context, model)); + }); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: items, + ); + } + + Widget _item(BuildContext context, CommonModel model) { + return GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: model.url, + statusBarColor: model.statusBarColor, + hideAppBar: model.hideAppBar, + )); + }, + child: Column( + children: [ + Image.network( + model.icon, + width: 32, + height: 32, + ), + Text( + model.title, + style: TextStyle(fontSize: 12), + ) + ], + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/widget/sales_box.dart b/FlutterHelper/flutter_trip/lib/widget/sales_box.dart new file mode 100644 index 00000000..7c6e1706 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/widget/sales_box.dart @@ -0,0 +1,126 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_trip/model/common_model.dart'; +import 'package:flutter_trip/model/sales_box_model.dart'; +import 'package:flutter_trip/util/navigator_util.dart'; +import 'package:flutter_trip/widget/webview.dart'; + +///底部卡片入口 +class SalesBox extends StatelessWidget { + final SalesBoxModel salesBox; + + const SalesBox({Key key, @required this.salesBox}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + ), + child: _items(context), + ); + } + + _items(BuildContext context) { + if (salesBox == null) return null; + List items = []; + items.add(_doubleItem( + context, salesBox.bigCard1, salesBox.bigCard2, true, false)); + items.add(_doubleItem( + context, salesBox.smallCard1, salesBox.smallCard2, false, false)); + items.add(_doubleItem( + context, salesBox.smallCard3, salesBox.smallCard4, false, true)); + + return Column( + children: [ + Container( + height: 44, + margin: EdgeInsets.only(left: 10), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide(width: 1, color: Color(0xfff2f2f2)))), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Image.network(salesBox.icon, height: 15, fit: BoxFit.fill), + Container( + padding: EdgeInsets.fromLTRB(10, 1, 8, 1), + margin: EdgeInsets.only(right: 7), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + gradient: LinearGradient( + colors: [ + Color(0xffff4e63), + Color(0xffff6cc9), + ], + begin: Alignment.centerLeft, + end: Alignment.centerRight)), + child: GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView(url: salesBox.moreUrl, title: '更多活动'), + ); + }, + child: Text( + '获取更多福利 >', + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + ) + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: items.sublist(0, 1), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: items.sublist(1, 2), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: items.sublist(2, 3), + ) + ], + ); + } + + Widget _doubleItem(BuildContext context, CommonModel leftCard, + CommonModel rightCard, bool big, bool last) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _item(context, leftCard, big, true, last), + _item(context, rightCard, big, false, last) + ], + ); + } + + Widget _item( + BuildContext context, CommonModel model, bool big, bool left, bool last) { + BorderSide borderSide = BorderSide(width: 0.8, color: Color(0xfff2f2f2)); + return GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: model.url, + statusBarColor: model.statusBarColor, + hideAppBar: model.hideAppBar, + )); + }, + child: Container( + decoration: BoxDecoration( + border: Border( + right: left ? borderSide : BorderSide.none, + bottom: last ? BorderSide.none : borderSide)), + child: Image.network( + model.icon, + fit: BoxFit.fill, + width: MediaQuery.of(context).size.width / 2 - 10, + height: big ? 129 : 80, + ), + )); + } +} diff --git a/FlutterHelper/flutter_trip/lib/widget/search_bar.dart b/FlutterHelper/flutter_trip/lib/widget/search_bar.dart new file mode 100644 index 00000000..168172aa --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/widget/search_bar.dart @@ -0,0 +1,230 @@ +import 'package:flutter/material.dart'; + +enum SearchBarType { home, normal, homeLight } + +class SearchBar extends StatefulWidget { + final bool enabled; + final bool hideLeft; + final SearchBarType searchBarType; + final String hint; + final String defaultText; + final void Function() leftButtonClick; + final void Function() rightButtonClick; + final void Function() speakClick; + final void Function() inputBoxClick; + final ValueChanged onChanged; + + const SearchBar( + {Key key, + this.enabled = true, + this.hideLeft, + this.searchBarType = SearchBarType.normal, + this.hint, + this.defaultText, + this.leftButtonClick, + this.rightButtonClick, + this.speakClick, + this.inputBoxClick, + this.onChanged}) + : super(key: key); + + @override + _SearchBarState createState() => _SearchBarState(); +} + +class _SearchBarState extends State { + bool showClear = false; + final TextEditingController _controller = TextEditingController(); + + @override + void initState() { + if (widget.defaultText != null) { + setState(() { + _controller.text = widget.defaultText; + }); + } + super.initState(); + } + + @override + Widget build(BuildContext context) { + return widget.searchBarType == SearchBarType.normal + ? _genNormalSearch() + : _genHomeSearch(); + } + + _genNormalSearch() { + return Container( + child: Row(children: [ + _wrapTap( + Container( + padding: EdgeInsets.fromLTRB(6, 5, 10, 5), + child: widget?.hideLeft ?? false + ? null + : Icon( + Icons.arrow_back_ios, + color: Colors.grey, + size: 26, + ), + ), + widget.leftButtonClick), + Expanded( + flex: 1, + child: _inputBox(), + ), + _wrapTap( + Container( + padding: EdgeInsets.fromLTRB(10, 5, 10, 5), + child: Text( + '搜索', + style: TextStyle(color: Colors.blue, fontSize: 17), + ), + ), + widget.rightButtonClick) + ]), + ); + } + + _genHomeSearch() { + return Container( + child: Row(children: [ + _wrapTap( + Container( + padding: EdgeInsets.fromLTRB(6, 5, 5, 5), + child: Row( + children: [ + Text( + '上海', + style: TextStyle(color: _homeFontColor(), fontSize: 14), + ), + Icon( + Icons.expand_more, + color: _homeFontColor(), + size: 22, + ) + ], + )), + widget.leftButtonClick), + Expanded( + flex: 1, + child: _inputBox(), + ), + _wrapTap( + Container( + padding: EdgeInsets.fromLTRB(10, 5, 10, 5), + child: Icon( + Icons.comment, + color: _homeFontColor(), + size: 26, + ), + ), + widget.rightButtonClick) + ]), + ); + } + + _inputBox() { + Color inputBoxColor; + if (widget.searchBarType == SearchBarType.home) { + inputBoxColor = Colors.white; + } else { + inputBoxColor = Color(int.parse('0xffEDEDED')); + } + return Container( + height: 30, + padding: EdgeInsets.fromLTRB(10, 0, 10, 0), + decoration: BoxDecoration( + color: inputBoxColor, + borderRadius: BorderRadius.circular( + widget.searchBarType == SearchBarType.normal ? 5 : 15)), + child: Row( + children: [ + Icon( + Icons.search, + size: 20, + color: widget.searchBarType == SearchBarType.normal + ? Color(0xffA9A9A9) + : Colors.blue, + ), + Expanded( + flex: 1, + child: widget.searchBarType == SearchBarType.normal + ? TextField( + controller: _controller, + onChanged: _onChanged, + autofocus: true, + style: TextStyle( + fontSize: 18.0, + color: Colors.black, + fontWeight: FontWeight.w300), + //输入文本的样式 + decoration: InputDecoration( + contentPadding: EdgeInsets.fromLTRB(5, 0, 5, 0), + border: InputBorder.none, + hintText: widget.hint ?? '', + hintStyle: TextStyle(fontSize: 15), + )) + : _wrapTap( + Container( + child: Text( + widget.defaultText, + style: TextStyle(fontSize: 13, color: Colors.grey), + ), + ), + widget.inputBoxClick)), + !showClear + ? _wrapTap( + Icon( + Icons.mic, + size: 22, + color: widget.searchBarType == SearchBarType.normal + ? Colors.blue + : Colors.grey, + ), + widget.speakClick) + : _wrapTap( + Icon( + Icons.clear, + size: 22, + color: Colors.grey, + ), () { + setState(() { + _controller.clear(); + }); + _onChanged(''); + }) + ], + ), + ); + } + + _wrapTap(Widget child, void Function() callback) { + return GestureDetector( + onTap: () { + if (callback != null) callback(); + }, + child: child, + ); + } + + _onChanged(String text) { + if (text.length > 0) { + setState(() { + showClear = true; + }); + } else { + setState(() { + showClear = false; + }); + } + if (widget.onChanged != null) { + widget.onChanged(text); + } + } + + _homeFontColor() { + return widget.searchBarType == SearchBarType.homeLight + ? Colors.black54 + : Colors.white; + } +} diff --git a/FlutterHelper/flutter_trip/lib/widget/sub_nav.dart b/FlutterHelper/flutter_trip/lib/widget/sub_nav.dart new file mode 100644 index 00000000..90c06f62 --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/widget/sub_nav.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_trip/model/common_model.dart'; +import 'package:flutter_trip/util/navigator_util.dart'; +import 'package:flutter_trip/widget/webview.dart'; + +///活动入口 +class SubNav extends StatelessWidget { + final List subNavList; + + const SubNav({Key key, @required this.subNavList}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(6), + ), + child: Padding( + padding: EdgeInsets.all(7), + child: _items(context), + ), + ); + } + + _items(BuildContext context) { + if (subNavList == null) return null; + List items = []; + subNavList.forEach((model) { + items.add(_item(context, model)); + }); + //计算出第一行显示的数量 + int separate = (subNavList.length / 2 + 0.5).toInt(); + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: items.sublist(0, separate), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: items.sublist(separate, subNavList.length), + ), + ) + ], + ); + } + + Widget _item(BuildContext context, CommonModel model) { + return Expanded( + flex: 1, + child: GestureDetector( + onTap: () { + NavigatorUtil.push( + context, + WebView( + url: model.url, + statusBarColor: model.statusBarColor, + hideAppBar: model.hideAppBar, + )); + }, + child: Column( + children: [ + Image.network( + model.icon, + width: 18, + height: 18, + ), + Padding( + padding: EdgeInsets.only(top: 3), + child: Text( + model.title, + style: TextStyle(fontSize: 12), + ), + ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/lib/widget/webview.dart b/FlutterHelper/flutter_trip/lib/widget/webview.dart new file mode 100644 index 00000000..2b5eae4d --- /dev/null +++ b/FlutterHelper/flutter_trip/lib/widget/webview.dart @@ -0,0 +1,161 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; + +const CATCH_URLS = ['m.ctrip.com/', 'm.ctrip.com/html5/', 'm.ctrip.com/html5']; + +class WebView extends StatefulWidget { + String url; + final String statusBarColor; + final String title; + final bool hideAppBar; + final bool backForbid; + + WebView( + {this.url, + this.statusBarColor, + this.title, + this.hideAppBar, + this.backForbid = false}) { + if (url != null && url.contains('ctrip.com')) { + //fix 携程H5 http://无法打开问题 + url = url.replaceAll("http://", 'https://'); + } + } + + @override + _WebViewState createState() => _WebViewState(); +} + +class _WebViewState extends State { + final webviewReference = FlutterWebviewPlugin(); + StreamSubscription _onUrlChanged; + StreamSubscription _onStateChanged; + StreamSubscription _onHttpError; + bool exiting = false; + + @override + void initState() { + super.initState(); + webviewReference.close(); + _onUrlChanged = webviewReference.onUrlChanged.listen((String url) {}); + _onStateChanged = + webviewReference.onStateChanged.listen((WebViewStateChanged state) { + switch (state.type) { + case WebViewState.startLoad: + if (_isToMain(state.url) && !exiting) { + if (widget.backForbid) { + webviewReference.launch(widget.url); + } else { + Navigator.pop(context); + exiting = true; + } + } + break; + default: + break; + } + }); + _onHttpError = + webviewReference.onHttpError.listen((WebViewHttpError error) { + print(error); + }); + } + + _isToMain(String url) { + bool contain = false; + for (final value in CATCH_URLS) { + if (url?.endsWith(value) ?? false) { + contain = true; + break; + } + } + return contain; + } + + @override + void dispose() { + _onStateChanged.cancel(); + _onUrlChanged.cancel(); + _onHttpError.cancel(); + webviewReference.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + String statusBarColorStr = widget.statusBarColor ?? 'ffffff'; + Color backButtonColor; + if (statusBarColorStr == 'ffffff') { + backButtonColor = Colors.black; + } else { + backButtonColor = Colors.white; + } + return Scaffold( + body: Column( + children: [ + _appBar( + Color(int.parse('0xff' + statusBarColorStr)), backButtonColor), + Expanded( + child: WebviewScaffold( + userAgent: 'null',//防止携程H5页面重定向到打开携程APP ctrip://wireless/xxx的网址 + url: widget.url, + withZoom: true, + withLocalStorage: true, + hidden: true, + initialChild: Container( + color: Colors.white, + child: Center( + child: Text('Waiting...'), + ), + ), + )) + ], + ), + ); + } + + _appBar(Color backgroundColor, Color backButtonColor) { + if (widget.hideAppBar ?? false) { + return Container( + color: backgroundColor, + height: 30, + ); + } + return Container( + color: backgroundColor, + padding: EdgeInsets.fromLTRB(0, 40, 0, 10), + child: FractionallySizedBox( + widthFactor: 1, + child: Stack( + children: [ + GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + margin: EdgeInsets.only(left: 10), + child: Icon( + Icons.close, + color: backButtonColor, + size: 26, + ), + ), + ), + Positioned( + left: 0, + right: 0, + child: Center( + child: Text( + widget.title ?? '', + style: TextStyle(color: backButtonColor, fontSize: 20), + ), + ), + ) + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/flutter_trip/pubspec.yaml b/FlutterHelper/flutter_trip/pubspec.yaml new file mode 100644 index 00000000..61d6c4af --- /dev/null +++ b/FlutterHelper/flutter_trip/pubspec.yaml @@ -0,0 +1,84 @@ +name: flutter_trip +description: A new Flutter application. + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# Read more about versioning at semver.org. +version: 1.0.0+1 + +environment: + sdk: ">=2.1.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^0.1.2 + flutter_swiper: ^1.1.4 + http: ^0.12.0+1 + flutter_webview_plugin: ^0.3.5 + flutter_staggered_grid_view: ^0.3.0 + underline_indicator: ^0.0.2 + flutter_splash_screen: ^0.1.0 +dev_dependencies: + flutter_test: + sdk: flutter + + +# For information on the generic Dart part of this file, see the +# following page: https://www.dartlang.org/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - images/type_channelplane.png + - images/type_district.png + - images/type_food.png + - images/type_hotel.png + - images/type_huodong.png + - images/type_shop.png + - images/type_sight.png + - images/type_ticket.png + - images/type_travelgroup.png + - images/type_channelgroup.png + - images/type_channelgs.png + - images/type_channeltrain.png + - images/type_cruise.png + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.io/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.io/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.io/custom-fonts/#from-packages diff --git a/FlutterHelper/flutter_trip/test/widget_test.dart b/FlutterHelper/flutter_trip/test/widget_test.dart new file mode 100644 index 00000000..e6522904 --- /dev/null +++ b/FlutterHelper/flutter_trip/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_trip/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/FlutterHelper/ninghao_flutter-master/.gitignore b/FlutterHelper/ninghao_flutter-master/.gitignore new file mode 100644 index 00000000..dee655cc --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ + +build/ + +.flutter-plugins diff --git a/FlutterHelper/ninghao_flutter-master/.idea/codeStyles/Project.xml b/FlutterHelper/ninghao_flutter-master/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..30aa626c --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/FlutterHelper/ninghao_flutter-master/.idea/inspectionProfiles/Project_Default.xml similarity index 100% rename from .idea/inspectionProfiles/Project_Default.xml rename to FlutterHelper/ninghao_flutter-master/.idea/inspectionProfiles/Project_Default.xml diff --git a/FlutterHelper/ninghao_flutter-master/.idea/libraries/Dart_Packages.xml b/FlutterHelper/ninghao_flutter-master/.idea/libraries/Dart_Packages.xml new file mode 100644 index 00000000..40ed6700 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/libraries/Dart_Packages.xml @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/.idea/libraries/Dart_SDK.xml b/FlutterHelper/ninghao_flutter-master/.idea/libraries/Dart_SDK.xml new file mode 100644 index 00000000..3d881b94 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/libraries/Dart_SDK.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/.idea/libraries/Flutter_Plugins.xml b/FlutterHelper/ninghao_flutter-master/.idea/libraries/Flutter_Plugins.xml new file mode 100644 index 00000000..b0f69711 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/libraries/Flutter_Plugins.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/.idea/libraries/Flutter_for_Android.xml b/FlutterHelper/ninghao_flutter-master/.idea/libraries/Flutter_for_Android.xml new file mode 100644 index 00000000..54548d9d --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/libraries/Flutter_for_Android.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/FlutterHelper/ninghao_flutter-master/.idea/misc.xml b/FlutterHelper/ninghao_flutter-master/.idea/misc.xml new file mode 100644 index 00000000..f6d2d510 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/misc.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/.idea/modules.xml b/FlutterHelper/ninghao_flutter-master/.idea/modules.xml new file mode 100644 index 00000000..192b704d --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/runConfigurations.xml b/FlutterHelper/ninghao_flutter-master/.idea/runConfigurations.xml similarity index 100% rename from .idea/runConfigurations.xml rename to FlutterHelper/ninghao_flutter-master/.idea/runConfigurations.xml diff --git a/FlutterHelper/ninghao_flutter-master/.idea/runConfigurations/main_dart.xml b/FlutterHelper/ninghao_flutter-master/.idea/runConfigurations/main_dart.xml new file mode 100644 index 00000000..aab7b5cd --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/runConfigurations/main_dart.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/cpp/demo/.idea/vcs.xml b/FlutterHelper/ninghao_flutter-master/.idea/vcs.xml similarity index 100% rename from cpp/demo/.idea/vcs.xml rename to FlutterHelper/ninghao_flutter-master/.idea/vcs.xml diff --git a/FlutterHelper/ninghao_flutter-master/.idea/workspace.xml b/FlutterHelper/ninghao_flutter-master/.idea/workspace.xml new file mode 100644 index 00000000..60be9c8d --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.idea/workspace.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1533729618709 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/.metadata b/FlutterHelper/ninghao_flutter-master/.metadata new file mode 100644 index 00000000..c4204e56 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.metadata @@ -0,0 +1,8 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 66091f969653fd3535b265ddcd87436901858a1d + channel: dev diff --git a/FlutterHelper/ninghao_flutter-master/.vscode/launch.json b/FlutterHelper/ninghao_flutter-master/.vscode/launch.json new file mode 100644 index 00000000..18135079 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/README.md b/FlutterHelper/ninghao_flutter-master/README.md new file mode 100644 index 00000000..3390f74c --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/README.md @@ -0,0 +1,9 @@ +IT教程吧 - www.itjc8.com +# ninghao_flutter + +A new Flutter project. + +## Getting Started + +For help getting started with Flutter, view our online +[documentation](https://flutter.io/). diff --git a/FlutterHelper/ninghao_flutter-master/android/.gitignore b/FlutterHelper/ninghao_flutter-master/android/.gitignore new file mode 100644 index 00000000..65b7315a --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/.gitignore @@ -0,0 +1,10 @@ +*.iml +*.class +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +GeneratedPluginRegistrant.java diff --git a/FlutterHelper/ninghao_flutter-master/android/app/build.gradle b/FlutterHelper/ninghao_flutter-master/android/app/build.gradle new file mode 100644 index 00000000..3924119a --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/app/build.gradle @@ -0,0 +1,61 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + throw new GradleException("versionCode not found. Define flutter.versionCode in the local.properties file.") +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + throw new GradleException("versionName not found. Define flutter.versionName in the local.properties file.") +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 27 + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.ninghaoflutter" + minSdkVersion 16 + targetSdkVersion 27 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' +} diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/AndroidManifest.xml b/FlutterHelper/ninghao_flutter-master/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..5f9d92cf --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/java/com/example/ninghaoflutter/MainActivity.java b/FlutterHelper/ninghao_flutter-master/android/app/src/main/java/com/example/ninghaoflutter/MainActivity.java new file mode 100644 index 00000000..7bc1876a --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/app/src/main/java/com/example/ninghaoflutter/MainActivity.java @@ -0,0 +1,13 @@ +package com.example.ninghaoflutter; + +import android.os.Bundle; +import io.flutter.app.FlutterActivity; +import io.flutter.plugins.GeneratedPluginRegistrant; + +public class MainActivity extends FlutterActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GeneratedPluginRegistrant.registerWith(this); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/drawable/launch_background.xml b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..db77bb4b Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..17987b79 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..09d43914 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..d5f1c8d3 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..4d6372ee Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/values/styles.xml b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..00fa4417 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/FlutterHelper/ninghao_flutter-master/android/build.gradle b/FlutterHelper/ninghao_flutter-master/android/build.gradle new file mode 100644 index 00000000..d4225c79 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.1.2' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/FlutterHelper/ninghao_flutter-master/android/gradle.properties b/FlutterHelper/ninghao_flutter-master/android/gradle.properties new file mode 100644 index 00000000..8bd86f68 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/FlutterHelper/ninghao_flutter-master/android/gradle/wrapper/gradle-wrapper.jar b/FlutterHelper/ninghao_flutter-master/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..13372aef Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/FlutterHelper/ninghao_flutter-master/android/gradle/wrapper/gradle-wrapper.properties b/FlutterHelper/ninghao_flutter-master/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..9372d0f3 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/FlutterHelper/ninghao_flutter-master/android/gradlew b/FlutterHelper/ninghao_flutter-master/android/gradlew new file mode 100644 index 00000000..9d82f789 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/FlutterHelper/ninghao_flutter-master/android/gradlew.bat b/FlutterHelper/ninghao_flutter-master/android/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/FlutterHelper/ninghao_flutter-master/android/settings.gradle b/FlutterHelper/ninghao_flutter-master/android/settings.gradle new file mode 100644 index 00000000..5a2f14fb --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/FlutterHelper/ninghao_flutter-master/ios/.gitignore b/FlutterHelper/ninghao_flutter-master/ios/.gitignore new file mode 100644 index 00000000..79cc4da8 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/.gitignore @@ -0,0 +1,45 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/app.flx +/Flutter/app.zip +/Flutter/flutter_assets/ +/Flutter/App.framework +/Flutter/Flutter.framework +/Flutter/Generated.xcconfig +/ServiceDefinitions.json + +Pods/ +.symlinks/ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Flutter/AppFrameworkInfo.plist b/FlutterHelper/ninghao_flutter-master/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..9367d483 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Flutter/Debug.xcconfig b/FlutterHelper/ninghao_flutter-master/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..592ceee8 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/FlutterHelper/ninghao_flutter-master/ios/Flutter/Release.xcconfig b/FlutterHelper/ninghao_flutter-master/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..592ceee8 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/FlutterHelper/ninghao_flutter-master/ios/Flutter/flutter_export_environment.sh b/FlutterHelper/ninghao_flutter-master/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 00000000..f59f0674 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Users/flannery/Library/Android/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/flannery/Desktop/AndroidHelper/FlutterHelper/ninghao_flutter-master" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build/ios" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=false" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.packages" diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.pbxproj b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..5b245582 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,438 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; + 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0910; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.ninghaoFlutter; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.ninghaoFlutter; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..1263ac84 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner.xcworkspace/contents.xcworkspacedata b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1d526a16 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..949b6789 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + BuildSystemType + Original + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/AppDelegate.h b/FlutterHelper/ninghao_flutter-master/ios/Runner/AppDelegate.h new file mode 100644 index 00000000..36e21bbf --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/AppDelegate.m b/FlutterHelper/ninghao_flutter-master/ios/Runner/AppDelegate.m new file mode 100644 index 00000000..59a72e90 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/AppDelegate.m @@ -0,0 +1,13 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + // Override point for customization after application launch. + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 00000000..3d43d11e Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..28c6bf03 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..2ccbfd96 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..f091b6b0 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..4cde1211 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..d0ef06e7 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..dcdc2306 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..2ccbfd96 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..c8f9ed8f Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..a6d6b860 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..a6d6b860 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..75b2d164 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..c4df70d3 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..6a84f41e Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..d0e1f585 Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 00000000..9da19eac Binary files /dev/null and b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Base.lproj/LaunchScreen.storyboard b/FlutterHelper/ninghao_flutter-master/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Base.lproj/Main.storyboard b/FlutterHelper/ninghao_flutter-master/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/Info.plist b/FlutterHelper/ninghao_flutter-master/ios/Runner/Info.plist new file mode 100644 index 00000000..e27043f5 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ninghao_flutter + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CFBundleLocalizations + + en + zh_CN + + + diff --git a/FlutterHelper/ninghao_flutter-master/ios/Runner/main.m b/FlutterHelper/ninghao_flutter-master/ios/Runner/main.m new file mode 100644 index 00000000..dff6597e --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/ios/Runner/main.m @@ -0,0 +1,9 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/alert_dialog_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/alert_dialog_demo.dart new file mode 100644 index 00000000..9b89040c --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/alert_dialog_demo.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; + +enum Action { + Ok, + Cancel +} + +class AlertDialogDemo extends StatefulWidget { + @override + _AlertDialogDemoState createState() => _AlertDialogDemoState(); +} + +class _AlertDialogDemoState extends State { + String _choice = 'Nothing'; + + Future _openAlertDialog() async { + final action = await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: Text('AlertDialog'), + content: Text('Are you sure about this?'), + actions: [ + FlatButton( + child: Text('Cancel'), + onPressed: () { + Navigator.pop(context, Action.Cancel); + }, + ), + FlatButton( + child: Text('Ok'), + onPressed: () { + Navigator.pop(context, Action.Ok); + }, + ), + ], + ); + }, + ); + + switch (action) { + case Action.Ok: + setState(() { + _choice = 'Ok'; + }); + break; + case Action.Cancel: + setState(() { + _choice = 'Cancel'; + }); + break; + default: + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('AlertDialogDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Your choice is: $_choice'), + SizedBox(height: 16.0,), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RaisedButton( + child: Text('Open AlertDialog'), + onPressed: _openAlertDialog, + ), + ], + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/animation/animation_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/animation/animation_demo.dart new file mode 100644 index 00000000..41020f88 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/animation/animation_demo.dart @@ -0,0 +1,105 @@ +import 'package:flutter/material.dart'; + +class AnimationDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('AnimationDemo'), + elevation: 0.0, + ), + body: AnimationDemoHome()); + } +} + +class AnimationDemoHome extends StatefulWidget { + @override + _AnimationDemoHomeState createState() => _AnimationDemoHomeState(); +} + +class _AnimationDemoHomeState extends State + with TickerProviderStateMixin { + AnimationController animationDemoController; + Animation animation; + Animation animationColor; + CurvedAnimation curve; + + @override + void initState() { + super.initState(); + + animationDemoController = AnimationController( + // value: 32.0, + // lowerBound: 32.0, + // upperBound: 100.0, + duration: Duration(milliseconds: 1000), + vsync: this, + ); + + curve = CurvedAnimation( + parent: animationDemoController, curve: Curves.bounceOut); + + animation = Tween(begin: 32.0, end: 100.0).animate(curve); + animationColor = + ColorTween(begin: Colors.red, end: Colors.red[900]).animate(curve); + + // animationDemoController.addListener(() { + // // print('${animationDemoController.value}'); + // setState(() {}); + // }); + + animationDemoController.addStatusListener((AnimationStatus status) { + print(status); + }); + + // animationDemoController.forward(); + } + + @override + void dispose() { + super.dispose(); + + animationDemoController.dispose(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: AnimatedHeart( + animations: [ + animation, + animationColor, + ], + controller: animationDemoController, + ), + ); + } +} + +class AnimatedHeart extends AnimatedWidget { + final List animations; + final AnimationController controller; + + AnimatedHeart({ + this.animations, + this.controller, + }) : super(listenable: controller); + + @override + Widget build(BuildContext context) { + return IconButton( + icon: Icon(Icons.favorite), + iconSize: animations[0].value, + color: animations[1].value, + onPressed: () { + switch (controller.status) { + case AnimationStatus.completed: + controller.reverse(); + break; + default: + controller.forward(); + } + }, + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/basic_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/basic_demo.dart new file mode 100644 index 00000000..3703ace6 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/basic_demo.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; + +class BasicDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ContainerBoxDecorationDemo(); + } +} + +class ContainerBoxDecorationDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + // color: Colors.grey[100], + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage('https://resources.ninghao.org/images/say-hello-to-barry.jpg'), + alignment: Alignment.topCenter, + // repeat: ImageRepeat.repeatY, + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + Colors.indigoAccent[400].withOpacity(0.5), + BlendMode.hardLight, + ), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + child: Icon(Icons.pool, size: 32.0, color: Colors.white), + // color: Color.fromRGBO(3, 54, 255, 1.0), + padding: EdgeInsets.all(16.0), + margin: EdgeInsets.all(8.0), + width: 90.0, + height: 90.0, + decoration: BoxDecoration( + color: Color.fromRGBO(3, 54, 255, 1.0), + border: Border.all( + color: Colors.indigoAccent[100], + width: 3.0, + style: BorderStyle.solid, + ), + // borderRadius: BorderRadius.circular(16.0), + boxShadow: [ + BoxShadow( + offset: Offset(0.0, 16.0), + color: Color.fromRGBO(16, 20, 188, 1.0), + blurRadius: 25.0, + spreadRadius: -9.0, + ), + ], + shape: BoxShape.circle, + // gradient: RadialGradient( + // colors: [ + // Color.fromRGBO(7, 102, 255, 1.0), + // Color.fromRGBO(3, 28, 128, 1.0), + // ], + // ), + gradient: LinearGradient( + colors: [ + Color.fromRGBO(7, 102, 255, 1.0), + Color.fromRGBO(3, 28, 128, 1.0), + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ), + ), + ], + ), + ); + } +} + +class RichTextDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return RichText( + text: TextSpan( + text: 'ninghao', + style: TextStyle( + color: Colors.deepPurpleAccent, + fontSize: 34.0, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w100, + ), + children: [ + TextSpan( + text: '.net', + style: TextStyle( + fontSize: 17.0, + color: Colors.grey, + ), + ) + ], + ), + ); + } +} + +class TextDemo extends StatelessWidget { + final TextStyle _textStyle = TextStyle( + fontSize: 16.0, + ); + + final String _author = '李白'; + final String _title = '将进酒'; + + @override + Widget build(BuildContext context) { + // TODO: implement build + return Text( + '《 $_title 》—— $_author。君不见黄河之水天上来,奔流到海不复回。君不见高堂明镜悲白发,朝如青丝暮成雪。人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。烹羊宰牛且为乐,会须一饮三百杯。', + textAlign: TextAlign.left, + style: _textStyle, + maxLines: 3, + overflow: TextOverflow.ellipsis, + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/bloc/bloc_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/bloc/bloc_demo.dart new file mode 100644 index 00000000..d1d68a00 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/bloc/bloc_demo.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; +import 'package:ninghao_flutter/demo/bloc/counter_bloc_demo.dart'; + +class BlocDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return CounterProvider( + bloc: CounterBloc(), + child: Scaffold( + appBar: AppBar( + title: Text('BlocDemo'), + elevation: 0.0, + ), + body: CounterHome(), + floatingActionButton: CounterActionButton(), + ), + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/bloc/counter_bloc_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/bloc/counter_bloc_demo.dart new file mode 100644 index 00000000..4593282d --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/bloc/counter_bloc_demo.dart @@ -0,0 +1,88 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class CounterHome extends StatelessWidget { + @override + Widget build(BuildContext context) { + CounterBloc _counterBloc = CounterProvider.of(context).bloc; + + return Center( + child: StreamBuilder( + initialData: 0, + stream: _counterBloc.count, + builder: (context, snapshot) { + return ActionChip( + label: Text('${snapshot.data}'), + onPressed: () { + // _counterBloc.log(); + _counterBloc.counter.add(1); + }, + ); + }, + ), + ); + } +} + +class CounterActionButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + CounterBloc _counterBloc = CounterProvider.of(context).bloc; + + return FloatingActionButton( + child: Icon(Icons.add), + onPressed: () { + // _counterBloc.log(); + _counterBloc.counter.add(1); + }, + ); + } +} + +class CounterProvider extends InheritedWidget { + final Widget child; + final CounterBloc bloc; + + CounterProvider({ + this.child, + this.bloc, + }) : super(child: child); + + static CounterProvider of(BuildContext context) => + context.inheritFromWidgetOfExactType(CounterProvider); + + @override + bool updateShouldNotify(CounterProvider oldWidget) { + return true; + } +} + +class CounterBloc { + int _count = 0; + + final _counterActionController = StreamController(); + StreamSink get counter => _counterActionController.sink; + + final _counterController = StreamController(); + Stream get count => _counterController.stream; + + CounterBloc() { + _counterActionController.stream.listen(onData); + } + + void onData(int data) { + print('$data'); + _count = data + _count; + _counterController.add(_count); + } + + void disponse() { + _counterActionController.close(); + _counterController.close(); + } + + void log() { + print('BLoC'); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/bottom_navigation_bar_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/bottom_navigation_bar_demo.dart new file mode 100644 index 00000000..930e60b7 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/bottom_navigation_bar_demo.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; + +class BottomNavigationBarDemo extends StatefulWidget { + @override + State createState() { + // TODO: implement createState + return _BottomNavigationBarDemoState(); + } +} + +class _BottomNavigationBarDemoState extends State { + int _currentIndex = 0; + + void _onTapHandler (int index) { + setState(() { + _currentIndex = index; + }); + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + return BottomNavigationBar( + currentIndex: _currentIndex, + onTap: _onTapHandler, + type: BottomNavigationBarType.fixed, + fixedColor: Colors.black, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.explore), + title: Text('Explore'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.history), + title: Text('History'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.list), + title: Text('List'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.person), + title: Text('My'), + ), + ], + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/bottom_sheet_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/bottom_sheet_demo.dart new file mode 100644 index 00000000..77b1ff07 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/bottom_sheet_demo.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; + +class BottomSheetDemo extends StatefulWidget { + @override + _BottomSheetDemoState createState() => _BottomSheetDemoState(); +} + +class _BottomSheetDemoState extends State { + final _bottomSheetScaffoldKey = GlobalKey(); + + _openBottomSheet() { + _bottomSheetScaffoldKey + .currentState + .showBottomSheet((BuildContext context) { + return BottomAppBar( + child: Container( + height: 90.0, + width: double.infinity, + padding: EdgeInsets.all(16.0), + child: Row( + children: [ + Icon(Icons.pause_circle_outline), + SizedBox(width: 16.0,), + Text('01:30 / 03:30'), + Expanded( + child: Text('Fix you - Coldplay', textAlign: TextAlign.right,), + ), + ], + ), + ), + ); + }); + } + + Future _openModalBottomSheet() async { + final option = await showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return Container( + height: 200.0, + child: Column( + children: [ + ListTile( + title: Text('Option A'), + onTap: () { + Navigator.pop(context, 'A'); + }, + ), + ListTile( + title: Text('Option B'), + onTap: () { + Navigator.pop(context, 'B'); + }, + ), + ListTile( + title: Text('Option C'), + onTap: () { + Navigator.pop(context, 'C'); + }, + ), + ], + ), + ); + } + ); + + print(option); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _bottomSheetScaffoldKey, + appBar: AppBar( + title: Text('BottomSheetDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FlatButton( + child: Text('Open BottomSheet'), + onPressed: _openBottomSheet, + ), + FlatButton( + child: Text('Modal BottomSheet'), + onPressed: _openModalBottomSheet, + ), + ] + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/button_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/button_demo.dart new file mode 100644 index 00000000..19e89638 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/button_demo.dart @@ -0,0 +1,208 @@ +import 'package:flutter/material.dart'; + +class ButtonDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + final Widget flatButtonDemo = Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FlatButton( + child: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey, + textColor: Theme.of(context).accentColor, + ), + FlatButton.icon( + icon: Icon(Icons.add), + label: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey, + textColor: Theme.of(context).accentColor, + ), + ], + ); + + final Widget raisedButtonDemo = Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + buttonColor: Theme.of(context).accentColor, + buttonTheme: ButtonThemeData( + textTheme: ButtonTextTheme.primary, + // shape: BeveledRectangleBorder( + // borderRadius: BorderRadius.circular(5.0), + // ), + shape: StadiumBorder(), + ), + ), + child: RaisedButton( + child: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey, + elevation: 0.0, + // color: Theme.of(context).accentColor, + // textColor: Colors.white, + // textTheme: ButtonTextTheme.primary, + ), + ), + SizedBox(width: 16.0,), + RaisedButton.icon( + icon: Icon(Icons.add), + label: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey, + elevation: 12.0, + textColor: Theme.of(context).accentColor, + ), + ], + ); + + final Widget outlineButtonDemo = Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + buttonColor: Theme.of(context).accentColor, + buttonTheme: ButtonThemeData( + textTheme: ButtonTextTheme.primary, + // shape: BeveledRectangleBorder( + // borderRadius: BorderRadius.circular(5.0), + // ), + shape: StadiumBorder(), + ), + ), + child: OutlineButton( + child: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey[100], + borderSide: BorderSide( + color: Colors.black, + ), + // color: Theme.of(context).accentColor, + textColor: Colors.black, + highlightedBorderColor: Colors.grey, + // textTheme: ButtonTextTheme.primary, + ), + ), + SizedBox(width: 16.0,), + OutlineButton.icon( + icon: Icon(Icons.add), + label: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey, + textColor: Theme.of(context).accentColor, + ), + ], + ); + + final Widget fixedWidthButton = Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 130.0, + child: OutlineButton( + child: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey[100], + borderSide: BorderSide( + color: Colors.black, + ), + textColor: Colors.black, + highlightedBorderColor: Colors.grey, + ), + ), + ], + ); + + final Widget expandedButton = Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: OutlineButton( + child: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey[100], + borderSide: BorderSide( + color: Colors.black, + ), + textColor: Colors.black, + highlightedBorderColor: Colors.grey, + ), + ), + SizedBox(width: 16.0,), + Expanded( + flex: 2, + child: OutlineButton( + child: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey[100], + borderSide: BorderSide( + color: Colors.black, + ), + textColor: Colors.black, + highlightedBorderColor: Colors.grey, + ), + ), + ], + ); + + final Widget buttonBarDemo = Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + buttonTheme: ButtonThemeData( + padding: EdgeInsets.symmetric(horizontal: 32.0), + ), + ), + child: ButtonBar( + children: [ + OutlineButton( + child: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey[100], + borderSide: BorderSide( + color: Colors.black, + ), + textColor: Colors.black, + highlightedBorderColor: Colors.grey, + ), + OutlineButton( + child: Text('Button'), + onPressed: () {}, + splashColor: Colors.grey[100], + borderSide: BorderSide( + color: Colors.black, + ), + textColor: Colors.black, + highlightedBorderColor: Colors.grey, + ), + ], + ), + ), + ], + ); + + return Scaffold( + appBar: AppBar( + title: Text('ButtonDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + flatButtonDemo, + raisedButtonDemo, + outlineButtonDemo, + fixedWidthButton, + expandedButton, + buttonBarDemo, + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/card_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/card_demo.dart new file mode 100644 index 00000000..85da6258 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/card_demo.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import '../model/post.dart'; + +class CardDemo extends StatefulWidget { + @override + _CardDemoState createState() => _CardDemoState(); +} + +class _CardDemoState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('CardDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: ListView( + children: posts.map((post) { + return Card( + child: Column( + children: [ + AspectRatio( + aspectRatio: 16/9, + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(4.0), + topRight: Radius.circular(4.0), + ), + child: Image.network( + post.imageUrl, + fit: BoxFit.cover, + ), + ), + ), + ListTile( + leading: CircleAvatar( + backgroundImage: NetworkImage(post.imageUrl), + ), + title: Text(post.title), + subtitle: Text(post.author), + ), + Container( + padding: EdgeInsets.all(16.0), + child: Text(post.description, maxLines: 2, overflow: TextOverflow.ellipsis,), + ), + ButtonTheme.bar( + child: ButtonBar( + children: [ + FlatButton( + child: Text('Like'.toUpperCase()), + onPressed: () {}, + ), + FlatButton( + child: Text('Read'.toUpperCase()), + onPressed: () {}, + ), + ], + ), + ), + ], + ), + ); + }).toList(), + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/checkbox_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/checkbox_demo.dart new file mode 100644 index 00000000..0652b390 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/checkbox_demo.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; + +class CheckboxDemo extends StatefulWidget { + @override + _CheckboxDemoState createState() => _CheckboxDemoState(); +} + +class _CheckboxDemoState extends State { + bool _checkboxItemA = true; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('CheckboxDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CheckboxListTile( + value: _checkboxItemA, + onChanged: (value) { + setState(() { + _checkboxItemA = value; + }); + }, + title: Text('Checkbox Item A'), + subtitle: Text('Description'), + secondary: Icon(Icons.bookmark), + selected: _checkboxItemA, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Checkbox( + // value: _checkboxItemA, + // onChanged: (value) { + // setState(() { + // _checkboxItemA = value; + // }); + // }, + // activeColor: Colors.black, + // ), + ], + ), + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/chip_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/chip_demo.dart new file mode 100644 index 00000000..6a3a40e8 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/chip_demo.dart @@ -0,0 +1,178 @@ +import 'package:flutter/material.dart'; + +class ChipDemo extends StatefulWidget { + @override + _ChipDemoState createState() => _ChipDemoState(); +} + +class _ChipDemoState extends State { + List _tags = [ + 'Apple', + 'Banana', + 'Lemon', + ]; + + String _action = 'Nothing'; + List _selected = []; + String _choice = 'Lemon'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ChipDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: [ + Chip( + label: Text('Life'), + ), + Chip( + label: Text('Sunset'), + backgroundColor: Colors.orange, + ), + Chip( + label: Text('Wanghao'), + avatar: CircleAvatar( + backgroundColor: Colors.grey, + child: Text('皓'), + ), + ), + Chip( + label: Text('Wanghao'), + avatar: CircleAvatar( + backgroundImage: NetworkImage( + 'https://resources.ninghao.net/images/wanghao.jpg' + ), + ), + ), + Chip( + label: Text('City'), + onDeleted: () {}, + deleteIcon: Icon(Icons.delete), + deleteIconColor: Colors.redAccent, + deleteButtonTooltipMessage: 'Remove this tag', + ), + Divider( + color: Colors.grey, + height: 32.0, + // indent: 32.0, + ), + Wrap( + spacing: 8.0, + children: _tags.map((tag) { + return Chip( + label: Text(tag), + onDeleted: () { + setState(() { + _tags.remove(tag); + }); + }, + ); + }).toList(), + ), + Divider( + color: Colors.grey, + height: 32.0, + // indent: 32.0, + ), + Container( + width: double.infinity, + child: Text('ActionChip: $_action'), + ), + Wrap( + spacing: 8.0, + children: _tags.map((tag) { + return ActionChip( + label: Text(tag), + onPressed: () { + setState(() { + _action = tag; + }); + }, + ); + }).toList(), + ), + Divider( + color: Colors.grey, + height: 32.0, + // indent: 32.0, + ), + Container( + width: double.infinity, + child: Text('FilterChip: ${_selected.toString()}'), + ), + Wrap( + spacing: 8.0, + children: _tags.map((tag) { + return FilterChip( + label: Text(tag), + selected: _selected.contains(tag), + onSelected: (value) { + setState(() { + if (_selected.contains(tag)) { + _selected.remove(tag); + } else { + _selected.add(tag); + } + }); + }, + ); + }).toList(), + ), + Divider( + color: Colors.grey, + height: 32.0, + // indent: 32.0, + ), + Container( + width: double.infinity, + child: Text('ChoiceChip: $_choice'), + ), + Wrap( + spacing: 8.0, + children: _tags.map((tag) { + return ChoiceChip( + label: Text(tag), + selectedColor: Colors.black, + selected: _choice == tag, + onSelected: (value) { + setState(() { + _choice = tag; + }); + }, + ); + }).toList(), + ), + ], + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + child: Icon(Icons.restore), + onPressed: () { + setState(() { + _tags = [ + 'Apple', + 'Banana', + 'Lemon', + ]; + + _selected = []; + + _choice = 'Lemon'; + }); + }, + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/data_table_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/data_table_demo.dart new file mode 100644 index 00000000..2394e974 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/data_table_demo.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import '../model/post.dart'; + +class DataTableDemo extends StatefulWidget { + @override + _DataTableDemoState createState() => _DataTableDemoState(); +} + +class _DataTableDemoState extends State { + int _sortColumnIndex; + bool _sortAscending = true; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('DataTableDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: ListView( + children: [ + DataTable( + sortColumnIndex: _sortColumnIndex, + sortAscending: _sortAscending, + // onSelectAll: (bool value) {}, + columns: [ + DataColumn( + label: Text('Title'), + onSort: (int index, bool ascending) { + setState(() { + _sortColumnIndex = index; + _sortAscending = ascending; + + posts.sort((a, b) { + if (!ascending) { + final c = a; + a = b; + b = c; + } + + return a.title.length.compareTo(b.title.length); + }); + }); + }, + ), + DataColumn( + label: Text('Author'), + ), + DataColumn( + label: Text('Image'), + ), + ], + rows: posts.map((post) { + return DataRow( + selected: post.selected, + onSelectChanged: (bool value) { + setState(() { + if (post.selected != value) { + post.selected = value; + } + }); + }, + cells: [ + DataCell(Text(post.title)), + DataCell(Text(post.author)), + DataCell(Image.network(post.imageUrl)), + ] + ); + }).toList(), + ), + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/datetime_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/datetime_demo.dart new file mode 100644 index 00000000..c5e0f4ec --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/datetime_demo.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'dart:async'; + +class DateTimeDemo extends StatefulWidget { + @override + _DateTimeDemoState createState() => _DateTimeDemoState(); +} + +class _DateTimeDemoState extends State { + DateTime selectedDate = DateTime.now(); + TimeOfDay selectedTime = TimeOfDay(hour: 9, minute: 30); + + Future _selectDate() async { + final DateTime date = await showDatePicker( + context: context, + initialDate: selectedDate, + firstDate: DateTime(1900), + lastDate: DateTime(2100), + ); + + if (date == null) return; + + setState(() { + selectedDate = date; + }); + } + + Future _selectTime() async { + final TimeOfDay time = await showTimePicker( + context: context, + initialTime: selectedTime, + ); + + if (time == null) return; + + setState(() { + selectedTime = time; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('DateTimeDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + onTap: _selectDate, + child: Row( + children: [ + Text(DateFormat.yMMMMd().format(selectedDate)), + Icon(Icons.arrow_drop_down), + ], + ), + ), + InkWell( + onTap: _selectTime, + child: Row( + children: [ + Text(selectedTime.format(context)), + Icon(Icons.arrow_drop_down), + ], + ), + ), + ], + ), + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/drawer_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/drawer_demo.dart new file mode 100644 index 00000000..04f738cb --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/drawer_demo.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; + +class DrawerDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + // TODO: implement build + return Drawer( + child: ListView( + padding: EdgeInsets.zero, + children: [ + UserAccountsDrawerHeader( + accountName: + Text('wanghao', style: TextStyle(fontWeight: FontWeight.bold)), + accountEmail: Text('wanghao@ninghao.net'), + currentAccountPicture: CircleAvatar( + backgroundImage: NetworkImage( + 'https://resources.ninghao.org/images/wanghao.jpg'), + ), + decoration: BoxDecoration( + color: Colors.yellow[400], + image: DecorationImage( + image: NetworkImage( + 'https://resources.ninghao.org/images/childhood-in-a-picture.jpg'), + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + Colors.yellow[400].withOpacity(0.6), BlendMode.hardLight), + ), + ), + ), + ListTile( + title: Text( + 'Messages', + textAlign: TextAlign.right, + ), + trailing: Icon(Icons.message, color: Colors.black12, size: 22.0), + onTap: () => Navigator.pop(context), + ), + ListTile( + title: Text( + 'Favorite', + textAlign: TextAlign.right, + ), + trailing: Icon(Icons.favorite, color: Colors.black12, size: 22.0), + onTap: () => Navigator.pop(context), + ), + ListTile( + title: Text( + 'Settings', + textAlign: TextAlign.right, + ), + trailing: Icon(Icons.settings, color: Colors.black12, size: 22.0), + onTap: () => Navigator.pop(context), + ), + ], + ), + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/expansion_panel_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/expansion_panel_demo.dart new file mode 100644 index 00000000..2624fdb7 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/expansion_panel_demo.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; + +class ExpansionPanelItem { + final String headerText; + final Widget body; + bool isExpanded; + + ExpansionPanelItem({ + this.headerText, + this.body, + this.isExpanded, + }); +} + +class ExpansionPanelDemo extends StatefulWidget { + @override + _ExpansionPanelDemoState createState() => _ExpansionPanelDemoState(); +} + +class _ExpansionPanelDemoState extends State { + List _expansionPanelItems; + + @override + void initState() { + super.initState(); + + _expansionPanelItems = [ + ExpansionPanelItem( + headerText: 'Panel A', + body: Container( + padding: EdgeInsets.all(16.0), + width: double.infinity, + child: Text('Content for Panel A.'), + ), + isExpanded: false, + ), + ExpansionPanelItem( + headerText: 'Panel B', + body: Container( + padding: EdgeInsets.all(16.0), + width: double.infinity, + child: Text('Content for Panel B.'), + ), + isExpanded: false, + ), + ExpansionPanelItem( + headerText: 'Panel C', + body: Container( + padding: EdgeInsets.all(16.0), + width: double.infinity, + child: Text('Content for Panel C.'), + ), + isExpanded: false, + ), + ]; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('ExpansionPanelDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ExpansionPanelList( + expansionCallback: (int panelIndex, bool isExpanded) { + setState(() { + _expansionPanelItems[panelIndex].isExpanded = !isExpanded; + }); + }, + children: _expansionPanelItems.map( + (ExpansionPanelItem item) { + return ExpansionPanel( + isExpanded: item.isExpanded, + body: item.body, + headerBuilder: (BuildContext context, bool isExpanded) { + return Container( + padding: EdgeInsets.all(16.0), + child: Text( + item.headerText, + style: Theme.of(context).textTheme.title, + ), + ); + }, + ); + } + ).toList(), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/floating_action_button_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/floating_action_button_demo.dart new file mode 100644 index 00000000..a5ad148e --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/floating_action_button_demo.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +class FloatingActionButtonDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + final Widget _floatingActionButton = FloatingActionButton( + onPressed: () {}, + child: Icon(Icons.add), + elevation: 0.0, + backgroundColor: Colors.black87, + // shape: BeveledRectangleBorder( + // borderRadius: BorderRadius.circular(30.0) + // ), + ); + + final Widget _floatingActionButtonExtended = FloatingActionButton.extended( + onPressed: () {}, + icon: Icon(Icons.add), + label: Text('Add'), + ); + + return Scaffold( + appBar: AppBar( + title: Text('FloatingActionButtonDemo'), + elevation: 0.0, + ), + floatingActionButton: _floatingActionButton, + floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, + bottomNavigationBar: BottomAppBar( + child: Container( + height: 80.0, + ), + shape: CircularNotchedRectangle(), + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/form_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/form_demo.dart new file mode 100644 index 00000000..9caea518 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/form_demo.dart @@ -0,0 +1,173 @@ +import 'package:flutter/material.dart'; + +class FormDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('FormDemo'), + elevation: 0.0, + ), + body: Theme( + data: Theme.of(context).copyWith( + primaryColor: Colors.black, + ), + child: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RegisterForm(), + ], + ), + ), + ), + ); + } +} + +class RegisterForm extends StatefulWidget { + @override + RegisterFormState createState() => RegisterFormState(); +} + +class RegisterFormState extends State { + final registerFormKey = GlobalKey(); + String username, password; + bool autovalidate = false; + + void submitRegisterForm() { + if (registerFormKey.currentState.validate()) { + registerFormKey.currentState.save(); + + debugPrint('username: $username'); + debugPrint('password: $password'); + + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text('Registering...'), + ) + ); + } else { + setState(() { + autovalidate = true; + }); + } + } + + String validateUsername(value) { + if (value.isEmpty) { + return 'Username is required.'; + } + + return null; + } + + String validatePassword(value) { + if (value.isEmpty) { + return 'Password is required.'; + } + + return null; + } + + @override + Widget build(BuildContext context) { + return Form( + key: registerFormKey, + child: Column( + children: [ + TextFormField( + decoration: InputDecoration( + labelText: 'Username', + helperText: '', + ), + onSaved: (value) { + username = value; + }, + validator: validateUsername, + autovalidate: autovalidate, + ), + TextFormField( + obscureText: true, + decoration: InputDecoration( + labelText: 'Password', + helperText: '', + ), + onSaved: (value) { + password = value; + }, + validator: validatePassword, + autovalidate: autovalidate, + ), + SizedBox(height: 32.0,), + Container( + width: double.infinity, + child: RaisedButton( + color: Theme.of(context).accentColor, + child: Text('Register', style: TextStyle(color: Colors.white)), + elevation: 0.0, + onPressed: submitRegisterForm, + ), + ), + ], + ), + ); + } +} + +class TextFieldDemo extends StatefulWidget { + @override + TextFieldDemoState createState() => TextFieldDemoState(); +} + +class TextFieldDemoState extends State { + final textEditingController = TextEditingController(); + + @override + void dispose() { + textEditingController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + // textEditingController.text = 'hi'; + textEditingController.addListener( + () { + debugPrint('input: ${textEditingController.text}'); + } + ); + } + + @override + Widget build(BuildContext context) { + return TextField( + controller: textEditingController, + // onChanged: (value) { + // debugPrint('input: $value'); + // }, + onSubmitted: (value) { + debugPrint('submit: $value'); + }, + decoration: InputDecoration( + icon: Icon(Icons.subject), + labelText: 'Title', + hintText: 'Enter the post title.', + // border: InputBorder.none, + // border: OutlineInputBorder(), + filled: true, + ), + ); + } +} + +class ThemeDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + color: Theme.of(context).accentColor, + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/hello_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/hello_demo.dart new file mode 100644 index 00000000..de8f67b7 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/hello_demo.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; + +class Hello extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Center( + child: Text( + 'hello', + textDirection: TextDirection.ltr, + style: TextStyle( + fontSize: 40.0, + fontWeight: FontWeight.bold, + color: Colors.black87, + ) + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/http/http_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/http/http_demo.dart new file mode 100644 index 00000000..3a5e1cde --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/http/http_demo.dart @@ -0,0 +1,129 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:async'; + +class HttpDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('HttpDemo'), + elevation: 0.0, + ), + body: HttpDemoHome(), + ); + } +} + +class HttpDemoHome extends StatefulWidget { + @override + _HttpDemoHomeState createState() => _HttpDemoHomeState(); +} + +class _HttpDemoHomeState extends State { + @override + void initState() { + super.initState(); + // fetchPosts() + // .then((value) => print(value)); + + // final post = { + // 'title': 'hello', + // 'description': 'nice to meet you.', + // }; + + // print(post['title']); + // print(post['description']); + + // final postJson = json.encode(post); + // print(postJson); + + // final postJsonConverted = json.decode(postJson); + // print(postJsonConverted['title']); + // print(postJsonConverted['description']); + // print(postJsonConverted is Map); + + // final postModel = Post.fromJson(postJsonConverted); + // print('title: ${postModel.title}, description: ${postModel.description}'); + + // print('${json.encode(postModel)}'); + } + + Future> fetchPosts() async { + final response = + await http.get('https://resources.ninghao.net/demo/posts.json'); + + // print('statusCode: ${response.statusCode}'); + // print('body: ${response.body}'); + + if (response.statusCode == 200) { + final responseBody = json.decode(response.body); + List posts = responseBody['posts'] + .map((item) => Post.fromJson(item)) + .toList(); + + return posts; + } else { + throw Exception('Failed to fetch posts.'); + } + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: fetchPosts(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + print('data: ${snapshot.data}'); + print('connectionState: ${snapshot.connectionState}'); + + if (snapshot.connectionState == ConnectionState.waiting) { + return Center( + child: Text('loading...'), + ); + } + + return ListView( + children: snapshot.data.map((item) { + return ListTile( + title: Text(item.title), + subtitle: Text(item.author), + leading: CircleAvatar( + backgroundImage: NetworkImage(item.imageUrl), + ), + ); + }).toList(), + ); + }, + ); + } +} + +class Post { + final int id; + final String title; + final String description; + final String author; + final String imageUrl; + + Post( + this.id, + this.title, + this.description, + this.author, + this.imageUrl, + ); + + Post.fromJson(Map json) + : id = json['id'], + title = json['title'], + description = json['description'], + author = json['author'], + imageUrl = json['imageUrl']; + + Map toJson() => { + 'title': title, + 'descritpion': description, + }; +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/i18n_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/i18n_demo.dart new file mode 100644 index 00000000..8a4877b9 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/i18n_demo.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +// import 'package:ninghao_flutter/demo/i18n/map/ninghao_demo_localizations.dart'; +import 'package:ninghao_flutter/demo/i18n/intl/ninghao_demo_localizations.dart'; + +class I18nDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + Locale locale = Localizations.localeOf(context); + + return Scaffold( + appBar: AppBar( + title: Text('I18nDemo'), + elevation: 0.0, + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(locale.toString()), + Text( + // Localizations.of(context, NinghaoDemoLocalizations).title, + // NinghaoDemoLocalizations.of(context).title, + NinghaoDemoLocalizations.of(context).greet('ninghao'), + style: Theme.of(context).textTheme.title, + ) + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_en.arb b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_en.arb new file mode 100644 index 00000000..15d5b6f2 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_en.arb @@ -0,0 +1,17 @@ +{ + "@@last_modified": "2018-10-19T15:45:15.386436", + "title": "hello", + "@title": { + "description": "demo localizations.", + "type": "text", + "placeholders": {} + }, + "greet": "hello {name}", + "@greet": { + "description": "greet someone.", + "type": "text", + "placeholders": { + "name": {} + } + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_messages.arb b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_messages.arb new file mode 100644 index 00000000..15d5b6f2 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_messages.arb @@ -0,0 +1,17 @@ +{ + "@@last_modified": "2018-10-19T15:45:15.386436", + "title": "hello", + "@title": { + "description": "demo localizations.", + "type": "text", + "placeholders": {} + }, + "greet": "hello {name}", + "@greet": { + "description": "greet someone.", + "type": "text", + "placeholders": { + "name": {} + } + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_zh.arb b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_zh.arb new file mode 100644 index 00000000..1e602a43 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/intl_zh.arb @@ -0,0 +1,17 @@ +{ + "@@last_modified": "2018-10-19T15:45:15.386436", + "title": "您好", + "@title": { + "description": "演示本地化", + "type": "text", + "placeholders": {} + }, + "greet": "您好 {name}", + "@greet": { + "description": "问候某人", + "type": "text", + "placeholders": { + "name": {} + } + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_localizations.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_localizations.dart new file mode 100644 index 00000000..3275282a --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_localizations.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'ninghao_demo_messages_all.dart'; + +class NinghaoDemoLocalizations { + static NinghaoDemoLocalizations of(BuildContext context) { + return Localizations.of( + context, + NinghaoDemoLocalizations + ); + } + + static Future load(Locale locale) { + final String name = + locale.countryCode.isEmpty ? locale.languageCode : locale.toString(); + + final String localeName = Intl.canonicalizedLocale(name); + + return initializeMessages(localeName).then((bool _) { + Intl.defaultLocale = localeName; + return NinghaoDemoLocalizations(); + }); + } + + String get title => Intl.message( + 'hello', + name: 'title', + desc: 'demo localizations.', + ); + + String greet(String name) => Intl.message( + 'hello $name', + name: 'greet', + desc: 'greet someone.', + args: [name], + ); +} + +class NinghaoDemoLocalizationsDelegate + extends LocalizationsDelegate { + NinghaoDemoLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return NinghaoDemoLocalizations.load(locale); + } + + @override + bool isSupported(Locale locale) { + return true; + } + + @override + bool shouldReload(LocalizationsDelegate old) { + return false; + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_all.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_all.dart new file mode 100644 index 00000000..548ef28c --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_all.dart @@ -0,0 +1,72 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that looks up messages for specific locales by +// delegating to the appropriate library. + +import 'dart:async'; + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; +// ignore: implementation_imports +import 'package:intl/src/intl_helpers.dart'; + +import 'ninghao_demo_messages_en.dart' as messages_en; +import 'ninghao_demo_messages_messages.dart' as messages_messages; +import 'ninghao_demo_messages_zh.dart' as messages_zh; + +typedef Future LibraryLoader(); +Map _deferredLibraries = { +// ignore: unnecessary_new + 'en': () => new Future.value(null), +// ignore: unnecessary_new + 'messages': () => new Future.value(null), +// ignore: unnecessary_new + 'zh': () => new Future.value(null), +}; + +MessageLookupByLibrary _findExact(localeName) { + switch (localeName) { + case 'en': + return messages_en.messages; + case 'messages': + return messages_messages.messages; + case 'zh': + return messages_zh.messages; + default: + return null; + } +} + +/// User programs should call this before using [localeName] for messages. +Future initializeMessages(String localeName) async { + var availableLocale = Intl.verifiedLocale( + localeName, + (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); + if (availableLocale == null) { + // ignore: unnecessary_new + return new Future.value(false); + } + var lib = _deferredLibraries[availableLocale]; + // ignore: unnecessary_new + await (lib == null ? new Future.value(false) : lib()); + // ignore: unnecessary_new + initializeInternalMessageLookup(() => new CompositeMessageLookup()); + messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); + // ignore: unnecessary_new + return new Future.value(true); +} + +bool _messagesExistFor(String locale) { + try { + return _findExact(locale) != null; + } catch (e) { + return false; + } +} + +MessageLookupByLibrary _findGeneratedMessagesFor(locale) { + var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, + onFailure: (_) => null); + if (actualLocale == null) return null; + return _findExact(actualLocale); +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_en.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_en.dart new file mode 100644 index 00000000..50e6cecc --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_en.dart @@ -0,0 +1,28 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a en locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +// ignore: unnecessary_new +final messages = new MessageLookup(); + +// ignore: unused_element +final _keepAnalysisHappy = Intl.defaultLocale; + +// ignore: non_constant_identifier_names +typedef MessageIfAbsent(String message_str, List args); + +class MessageLookup extends MessageLookupByLibrary { + get localeName => 'en'; + + static m0(name) => "hello ${name}"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static _notInlinedMessages(_) => { + "greet" : m0, + "title" : MessageLookupByLibrary.simpleMessage("hello") + }; +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_messages.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_messages.dart new file mode 100644 index 00000000..33b8e3b0 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_messages.dart @@ -0,0 +1,28 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a messages locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +// ignore: unnecessary_new +final messages = new MessageLookup(); + +// ignore: unused_element +final _keepAnalysisHappy = Intl.defaultLocale; + +// ignore: non_constant_identifier_names +typedef MessageIfAbsent(String message_str, List args); + +class MessageLookup extends MessageLookupByLibrary { + get localeName => 'messages'; + + static m0(name) => "hello ${name}"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static _notInlinedMessages(_) => { + "greet" : m0, + "title" : MessageLookupByLibrary.simpleMessage("hello") + }; +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_zh.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_zh.dart new file mode 100644 index 00000000..29786aa9 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/intl/ninghao_demo_messages_zh.dart @@ -0,0 +1,28 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a zh locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +// ignore: unnecessary_new +final messages = new MessageLookup(); + +// ignore: unused_element +final _keepAnalysisHappy = Intl.defaultLocale; + +// ignore: non_constant_identifier_names +typedef MessageIfAbsent(String message_str, List args); + +class MessageLookup extends MessageLookupByLibrary { + get localeName => 'zh'; + + static m0(name) => "您好 ${name}"; + + final messages = _notInlinedMessages(_notInlinedMessages); + static _notInlinedMessages(_) => { + "greet" : m0, + "title" : MessageLookupByLibrary.simpleMessage("您好") + }; +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/map/ninghao_demo_localizations.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/map/ninghao_demo_localizations.dart new file mode 100644 index 00000000..3f5e75b3 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/i18n/map/ninghao_demo_localizations.dart @@ -0,0 +1,49 @@ +import 'package:flutter/foundation.dart' show SynchronousFuture; +import 'package:flutter/material.dart'; + +class NinghaoDemoLocalizations { + final Locale locale; + + NinghaoDemoLocalizations(this.locale); + + static NinghaoDemoLocalizations of(BuildContext context) { + return Localizations.of( + context, + NinghaoDemoLocalizations + ); + } + + static Map> _localized = { + 'en': { + 'title': 'hello', + }, + 'zh': { + 'title': '您好', + } + }; + + String get title { + return _localized[locale.languageCode]['title']; + } +} + +class NinghaoDemoLocalizationsDelegate + extends LocalizationsDelegate { + NinghaoDemoLocalizationsDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture( + NinghaoDemoLocalizations(locale)); + } + + @override + bool isSupported(Locale locale) { + return true; + } + + @override + bool shouldReload(LocalizationsDelegate old) { + return false; + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/layout_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/layout_demo.dart new file mode 100644 index 00000000..386e305f --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/layout_demo.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; + +class LayoutDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + StackDemo(), + ], + ), + ); + } +} + +class ConstrainedBoxDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ConstrainedBox( + constraints: BoxConstraints( + minHeight: 200.0, + maxWidth: 200.0, + ), + child: Container( + color: Color.fromRGBO(3, 54, 255, 1.0), + ), + ); + } +} + +class AspectRatioDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return AspectRatio( + aspectRatio: 16.0 / 9.0, + child: Container( + color: Color.fromRGBO(3, 54, 255, 1.0), + ), + ); + } +} + +class StackDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.topLeft, + children: [ + SizedBox( + width: 200.0, + height: 300.0, + child: Container( + alignment: Alignment(0.0, -0.9), + decoration: BoxDecoration( + color: Color.fromRGBO(3, 54, 255, 1.0), + borderRadius: BorderRadius.circular(8.0), + ), + ), + ), + SizedBox( + height: 32.0, + ), + SizedBox( + width: 100.0, + height: 100.0, + child: Container( + decoration: BoxDecoration( + color: Color.fromRGBO(3, 54, 255, 1.0), + shape: BoxShape.circle, + gradient: RadialGradient(colors: [ + Color.fromRGBO(7, 102, 255, 1.0), + Color.fromRGBO(3, 54, 255, 1.0), + ]), + ), + child: Icon(Icons.brightness_2, color: Colors.white, size: 32.0), + ), + ), + Positioned( + right: 20.0, + top: 20.0, + child: Icon(Icons.ac_unit, color: Colors.white, size: 16.0), + ), + Positioned( + right: 40.0, + top: 60.0, + child: Icon(Icons.ac_unit, color: Colors.white, size: 18.0), + ), + Positioned( + right: 20.0, + top: 120.0, + child: Icon(Icons.ac_unit, color: Colors.white, size: 20.0), + ), + Positioned( + right: 70.0, + top: 180.0, + child: Icon(Icons.ac_unit, color: Colors.white, size: 16.0), + ), + Positioned( + right: 30.0, + top: 230.0, + child: Icon(Icons.ac_unit, color: Colors.white, size: 18.0), + ), + Positioned( + right: 90.0, + bottom: 20.0, + child: Icon(Icons.ac_unit, color: Colors.white, size: 16.0), + ), + Positioned( + right: 4.0, + bottom: -4.0, + child: Icon(Icons.ac_unit, color: Colors.white, size: 16.0), + ), + ], + ); + } +} + +class IconBadge extends StatelessWidget { + final IconData icon; + final double size; + + IconBadge(this.icon, {this.size = 32.0}); + + @override + Widget build(BuildContext context) { + return Container( + child: Icon(icon, size: size, color: Colors.white), + width: size + 60, + height: size + 60, + color: Color.fromRGBO(3, 54, 255, 1.0), + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/listview_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/listview_demo.dart new file mode 100644 index 00000000..c353d923 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/listview_demo.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import './post_show.dart'; +import '../model/post.dart'; + +class ListViewDemo extends StatelessWidget { + Widget _listItemBuilder(BuildContext context, int index) { + return Container( + color: Colors.white, + margin: EdgeInsets.all(8.0), + child: Stack( + children: [ + Column( + children: [ + AspectRatio( + aspectRatio: 16/9, + child: Image.network(posts[index].imageUrl, fit: BoxFit.cover), + ), + SizedBox(height: 16.0), + Text( + posts[index].title, + style: Theme.of(context).textTheme.title + ), + Text( + posts[index].author, + style: Theme.of(context).textTheme.subhead + ), + SizedBox(height: 16.0), + ], + ), + Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + splashColor: Colors.white.withOpacity(0.3), + highlightColor: Colors.white.withOpacity(0.1), + onTap: () { + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => PostShow(post: posts[index])) + ); + } + ), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + return ListView.builder( + itemCount: posts.length, + itemBuilder: _listItemBuilder, + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/material_components.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/material_components.dart new file mode 100644 index 00000000..e1515365 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/material_components.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import './button_demo.dart'; +import './floating_action_button_demo.dart'; +import './popup_menu_button_demo.dart'; +import './form_demo.dart'; +import './checkbox_demo.dart'; +import './radio_demo.dart'; +import './switch_demo.dart'; +import './slider_demo.dart'; +import './datetime_demo.dart'; +import './simple_dialog_demo.dart'; +import './alert_dialog_demo.dart'; +import './bottom_sheet_demo.dart'; +import './snack_bar_demo.dart'; +import './expansion_panel_demo.dart'; +import './chip_demo.dart'; +import './data_table_demo.dart'; +import './paginated_data_table_demo.dart'; +import './card_demo.dart'; +import './stepper_demo.dart'; + +class MaterialComponents extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('MaterialComponents'), + elevation: 0.0, + ), + body: ListView( + children: [ + ListItem(title: 'Stepper', page: StepperDemo()), + ListItem(title: 'Card', page: CardDemo()), + ListItem(title: 'PaginatedDataTable', page: PaginatedDataTableDemo()), + ListItem(title: 'DataTable', page: DataTableDemo()), + ListItem(title: 'Chip', page: ChipDemo()), + ListItem(title: 'ExpansionPanel', page: ExpansionPanelDemo()), + ListItem(title: 'SnackBar', page: SnackBarDemo()), + ListItem(title: 'BottomSheet', page: BottomSheetDemo()), + ListItem(title: 'AlertDialog', page: AlertDialogDemo()), + ListItem(title: 'SimpleDialog', page: SimpleDialogDemo()), + ListItem(title: 'Date & Time', page: DateTimeDemo()), + ListItem(title: 'Slider', page: SliderDemo()), + ListItem(title: 'Switch', page: SwitchDemo()), + ListItem(title: 'Radio', page: RadioDemo()), + ListItem(title: 'Checkbox', page: CheckboxDemo()), + ListItem(title: 'Form', page: FormDemo()), + ListItem(title: 'PopupMenuButton', page: PopupMenuButtonDemo()), + ListItem(title: 'Button', page: ButtonDemo()), + ListItem(title: 'FloatingActionButton', page: FloatingActionButtonDemo()), + ], + ), + ); + } +} + +class _WidgetDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('_WidgetDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + + ], + ), + ], + ), + ) + ); + } +} + +class ListItem extends StatelessWidget { + final String title; + final Widget page; + + ListItem({ + this.title, + this.page, + }); + + @override + Widget build(BuildContext context) { + return ListTile( + title: Text(title), + onTap: () { + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => page), + ); + }, + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/navigator_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/navigator_demo.dart new file mode 100644 index 00000000..50a11323 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/navigator_demo.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +class NavigatorDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FlatButton( + child: Text('Home'), + onPressed: null, + ), + FlatButton( + child: Text('About'), + onPressed: () { + Navigator.pushNamed(context, '/about'); + }, + ), + ], + ), + ), + ); + } +} + +class Page extends StatelessWidget { + final String title; + + Page({ + this.title + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + elevation: 0.0, + ), + floatingActionButton: FloatingActionButton( + child: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pop(context); + }, + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/paginated_data_table_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/paginated_data_table_demo.dart new file mode 100644 index 00000000..052ff125 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/paginated_data_table_demo.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import '../model/post.dart'; + +class PostDataSource extends DataTableSource { + final List _posts = posts; + int _selectedCount = 0; + + @override + int get rowCount => _posts.length; + + @override + bool get isRowCountApproximate => false; + + @override + int get selectedRowCount => _selectedCount; + + @override + DataRow getRow(int index) { + final Post post = _posts[index]; + + return DataRow.byIndex( + index: index, + cells: [ + DataCell(Text(post.title)), + DataCell(Text(post.author)), + DataCell(Image.network(post.imageUrl)), + ], + ); + } + + void _sort(getField(post), bool ascending) { + _posts.sort((a, b) { + if (!ascending) { + final c = a; + a = b; + b = c; + } + + final aValue = getField(a); + final bValue = getField(b); + + return Comparable.compare(aValue, bValue); + }); + + notifyListeners(); + } +} + +class PaginatedDataTableDemo extends StatefulWidget { + @override + _PaginatedDataTableDemoState createState() => _PaginatedDataTableDemoState(); +} + +class _PaginatedDataTableDemoState extends State { + int _sortColumnIndex; + bool _sortAscending = true; + + final PostDataSource _postsDataSource = PostDataSource(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('PaginatedDataTableDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: ListView( + children: [ + PaginatedDataTable( + header: Text('Posts'), + rowsPerPage: 5, + source: _postsDataSource, + sortColumnIndex: _sortColumnIndex, + sortAscending: _sortAscending, + // onSelectAll: (bool value) {}, + columns: [ + DataColumn( + label: Text('Title'), + onSort: (int columnIndex, bool ascending) { + _postsDataSource._sort((post) => post.title.length, ascending); + + setState(() { + _sortColumnIndex = columnIndex; + _sortAscending = ascending; + }); + }, + ), + DataColumn( + label: Text('Author'), + ), + DataColumn( + label: Text('Image'), + ), + ], + ), + ], + ), + )); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/popup_menu_button_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/popup_menu_button_demo.dart new file mode 100644 index 00000000..70e046a4 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/popup_menu_button_demo.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; + +class PopupMenuButtonDemo extends StatefulWidget { + @override + _PopupMenuButtonDemoState createState() => _PopupMenuButtonDemoState(); +} + +class _PopupMenuButtonDemoState extends State { + String _currentMenuItem = 'Home'; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('PopupMenuButtonDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(_currentMenuItem), + PopupMenuButton( + onSelected: (value) { + print(value); + setState(() { + _currentMenuItem = value; + }); + }, + itemBuilder: (BuildContext context) => [ + PopupMenuItem( + value: 'Home', + child: Text('Home'), + ), + PopupMenuItem( + value: 'Discover', + child: Text('Discover'), + ), + PopupMenuItem( + value: 'Community', + child: Text('Community'), + ), + ], + ), + ], + ), + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/post_show.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/post_show.dart new file mode 100644 index 00000000..ec4a90ce --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/post_show.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import '../model/post.dart'; + +class PostShow extends StatelessWidget { + final Post post; + + PostShow({ + @required this.post, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('${post.title}'), + elevation: 0.0, + ), + body: Column( + children: [ + Image.network( + post.imageUrl + ), + Container( + padding: EdgeInsets.all(32.0), + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('${post.title}', style: Theme.of(context).textTheme.title), + Text('${post.author}', style: Theme.of(context).textTheme.subhead), + SizedBox(height: 32.0), + Text('${post.description}', style: Theme.of(context).textTheme.body1), + ], + ), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/radio_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/radio_demo.dart new file mode 100644 index 00000000..e082174c --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/radio_demo.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; + +class RadioDemo extends StatefulWidget { + @override + _RadioDemoState createState() => _RadioDemoState(); +} + +class _RadioDemoState extends State { + int _radioGroupA = 0; + + void _handleRadioValueChanged(int value) { + setState(() { + _radioGroupA = value; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('RadioDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('RadioGroupValue: $_radioGroupA'), + SizedBox(height: 32.0), + RadioListTile( + value: 0, + groupValue: _radioGroupA, + onChanged: _handleRadioValueChanged, + title: Text('Options A'), + subtitle: Text('Description'), + secondary: Icon(Icons.filter_1), + selected: _radioGroupA == 0, + ), + RadioListTile( + value: 1, + groupValue: _radioGroupA, + onChanged: _handleRadioValueChanged, + title: Text('Options B'), + subtitle: Text('Description'), + secondary: Icon(Icons.filter_2), + selected: _radioGroupA == 1, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Radio( + // value: 0, + // groupValue: _radioGroupA, + // onChanged: _handleRadioValueChanged, + // activeColor: Colors.black, + // ), + // Radio( + // value: 1, + // groupValue: _radioGroupA, + // onChanged: _handleRadioValueChanged, + // activeColor: Colors.black, + // ), + ], + ), + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/rxdart/rxdart_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/rxdart/rxdart_demo.dart new file mode 100644 index 00000000..d77ae91c --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/rxdart/rxdart_demo.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; +import 'dart:async'; + +class RxDartDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('RxDartDemo'), + elevation: 0.0, + ), + body: RxDartDemoHome(), + ); + } +} + +class RxDartDemoHome extends StatefulWidget { + @override + _RxDartDemoHomeState createState() => _RxDartDemoHomeState(); +} + +class _RxDartDemoHomeState extends State { + PublishSubject _textFieldSubject; + + @override + void initState() { + super.initState(); + + _textFieldSubject = PublishSubject(); + + _textFieldSubject + // .map((item) => 'item: $item') + // .where((item) => item.length > 9) + .debounce(Duration(milliseconds: 500)) + .listen((data) => print(data)); + + // Observable _observable = + // // Observable(Stream.fromIterable(['hello', '您好'])); + // // Observable.fromFuture(Future.value('hello ~')); + // // Observable.fromIterable(['hello', '您好']); + // // Observable.just('hello ~'); + // Observable.periodic(Duration(seconds: 3), (x) => x.toString()); + + // _observable.listen(print); + + // PublishSubject _subject = PublishSubject(); + // BehaviorSubject _subject = BehaviorSubject(); + // ReplaySubject _subject = ReplaySubject(maxSize: 2); + + // _subject.add('hello'); + // _subject.add('hola'); + // _subject.add('hi'); + // _subject.listen((data) => print('listen 1: $data')); + // _subject.listen((data) => print('listen 2: ${data.toUpperCase()}')); + + // _subject.close(); + } + + @override + void dispose() { + super.dispose(); + _textFieldSubject.close(); + } + + @override + Widget build(BuildContext context) { + return Theme( + data: Theme.of(context).copyWith( + primaryColor: Colors.black, + ), + child: TextField( + onChanged: (value) { + _textFieldSubject.add('input: $value'); + }, + onSubmitted: (value) { + _textFieldSubject.add('submit: $value'); + }, + decoration: InputDecoration( + labelText: 'Title', + filled: true, + ), + ), + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/simple_dialog_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/simple_dialog_demo.dart new file mode 100644 index 00000000..c183f90e --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/simple_dialog_demo.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'dart:async'; + +enum Option { + A, B, C +} + +class SimpleDialogDemo extends StatefulWidget { + @override + _SimpleDialogDemoState createState() => _SimpleDialogDemoState(); +} + +class _SimpleDialogDemoState extends State { + String _choice = 'Nothing'; + + Future _openSimpleDialog() async { + final option = await showDialog( + context: context, + builder: (BuildContext context) { + return SimpleDialog( + title: Text('SimpleDialog'), + children: [ + SimpleDialogOption( + child: Text('Option A'), + onPressed: () { + Navigator.pop(context, Option.A); + }, + ), + SimpleDialogOption( + child: Text('Option B'), + onPressed: () { + Navigator.pop(context, Option.B); + }, + ), + SimpleDialogOption( + child: Text('Option C'), + onPressed: () { + Navigator.pop(context, Option.C); + }, + ), + ], + ); + } + ); + + switch (option) { + case Option.A: + setState(() { + _choice = 'A'; + }); + break; + case Option.B: + setState(() { + _choice = 'B'; + }); + break; + case Option.C: + setState(() { + _choice = 'C'; + }); + break; + default: + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('SimpleDialogDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Your choice is: $_choice'), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ], + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + child: Icon(Icons.format_list_numbered), + onPressed: _openSimpleDialog, + ), + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/slider_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/slider_demo.dart new file mode 100644 index 00000000..330706d2 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/slider_demo.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +class SliderDemo extends StatefulWidget { + @override + _SliderDemoState createState() => _SliderDemoState(); +} + +class _SliderDemoState extends State { + double _sliderItemA = 0.0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('SliderDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Slider( + value: _sliderItemA, + onChanged: (value) { + setState(() { + _sliderItemA = value; + }); + }, + activeColor: Theme.of(context).accentColor, + inactiveColor: Theme.of(context).accentColor.withOpacity(0.3), + min: 0.0, + max: 10.0, + divisions: 10, + label: '${_sliderItemA.toInt()}', + ), + ], + ), + SizedBox(height: 16.0,), + Text('SliderValue: $_sliderItemA'), + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/sliver_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/sliver_demo.dart new file mode 100644 index 00000000..cde1d0a2 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/sliver_demo.dart @@ -0,0 +1,120 @@ +import 'package:flutter/material.dart'; +import '../model/post.dart'; + +class SliverDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: CustomScrollView( + slivers: [ + SliverAppBar( + // title: Text('NINGHAO'), + // pinned: true, + floating: true, + expandedHeight: 178.0, + flexibleSpace: FlexibleSpaceBar( + title: Text( + 'Ninghao Flutter'.toUpperCase(), + style: TextStyle( + fontSize: 15.0, + letterSpacing: 3.0, + fontWeight: FontWeight.w400, + ), + ), + background: Image.network( + 'https://resources.ninghao.net/images/overkill.png', + fit: BoxFit.cover, + ), + ), + ), + SliverSafeArea( + sliver: SliverPadding( + padding: EdgeInsets.all(8.0), + sliver: SliverGridDemo() + ), + ), + ], + ), + ); + } +} + +class SliverListDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(bottom: 32.0), + child: Material( + borderRadius: BorderRadius.circular(12.0), + elevation: 14.0, + shadowColor: Colors.grey.withOpacity(0.5), + child: Stack( + children: [ + AspectRatio( + aspectRatio: 16/9, + child: Image.network( + posts[index].imageUrl, + fit: BoxFit.cover, + ), + ), + Positioned( + top: 32.0, + left: 32.0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + posts[index].title, + style: TextStyle( + fontSize: 20.0, + color: Colors.white + ), + ), + Text( + posts[index].author, + style: TextStyle( + fontSize: 13.0, + color: Colors.white + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + childCount: posts.length, + ), + ); + } +} + +class SliverGridDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SliverGrid( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 8.0, + mainAxisSpacing: 8.0, + childAspectRatio: 1.0, + ), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return Container( + child: Image.network( + posts[index].imageUrl, + fit: BoxFit.cover, + ), + ); + }, + childCount: posts.length, + ), + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/snack_bar_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/snack_bar_demo.dart new file mode 100644 index 00000000..408b605f --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/snack_bar_demo.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +class SnackBarDemo extends StatefulWidget { + @override + _SnackBarDemoState createState() => _SnackBarDemoState(); +} + +class _SnackBarDemoState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('SnackBarDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SnackBarButton(), + ] + ), + ], + ), + ), + ); + } +} + +class SnackBarButton extends StatelessWidget { + @override + Widget build(BuildContext context) { + return FlatButton( + child: Text('Open SnackBar'), + onPressed: () { + Scaffold.of(context).showSnackBar( + SnackBar( + content: Text('Processing...'), + action: SnackBarAction( + label: 'OK', + onPressed: () {}, + ), + ) + ); + }, + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/state/state_management_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/state/state_management_demo.dart new file mode 100644 index 00000000..fd35aaf5 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/state/state_management_demo.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:scoped_model/scoped_model.dart'; + +class StateManagementDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ScopedModel( + model: CounterModel(), + child: Scaffold( + appBar: AppBar( + title: Text('StateManagementDemo'), + elevation: 0.0, + ), + body: CounterWrapper(), + floatingActionButton: ScopedModelDescendant( + rebuildOnChange: false, + builder: (context, _, model) => FloatingActionButton( + child: Icon(Icons.add), + onPressed: model.increaseCount, + ), + ), + ), + ); + } +} + +class CounterWrapper extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Center( + child: Counter(), + ); + } +} + +class Counter extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ScopedModelDescendant( + builder: (context, _, model) => ActionChip( + label: Text('${model.count}'), + onPressed: model.increaseCount, + ), + ); + } +} + +class CounterProvider extends InheritedWidget { + final int count; + final VoidCallback increaseCount; + final Widget child; + + CounterProvider({ + this.count, + this.increaseCount, + this.child, + }) : super(child: child); + + static CounterProvider of(BuildContext context) => + context.inheritFromWidgetOfExactType(CounterProvider); + + @override + bool updateShouldNotify(InheritedWidget oldWidget) { + return true; + } +} + +class CounterModel extends Model { + int _count = 0; + int get count => _count; + + void increaseCount() { + _count += 1; + notifyListeners(); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/stepper_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/stepper_demo.dart new file mode 100644 index 00000000..0593211b --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/stepper_demo.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; + +class StepperDemo extends StatefulWidget { + @override + _StepperDemoState createState() => _StepperDemoState(); +} + +class _StepperDemoState extends State { + int _currentStep = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('StepperDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + primaryColor: Colors.black, + ), + child: Stepper( + currentStep: _currentStep, + onStepTapped: (int value) { + setState(() { + _currentStep = value; + }); + }, + onStepContinue: () { + setState(() { + _currentStep < 2 ? _currentStep += 1 : _currentStep = 0; + }); + }, + onStepCancel: () { + setState(() { + _currentStep > 0 ? _currentStep -= 1 : _currentStep = 0; + }); + }, + steps: [ + Step( + title: Text('Login'), + subtitle: Text('Login first'), + content: Text('Magna exercitation duis non sint eu nostrud.'), + isActive: _currentStep == 0, + ), + Step( + title: Text('Choose Plan'), + subtitle: Text('Choose you plan.'), + content: Text('Magna exercitation duis non sint eu nostrud.'), + isActive: _currentStep == 1, + ), + Step( + title: Text('Confirm payment'), + subtitle: Text('Confirm your payment method.'), + content: Text('Magna exercitation duis non sint eu nostrud.'), + isActive: _currentStep == 2, + ), + ], + ), + ), + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/stream/stream_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/stream/stream_demo.dart new file mode 100644 index 00000000..e4aa66e7 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/stream/stream_demo.dart @@ -0,0 +1,142 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class StreamDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('StreamDemo'), + elevation: 0.0, + ), + body: StreamDemoHome(), + ); + } +} + +class StreamDemoHome extends StatefulWidget { + @override + _StreamDemoHomeState createState() => _StreamDemoHomeState(); +} + +class _StreamDemoHomeState extends State { + StreamSubscription _streamDemoSubscription; + StreamController _streamDemo; + StreamSink _sinkDemo; + String _data = '...'; + + @override + void dispose() { + _streamDemo.close(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + + print('Create a stream.'); + // Stream _streamDemo = Stream.fromFuture(fetchData()); + _streamDemo = StreamController.broadcast(); + _sinkDemo = _streamDemo.sink; + + print('Start listening on a stream.'); + _streamDemoSubscription = + _streamDemo.stream.listen(onData, onError: onError, onDone: onDone); + + _streamDemo.stream.listen(onDataTwo, onError: onError, onDone: onDone); + + print('Initialize completed.'); + } + + void onDone() { + print('Done!'); + } + + void onError(error) { + print('Error: $error'); + } + + void onData(String data) { + setState(() { + _data = data; + }); + print('$data'); + } + + void onDataTwo(String data) { + print('onDataTwo: $data'); + } + + void _pauseStream() { + print('Pause subscription'); + _streamDemoSubscription.pause(); + } + + void _resumeStream() { + print('Resume subscription'); + _streamDemoSubscription.resume(); + } + + void _cancelStream() { + print('Cancel subscription'); + _streamDemoSubscription.cancel(); + } + + void _addDataToStream() async { + print('Add data to stream.'); + + String data = await fetchData(); + // _streamDemo.add(data); + _sinkDemo.add(data); + } + + Future fetchData() async { + await Future.delayed(Duration(seconds: 5)); + // throw 'Something happened'; + return 'hello ~'; + } + + @override + Widget build(BuildContext context) { + return Container( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Text(_data), + StreamBuilder( + stream: _streamDemo.stream, + initialData: '...', + builder: (context, snapshot) { + return Text('${snapshot.data}'); + }, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FlatButton( + child: Text('Add'), + onPressed: _addDataToStream, + ), + FlatButton( + child: Text('Pause'), + onPressed: _pauseStream, + ), + FlatButton( + child: Text('Resume'), + onPressed: _resumeStream, + ), + FlatButton( + child: Text('Cancel'), + onPressed: _cancelStream, + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/switch_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/switch_demo.dart new file mode 100644 index 00000000..40408f9f --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/switch_demo.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; + +class SwitchDemo extends StatefulWidget { + @override + _SwitchDemoState createState() => _SwitchDemoState(); +} + +class _SwitchDemoState extends State { + bool _switchItemA = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('SwitchDemo'), + elevation: 0.0, + ), + body: Container( + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SwitchListTile( + value: _switchItemA, + onChanged: (value) { + setState(() { + _switchItemA = value; + }); + }, + title: Text('Switch Item A'), + subtitle: Text('Description'), + secondary: Icon(_switchItemA ? Icons.visibility : Icons.visibility_off), + selected: _switchItemA, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Text(_switchItemA ? '😁' : '😐', style: TextStyle(fontSize: 32.0),), + // Switch( + // value: _switchItemA, + // onChanged: (value) { + // setState(() { + // _switchItemA = value; + // }); + // }, + // ), + ], + ), + ], + ), + ) + ); + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/test/test_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/test/test_demo.dart new file mode 100644 index 00000000..fa0921f6 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/test/test_demo.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +class TestDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('TestDemo'), + elevation: 0.0, + ), + body: TestDemoHome(), + ); + } +} + +class TestDemoHome extends StatefulWidget { + @override + _TestDemoHomeState createState() => _TestDemoHomeState(); +} + +class _TestDemoHomeState extends State { + int count = 0; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Chip( + label: Text('hello'), + ), + ActionChip( + key: Key('actionChip'), + label: Text('$count', key: Key('actionChipLabelText')), + onPressed: () { + setState(() { + count++; + }); + }, + ) + ], + ); + } +} + +class NinghaoTestDemo { + static greet(String name) { + return 'hello $name ~~'; + } +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/lib/demo/view_demo.dart b/FlutterHelper/ninghao_flutter-master/lib/demo/view_demo.dart new file mode 100644 index 00000000..27f2d794 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/demo/view_demo.dart @@ -0,0 +1,154 @@ +import 'package:flutter/material.dart'; +import '../model/post.dart'; + +class ViewDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return GridViewBuilderDemo(); + } +} + +class GridViewBuilderDemo extends StatelessWidget { + Widget _gridItemBuilder(BuildContext context, int index) { + return Container( + child: Image.network( + posts[index].imageUrl, + fit: BoxFit.cover + ), + ); + } + + @override + Widget build(BuildContext context) { + return GridView.builder( + padding: EdgeInsets.all(8.0), + itemCount: posts.length, + itemBuilder: _gridItemBuilder, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + // crossAxisCount: 3, + maxCrossAxisExtent: 150.0, + crossAxisSpacing: 8.0, + mainAxisSpacing: 8.0, + ), + ); + } +} + +class GridViewExtentDemo extends StatelessWidget { + List _buildTiles(int length) { + return List.generate(length, (int index) { + return Container( + color: Colors.grey[300], + alignment: Alignment(0.0, 0.0), + child: Text('Item $index', + style: TextStyle(fontSize: 18.0, color: Colors.grey)), + ); + }); + } + + @override + Widget build(BuildContext context) { + return GridView.extent( + maxCrossAxisExtent: 150.0, + crossAxisSpacing: 16.0, + mainAxisSpacing: 16.0, + // scrollDirection: Axis.horizontal, + children: _buildTiles(100), + ); + } +} + +class GridViewCountDemo extends StatelessWidget { + List _buildTiles(int length) { + return List.generate(length, (int index) { + return Container( + color: Colors.grey[300], + alignment: Alignment(0.0, 0.0), + child: Text('Item $index', + style: TextStyle(fontSize: 18.0, color: Colors.grey)), + ); + }); + } + + @override + Widget build(BuildContext context) { + return GridView.count( + crossAxisCount: 3, + crossAxisSpacing: 16.0, + mainAxisSpacing: 16.0, + scrollDirection: Axis.horizontal, + children: _buildTiles(100), + ); + } +} + +class PageViewBuilderDemo extends StatelessWidget { + Widget _pageItemBuilder(BuildContext context, int index) { + return Stack( + children: [ + SizedBox.expand( + child: Image.network(posts[index].imageUrl, fit: BoxFit.cover), + ), + Positioned( + bottom: 8.0, + left: 8.0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(posts[index].title, + style: TextStyle(fontWeight: FontWeight.bold)), + Text(posts[index].author), + ], + ), + ), + ], + ); + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + return PageView.builder( + itemCount: posts.length, + itemBuilder: _pageItemBuilder, + ); + } +} + +class PageViewDemo extends StatelessWidget { + @override + Widget build(BuildContext context) { + // TODO: implement build + return PageView( + // pageSnapping: false, + // reverse: true, + scrollDirection: Axis.vertical, + onPageChanged: (currentPage) => debugPrint('Page: $currentPage'), + controller: PageController( + initialPage: 1, + keepPage: false, + viewportFraction: 0.85, + ), + children: [ + Container( + color: Colors.brown[900], + alignment: Alignment(0.0, 0.0), + child: Text('ONE', + style: TextStyle(fontSize: 32.0, color: Colors.white)), + ), + Container( + color: Colors.grey[900], + alignment: Alignment(0.0, 0.0), + child: Text('TWO', + style: TextStyle(fontSize: 32.0, color: Colors.white)), + ), + Container( + color: Colors.blueGrey[900], + alignment: Alignment(0.0, 0.0), + child: Text('THREE', + style: TextStyle(fontSize: 32.0, color: Colors.white)), + ), + ], + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/main.dart b/FlutterHelper/ninghao_flutter-master/lib/main.dart new file mode 100644 index 00000000..be738d5b --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/main.dart @@ -0,0 +1,116 @@ +import 'package:flutter/material.dart'; +import 'package:ninghao_flutter/demo/animation/animation_demo.dart'; +import 'package:ninghao_flutter/demo/bloc/bloc_demo.dart'; +import 'package:ninghao_flutter/demo/http/http_demo.dart'; +import 'package:ninghao_flutter/demo/i18n/i18n_demo.dart'; +import 'package:ninghao_flutter/demo/rxdart/rxdart_demo.dart'; +import 'package:ninghao_flutter/demo/state/state_management_demo.dart'; +import 'package:ninghao_flutter/demo/stream/stream_demo.dart'; +import 'package:ninghao_flutter/demo/test/test_demo.dart'; +import './demo/drawer_demo.dart'; +import './demo/bottom_navigation_bar_demo.dart'; +import './demo/listview_demo.dart'; +import './demo/basic_demo.dart'; +import './demo/layout_demo.dart'; +import './demo/view_demo.dart'; +import './demo/sliver_demo.dart'; +import './demo/navigator_demo.dart'; +import './demo/form_demo.dart'; +import './demo/material_components.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +// import 'package:ninghao_flutter/demo/i18n/map/ninghao_demo_localizations.dart'; +import 'package:ninghao_flutter/demo/i18n/intl/ninghao_demo_localizations.dart'; + +void main() => runApp(App()); + +class App extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + locale: Locale('en', 'US'), + // locale: Locale('zh', 'CN'), + // localeResolutionCallback: (Locale locale, Iterable supportedLocales) { + // return Locale('en', 'US'); + // }, + localizationsDelegates: [ + NinghaoDemoLocalizationsDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: [ + Locale('en', 'US'), + Locale('zh', 'CN'), + ], + debugShowCheckedModeBanner: false, + // home: NavigatorDemo(), + initialRoute: '/test', + routes: { + '/': (context) => Home(), + '/about': (context) => Page(title: 'About'), + '/form': (context) => FormDemo(), + '/mdc': (context) => MaterialComponents(), + '/state-management': (context) => StateManagementDemo(), + '/stream': (context) => StreamDemo(), + '/rxdart': (context) => RxDartDemo(), + '/bloc': (context) => BlocDemo(), + '/http': (context) => HttpDemo(), + '/animation': (context) => AnimationDemo(), + '/i18n': (context) => I18nDemo(), + '/test': (context) => TestDemo(), + }, + theme: ThemeData( + primarySwatch: Colors.yellow, + highlightColor: Color.fromRGBO(255, 255, 255, 0.5), + splashColor: Colors.white70, + accentColor: Color.fromRGBO(3, 54, 255, 1.0), + ) + ); + } +} + +class Home extends StatelessWidget { + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 4, + child: Scaffold( + backgroundColor: Colors.grey[100], + appBar: AppBar( + title: Text('NINGHAO'), + actions: [ + IconButton( + icon: Icon(Icons.search), + tooltip: 'Search', + onPressed: () => debugPrint('Search button is pressed.'), + ) + ], + elevation: 0.0, + bottom: TabBar( + unselectedLabelColor: Colors.black38, + indicatorColor: Colors.black54, + indicatorSize: TabBarIndicatorSize.label, + indicatorWeight: 1.0, + tabs: [ + Tab(icon: Icon(Icons.local_florist)), + Tab(icon: Icon(Icons.change_history)), + Tab(icon: Icon(Icons.directions_bike)), + Tab(icon: Icon(Icons.view_quilt)), + ], + ), + ), + body: TabBarView( + children: [ + ListViewDemo(), + // Icon(Icons.change_history, size: 128.0, color: Colors.black12), + BasicDemo(), + // Icon(Icons.directions_bike, size: 128.0, color: Colors.black12), + LayoutDemo(), + SliverDemo(), + ], + ), + drawer: DrawerDemo(), + bottomNavigationBar: BottomNavigationBarDemo(), + ), + ); + } +} diff --git a/FlutterHelper/ninghao_flutter-master/lib/model/post.dart b/FlutterHelper/ninghao_flutter-master/lib/model/post.dart new file mode 100644 index 00000000..2187663b --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/lib/model/post.dart @@ -0,0 +1,108 @@ +class Post { + Post({ + this.title, + this.author, + this.imageUrl, + this.description, + }); + + final String title; + final String author; + final String imageUrl; + final String description; + + bool selected = false; +} + +final List posts = [ + Post( + title: 'Candy Shop', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/candy-shop.jpg', + ), + Post( + title: 'Childhood in a picture', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/childhood-in-a-picture.jpg', + ), + Post( + title: 'Contained', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/contained.jpg', + ), + Post( + title: 'Dragon', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/dragon.jpg', + ), + Post( + title: 'Free Hugs', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/free_hugs.jpg', + ), + Post( + title: 'Gravity Falls', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/gravity-falls.png', + ), + Post( + title: 'Icecream Truck', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/icecreamtruck.png', + ), + Post( + title: 'keyclack', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/keyclack.jpg', + ), + Post( + title: 'Overkill', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/overkill.png', + ), + Post( + title: 'Say Hello to Barry', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/say-hello-to-barry.jpg', + ), + Post( + title: 'Space Skull', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/space-skull.jpg', + ), + Post( + title: 'The Old Fashioned', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/the-old-fashioned.png', + ), + Post( + title: 'Tornado', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/tornado.jpg', + ), + Post( + title: 'Undo', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/undo.jpg', + ), + Post( + title: 'White Dragon', + author: 'Mohamed Chahin', + description: 'Esse ut nulla velit reprehenderit veniam sint nostrud nulla exercitation ipsum. Officia deserunt aliquip aliquip excepteur eiusmod dolor. Elit amet ipsum labore sint occaecat dolore tempor officia irure voluptate ad. Veniam laboris deserunt aute excepteur sit deserunt dolor esse dolor velit sint nulla anim ut. Reprehenderit voluptate adipisicing culpa magna ea nulla ullamco consectetur. Cupidatat adipisicing consequat adipisicing sit consectetur dolor occaecat.', + imageUrl: 'https://resources.ninghao.org/images/white-dragon.jpg', + ) +]; \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/pubspec.lock b/FlutterHelper/ninghao_flutter-master/pubspec.lock new file mode 100644 index 00000000..46e7a78f --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/pubspec.lock @@ -0,0 +1,247 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.2" + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.6.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.15.0" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + file: + dependency: transitive + description: + name: file + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.1.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_driver: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.0" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.3" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.10" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.0" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" + process: + dependency: transitive + description: + name: process + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.2.1" + rxdart: + dependency: "direct main" + description: + name: rxdart + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.18.1" + scoped_model: + dependency: "direct main" + description: + name: scoped_model + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + sync_http: + dependency: transitive + description: + name: sync_http + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.0" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.2.0" + webdriver: + dependency: transitive + description: + name: webdriver + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" +sdks: + dart: ">=2.12.0 <3.0.0" diff --git a/FlutterHelper/ninghao_flutter-master/pubspec.yaml b/FlutterHelper/ninghao_flutter-master/pubspec.yaml new file mode 100644 index 00000000..1c10140d --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/pubspec.yaml @@ -0,0 +1,75 @@ +name: ninghao_flutter +description: A new Flutter project. + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# Read more about versioning at semver.org. +version: 1.0.0+1 + +dependencies: + flutter: + sdk: flutter + scoped_model: ^0.3.0 + rxdart: ^0.18.1 + http: ^0.12.0 +# flutter_localizations: +# sdk: flutter +# intl: ^0.17.0 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^0.1.2 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_driver: + sdk: flutter +# intl_translation: ^0.17.2 + +environment: + sdk: '>=2.10.0 <3.0.0' +# For information on the generic Dart part of this file, see the +# following page: https://www.dartlang.org/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.io/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.io/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.io/custom-fonts/#from-packages diff --git a/FlutterHelper/ninghao_flutter-master/test/ninghao_demo_test.dart b/FlutterHelper/ninghao_flutter-master/test/ninghao_demo_test.dart new file mode 100644 index 00000000..55320349 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/test/ninghao_demo_test.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ninghao_flutter/demo/test/test_demo.dart'; + +void main() { + test('should return hello + something.', () { + var string = NinghaoTestDemo.greet('ninghao'); + expect(string, 'hello ninghao ~~'); + }); + + testWidgets('widget testing demo', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: TestDemo() + ) + ); + + final labelText = find.text('hello'); + + // expect(labelText, findsNothing); + // expect(labelText, findsOneWidget); + expect(labelText, findsNWidgets(1)); + + final actionChipLabelText = find.text('0'); + expect(actionChipLabelText, findsOneWidget); + + final actionChip = find.byType(ActionChip); + await tester.tap(actionChip); + await tester.pump(); + + final actionChipLabelTextAfterTap = find.text('1'); + expect(actionChipLabelTextAfterTap, findsOneWidget); + expect(actionChipLabelText, findsNothing); + }); +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/test_driver/app.dart b/FlutterHelper/ninghao_flutter-master/test_driver/app.dart new file mode 100644 index 00000000..99aa8a03 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/test_driver/app.dart @@ -0,0 +1,8 @@ +import 'package:flutter_driver/driver_extension.dart'; +import 'package:ninghao_flutter/main.dart' as app; + +void main() { + enableFlutterDriverExtension(); + + app.main(); +} \ No newline at end of file diff --git a/FlutterHelper/ninghao_flutter-master/test_driver/app_test.dart b/FlutterHelper/ninghao_flutter-master/test_driver/app_test.dart new file mode 100644 index 00000000..f9877237 --- /dev/null +++ b/FlutterHelper/ninghao_flutter-master/test_driver/app_test.dart @@ -0,0 +1,31 @@ +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:test/test.dart'; + +void main() { + group('App', () { + FlutterDriver driver; + + final actionChip = find.byValueKey('actionChip'); + final actionChipLabelText = find.byValueKey('actionChipLabelText'); + + setUpAll(() async { + driver = await FlutterDriver.connect(); + }); + + tearDownAll(() async { + if (driver != null) { + driver.close(); + } + }); + + test('starts at 0', () async { + expect(await driver.getText(actionChipLabelText), '0'); + }); + + test('increments the counter', () async { + await driver.tap(actionChip); + + expect(await driver.getText(actionChipLabelText), '1'); + }); + }); +} \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/.gitignore b/MemoryLeak/memoryleak1/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/MemoryLeak/memoryleak1/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/build.gradle b/MemoryLeak/memoryleak1/build.gradle deleted file mode 100644 index bd47cc2d..00000000 --- a/MemoryLeak/memoryleak1/build.gradle +++ /dev/null @@ -1,44 +0,0 @@ -plugins { - id 'com.android.application' -} - -android { - compileSdkVersion 30 - buildToolsVersion "30.0.3" - - defaultConfig { - applicationId "com.example.memoryleak1" - minSdkVersion 16 - targetSdkVersion 30 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - -dependencies { - - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'com.google.android.material:material:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - testImplementation 'junit:junit:4.+' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - - debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3' - releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3' - // Optional, if you use support library fragments: - debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3' -} \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/proguard-rules.pro b/MemoryLeak/memoryleak1/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/MemoryLeak/memoryleak1/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/src/androidTest/java/com/example/memoryleak1/ExampleInstrumentedTest.java b/MemoryLeak/memoryleak1/src/androidTest/java/com/example/memoryleak1/ExampleInstrumentedTest.java deleted file mode 100644 index 2b4a5e70..00000000 --- a/MemoryLeak/memoryleak1/src/androidTest/java/com/example/memoryleak1/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.example.memoryleak1; - -import android.content.Context; - -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); - assertEquals("com.example.memoryleak1", appContext.getPackageName()); - } -} \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/src/main/AndroidManifest.xml b/MemoryLeak/memoryleak1/src/main/AndroidManifest.xml deleted file mode 100644 index b0f3a193..00000000 --- a/MemoryLeak/memoryleak1/src/main/AndroidManifest.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/LeakOneActivity.java b/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/LeakOneActivity.java deleted file mode 100644 index 678dd855..00000000 --- a/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/LeakOneActivity.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.example.memoryleak1; - -import androidx.appcompat.app.AppCompatActivity; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class LeakOneActivity extends AppCompatActivity { - - - public static Activity sActivity; - public static List list = new ArrayList(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_leak_one); - - sActivity = this; - list.add(this); - - for (int i = 0; i < 10; i++) { - new Thread(new Runnable() { - @Override - public void run() { - while (true); - } - },"Thread i=" + i).start(); - } - - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - Map allStackTraces = Thread.getAllStackTraces(); - System.out.println(allStackTraces); - } - - public void finishClick(View view) { - - finish(); - } -} \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/MainActivity.java b/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/MainActivity.java deleted file mode 100644 index bd83ef44..00000000 --- a/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/MainActivity.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.example.memoryleak1; - -import androidx.appcompat.app.AppCompatActivity; - -import android.content.Intent; -import android.os.Bundle; -import android.view.View; - -public class MainActivity extends AppCompatActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - } - - public void leakClick(View view) { - startActivity(new Intent(this, LeakOneActivity.class)); - } -} \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/MyApplication.java b/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/MyApplication.java deleted file mode 100644 index d8881f34..00000000 --- a/MemoryLeak/memoryleak1/src/main/java/com/example/memoryleak1/MyApplication.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.example.memoryleak1; - -import android.app.Application; - -import com.squareup.leakcanary.LeakCanary; - -public class MyApplication extends Application { - - - @Override - public void onCreate() { - super.onCreate(); - if(LeakCanary.isInAnalyzerProcess(this)){ - return; - } - LeakCanary.install(this); - } -} diff --git a/MemoryLeak/memoryleak1/src/main/res/drawable-v24/ic_launcher_foreground.xml b/MemoryLeak/memoryleak1/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d11..00000000 --- a/MemoryLeak/memoryleak1/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/MemoryLeak/memoryleak1/src/main/res/drawable/ic_launcher_background.xml b/MemoryLeak/memoryleak1/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9c..00000000 --- a/MemoryLeak/memoryleak1/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MemoryLeak/memoryleak1/src/main/res/layout/activity_leak_one.xml b/MemoryLeak/memoryleak1/src/main/res/layout/activity_leak_one.xml deleted file mode 100644 index 8a1c7275..00000000 --- a/MemoryLeak/memoryleak1/src/main/res/layout/activity_leak_one.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - -